1616 lines
87 KiB
C#
1616 lines
87 KiB
C#
using Aurora.Api;
|
|
using Aurora.Api.Devices;
|
|
using AuroraLaser;
|
|
using AuroraLaserScanner;
|
|
using CoreUnit.Control.UserControl.Canvas;
|
|
using CoreUnit.Scanner.UserControl.ScannerCanvas;
|
|
using DB;
|
|
using Hermes;
|
|
using Matrox.MatroxImagingLibrary;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.Remoting.Contexts;
|
|
using System.Runtime.Remoting.Lifetime;
|
|
using System.Security.RightsManagement;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using VisionCommon;
|
|
using WeldingCommon.Alarm;
|
|
using WeldingCommon.Data;
|
|
using WeldingCommon.Settings;
|
|
using WeldingCommon.Utils;
|
|
|
|
namespace WeldingCommon.Sequences
|
|
{
|
|
public class SeqUploadWeldingList
|
|
{
|
|
static readonly Logger Log = new Logger("SeqUploadWeldingList");
|
|
|
|
const string SEQ_ENTER = "[SeqUploadWeldingList] SEQ_ENTER"; // inputParam 으로 받자.
|
|
const string SEQ_CHECK_INIT_CONDITION = "[SeqUploadWeldingList] Check Init Condition"; // Check Init Condition
|
|
|
|
const string SEQ_MARKING_ON_THE_FLY_ON = "[SeqUploadWeldingList] Marking OnTheFly On";
|
|
const string SEQ_RECORD_SIGNAL_ON = "[SeqUploadWeldingList] Record Signal On";
|
|
const string SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM = "[SeqUploadWeldingList] Load DrawObjectScannerParam";
|
|
const string SEQ_MARKING_ON_THE_FLY_OFF = "[SeqUploadWeldingList] Marking OnTheFly Off";
|
|
const string SEQ_RECORD_SIGNAL_OFF = "[SeqUploadWeldingList] Record Signal Off";
|
|
|
|
const string SEQ_SAVE_RESULT_DATA = "[SeqUploadWeldingList] Save Result Data";
|
|
|
|
const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqUploadWeldingList] Write Completion PLC Bit";
|
|
const string SEQ_COMPLETE = "[SeqUploadWeldingList] SEQ_COMPLETE"; // 완료
|
|
|
|
static class ContextKey
|
|
{
|
|
public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqUploadWeldingList";
|
|
public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqUploadWeldingList";
|
|
}
|
|
|
|
private SeqUploadWeldingList_InitParam _InitParam;
|
|
|
|
private Scanner _Scanner;
|
|
private Laser _Laser;
|
|
|
|
private LaserPowerCalParam _LaserPowerCalParam;
|
|
|
|
private double _LastX = 0;
|
|
private double _LastY = 0;
|
|
private double _FlyOffsetX;
|
|
private double _FlyOffsetY;
|
|
|
|
private PointF _ExternalCommandOffset = new PointF(0, 0);
|
|
|
|
private static DateTime _UploadstartTime;
|
|
private static TimeSpan _UploadSpanTime;
|
|
|
|
private static int _CenterRingRatio; // Center Ring의 파워 비율
|
|
private static float _LaserPowerRatio; // Laser에서 출력 파워 비율
|
|
|
|
private static SeqUploadWeldingList_OutParam result;
|
|
const int ROTATION_DEGREE = 15; // 15도 설정, 하나의 지그가 30도 이므로, 15도부터 돌도록 설정됨.
|
|
|
|
private ScannerParam _ScannerParam;
|
|
public SequenceBuilder Builder()
|
|
{
|
|
var sb = new SequenceBuilder(1000, true);
|
|
////var sb = new SequenceBuilder(1000, false); // With log
|
|
|
|
//MOTF와 RecordSignal이 동시 수행 가능한지 모르니깐 우선 순차적으로 실행될 수 있도록 LASA와 동일하게 구성..
|
|
//동시 수행 가능하면 Fork로 구성해도 될 듯
|
|
sb.AddAction(SEQ_ENTER, Sequence_Enter);
|
|
sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기
|
|
|
|
sb.AddAction(SEQ_MARKING_ON_THE_FLY_ON, MarkingOnTheFlyOn);
|
|
sb.AddAction(SEQ_RECORD_SIGNAL_ON, RecordSignalOn);
|
|
sb.AddAction(SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM, LoadDrawObjectScannerParam);
|
|
sb.AddAction(SEQ_MARKING_ON_THE_FLY_OFF, MarkingOnTheFlyOff);
|
|
sb.AddAction(SEQ_RECORD_SIGNAL_OFF, RecordSignalOff);
|
|
|
|
sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함.
|
|
sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write
|
|
sb.AddAction(SEQ_COMPLETE, Complete);
|
|
|
|
|
|
sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION]
|
|
> sb[SEQ_MARKING_ON_THE_FLY_ON] > sb[SEQ_RECORD_SIGNAL_ON] > sb[SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM]
|
|
> sb[SEQ_MARKING_ON_THE_FLY_OFF] > sb[SEQ_RECORD_SIGNAL_OFF]
|
|
> sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]);
|
|
|
|
sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final);
|
|
|
|
sb.OnStopped(OnStopped);
|
|
sb.OnForceError(OnForceError);
|
|
|
|
|
|
//sb.Draw("SeqUploadWeldingList.pdf");
|
|
|
|
return sb;
|
|
}
|
|
|
|
private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
Log.I("SeqUploadWeldingList Start");
|
|
|
|
_InitParam = param.Param as SeqUploadWeldingList_InitParam;
|
|
_LaserPowerCalParam = context.GetSetting<LaserPowerCalParam>(CommonSettingIds.LaserPowerCalParam);//우선 AuroraRecipe로 상속받아서 함수 사용하도록 함
|
|
|
|
if (result == null)
|
|
result = new SeqUploadWeldingList_OutParam();
|
|
result.Clear();
|
|
|
|
InitDev(context);
|
|
if (!CheckDeviceReady(context)) { //Check Device
|
|
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_DeviceNotReady);
|
|
Log.E("The devices are not active.");
|
|
return null;
|
|
}
|
|
|
|
if (InitSequenceVariable(context) == false) {
|
|
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_InitVariableError);
|
|
return null;
|
|
}
|
|
|
|
// ian0513, 이게 여기 있어야 할까??, 무엇을 측정 하기 위한건지 명확히 알고 실제 공정이면 다른 밑의 Node 로 변경
|
|
_UploadstartTime = DateTime.Now;
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private bool InitSequenceVariable(SequenceContext context)
|
|
{
|
|
//laserPowerCalParam 초기화(CSV 파일 불러오기)
|
|
_LaserPowerCalParam.Initialize(_LaserPowerCalParam.PowerCalibrationCenterBeamCSVFile, _LaserPowerCalParam.PowerCalibrationRingBeamCSVFile);
|
|
|
|
_FlyOffsetX = 0;
|
|
_FlyOffsetY = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
private void InitDev(SequenceContext context)
|
|
{
|
|
//Device Init
|
|
_Scanner = context.GetLaserScanner();
|
|
//_Laser = context.GetLaser();
|
|
}
|
|
|
|
private bool CheckDeviceReady(SequenceContext context)
|
|
{
|
|
List<string> deviceListToCheck = new List<string>() { CommonDeviceIds.Scanner };
|
|
bool isAllDeviceActivated = true;
|
|
foreach (string item in deviceListToCheck) {
|
|
if (!context.Devices[item].IsActivated) {
|
|
isAllDeviceActivated = isAllDeviceActivated && false;
|
|
}
|
|
}
|
|
|
|
return isAllDeviceActivated;
|
|
}
|
|
|
|
private bool CheckCondition()
|
|
{
|
|
if (CheckCondition_Interlock()) {
|
|
if (InitializeDeviceStatus()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool CheckCondition_Interlock()
|
|
{
|
|
// PLC, Data, IO 등 Interlock checking
|
|
return true;
|
|
}
|
|
|
|
private bool InitializeDeviceStatus()
|
|
{
|
|
if (_InitParam.IncludeListStartEnd) {
|
|
_Scanner.SetStartList(_InitParam.WeldingScannerListNo);
|
|
}
|
|
|
|
// SetLaserTiming 테스트
|
|
IDrawObject firstObject = _InitParam.SelectedDrawObjectList[0] as IDrawObject;
|
|
int firstObjectScannerNo = firstObject.ScannerParamID - 1;
|
|
|
|
_ScannerParam = ScannerCanvasUserCtrl.ScannerParams[firstObjectScannerNo];
|
|
|
|
_Scanner.SetLaserTiming((uint)_ScannerParam.LaserFrequency, (_ScannerParam.LaserPulseDuration), (_ScannerParam.LaserPulseDuration));
|
|
Log.D(string.Format($"[SetLaserTiming] LaserFrequency : {_ScannerParam.LaserFrequency}, LaserPulseDuration : {_ScannerParam.LaserPulseDuration}"));
|
|
|
|
return true;
|
|
}
|
|
|
|
private string CheckInitCondition(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
|
{
|
|
if (!CheckCondition()) {
|
|
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_CheckInitCondition);
|
|
Log.E("Condition is not in state to start sequence.");
|
|
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false);
|
|
return SEQ_COMPLETE;
|
|
}
|
|
|
|
var startTime = DateTime.Now;
|
|
context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime);
|
|
|
|
Log.D("UploadWeldingList Sequence CheckInitCondition");
|
|
return SEQ_MARKING_ON_THE_FLY_ON;
|
|
}
|
|
|
|
// MOTF 지원 중
|
|
private SequenceActionResult MarkingOnTheFlyOn(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
if (_Scanner.Config.UseMarkingOnTheFly) {
|
|
if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) {
|
|
// 1. Linear Track OTF 활성화 및 엔코더 초기화
|
|
_Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX);
|
|
|
|
// 2. 엔코더 특정 위치갈 때까지 대기
|
|
_Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX);
|
|
|
|
_FlyOffsetX = _Scanner.Config.MarkingOntheFlyOffsetX;
|
|
_FlyOffsetY = _Scanner.Config.MarkingOntheFlyOffsetY;
|
|
|
|
} else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) {
|
|
Log.I(string.Format("MOTF 사용, Rotate 보상"));
|
|
// 1. 엔코더 값이 들어오면 바로 X(Rotary) Encoder 리셋
|
|
_Scanner.SetFlyRotate(_Scanner.Config.MarkingOnTheFlyEncoderResolutionRotate);
|
|
|
|
// 2. 일괄 회전.(OTW 세팅시, Encoder가 0부터 시작하므로)
|
|
foreach (IDrawObject obj in _InitParam.SelectedDrawObjectList) {
|
|
obj.Rotate(ROTATION_DEGREE, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // +15도 회전
|
|
}
|
|
|
|
// 3. 원하는 용접 시작 각도 올 때까지 기다리기.
|
|
double weldingAngle = _Scanner.Config.MarkingRangeMinRotate + ROTATION_DEGREE;
|
|
_Scanner.WaitForEncoderRotateX(weldingAngle); // -5도부터 용접시작하고 싶으면 10도 넣으면 됨
|
|
|
|
// _FlyOffsetX, _FlyOffsetY 값 설정 불필요, 0-0 이면 됨.
|
|
}
|
|
|
|
// 엔코더 기록(용접 시작)
|
|
_Scanner.StoreEncoder(0);
|
|
_Scanner.SaveAndRestartTimer(); // 이전 용접의 T/T을 가져가고 싶으면 여기서 Reset 하기 전에 GetTime으로 읽어가야 함
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult RecordSignalOn(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
if (_Scanner.Config.UseRecordSignal) {
|
|
_Scanner.SaveAndRestartTimer();
|
|
_Scanner.SetTrigger(_Scanner.Config.RecordPeriod,
|
|
_Scanner.Config.RecordSignalType1, _Scanner.Config.RecordSignalType2,
|
|
_Scanner.Config.RecordSignalType3, _Scanner.Config.RecordSignalType4);
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult LoadDrawObjectScannerParam(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
//객체에 대한 파라미터 Load 전 lastX,Y를 현재 스캐너 위치로 받아옴
|
|
_Scanner.GetXYPos(out _LastX, out _LastY);
|
|
|
|
_ExternalCommandOffset.X = (float)_InitParam.CellMeasureCenterOffsetX;
|
|
_ExternalCommandOffset.Y = (float)_InitParam.CellMeasureCenterOffsetY;
|
|
|
|
// 첫번째 Object의 파라미터만 넣어주자?
|
|
var scanParam = getScannerParameter(_InitParam.SelectedDrawObjectList.First());
|
|
if (scanParam != null) {
|
|
result.SettingPower = scanParam.LaserPower1 + scanParam.LaserPower2;
|
|
result.SettingVelocity = scanParam.MarkSpeed;
|
|
}
|
|
//ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
int drawObjectCount = FuncLoadDrawObjectScannerParam(_InitParam.SelectedDrawObjectList);
|
|
|
|
//var weldingData = Status.GetProcessingWeldingData();
|
|
//weldingData.UploadDatas[eUploadData.LaserWeldingRecipeNo].Value = context.Recipes.ActivatedRecipe().Id;
|
|
//weldingData.UploadDatas[eUploadData.PreWeldingPointCount].Value = drawObjectCount;
|
|
|
|
//if (_PageNo == 1) {
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserDrawSpeed].Value = _ScannerParam.MarkSpeed;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserJumpSpeed].Value = _ScannerParam.JumpSpeed;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserMainPowerCore].Value = _ScannerParam.LaserPower1;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserMainPowerRing].Value = _ScannerParam.LaserPower2;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserRampingPower_Starting].Value = _ScannerParam.RampingStartPower;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserRampingLength_Starting].Value = _ScannerParam.RampingStartDist;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserRampingPower_OverPath].Value = _ScannerParam.RampingEndPower;
|
|
// weldingData.UploadDatas[eUploadData.CommonLaserRampingLength_OverPath].Value = _ScannerParam.RampingEndDist;
|
|
//} else {
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserDrawSpeed].Value = _ScannerParam.MarkSpeed;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserJumpSpeed].Value = _ScannerParam.JumpSpeed;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserMainPowerCore].Value = _ScannerParam.LaserPower1;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserMainPowerRing].Value = _ScannerParam.LaserPower2;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserRampingPower_Starting].Value = _ScannerParam.RampingStartPower;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserRampingLength_Starting].Value = _ScannerParam.RampingStartDist;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserRampingPower_OverPath].Value = _ScannerParam.RampingEndPower;
|
|
// weldingData.UploadDatas[eUploadData.CathodeLaserRampingLength_OverPath].Value = _ScannerParam.RampingEndDist;
|
|
//}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private int FuncLoadDrawObjectScannerParam(List<IDrawObject> objects)
|
|
{
|
|
int drawObjectCount = 0;
|
|
foreach (IDrawObject obj in objects) {
|
|
drawObjectCount += FuncLoadDrawObjectScannerParamSelected(obj);
|
|
}
|
|
|
|
return drawObjectCount;
|
|
}
|
|
|
|
private int LoadGroupScannerParam(Group obj)
|
|
{
|
|
int count = 0;
|
|
//서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
for (uint i = 0; i < obj.MarkingCount; i++) {
|
|
foreach (IDrawObject subObj in obj.SubObjects) { //Group객체내 포함된 DrawTools에 대한 용접 작업
|
|
count += FuncLoadDrawObjectScannerParamSelected(subObj);
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
private int FuncLoadDrawObjectScannerParamSelected(IDrawObject obj)
|
|
{
|
|
if (!obj.Enabled)
|
|
return 0;
|
|
|
|
uint repeatCount = getScannerParameter(obj).NumberOfCount;
|
|
if (repeatCount <= 0)
|
|
repeatCount = 1;
|
|
|
|
int count = 0;
|
|
|
|
for (int i = 0; i < repeatCount; i++) {
|
|
// 같은 obj를 두 번째 이상 반복할 때는
|
|
// _LastX/_LastY를 깨서 항상 시작점으로 Jump 하도록 유도
|
|
if (i > 0) {
|
|
_LastX = double.NaN;
|
|
_LastY = double.NaN;
|
|
}
|
|
|
|
if (obj is Line) {
|
|
LoadLineScannerParam((Line)obj);
|
|
count++;
|
|
} else if (obj is Dot) {
|
|
LoadDotScannerParam((Dot)obj);
|
|
count++;
|
|
} else if (obj is Spline) {
|
|
LoadSplineScannerParam((Spline)obj);
|
|
count++;
|
|
} else if (obj is SnowMan) {
|
|
LoadSnowManScannerParam((SnowMan)obj);
|
|
count++;
|
|
} else if (obj is Arc) {
|
|
Arc arcObj = (Arc)obj;
|
|
|
|
if (arcObj.UseHatching) {
|
|
// 해칭 리스트 가져오기
|
|
var hatchObjects = arcObj.GetHatchObjects();
|
|
|
|
// 액션, 외곽선(원) 업로드
|
|
Action uploadOutline = () => {
|
|
LoadArcScannerParam(arcObj);
|
|
count++;
|
|
};
|
|
|
|
// 액션, 해칭 업로드
|
|
Action uploadHatch = () => {
|
|
foreach (var hatchItem in hatchObjects) {
|
|
// HatchOnly 모드일 때, 외각선(원) 업로드 제외
|
|
if (arcObj.HatchMarkType == Arc.eHatchMarkType.Hatch_Only) {
|
|
if (hatchItem is Arc inner && inner.InnerArcFlag == Arc.FLAG_INNER_ARC) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// 해칭 선이나 외각선(원)을 다시 이 함수로 보내서 업로드
|
|
count += FuncLoadDrawObjectScannerParamSelected(hatchItem);
|
|
}
|
|
};
|
|
|
|
switch (arcObj.HatchMarkType) {
|
|
case Arc.eHatchMarkType.Outline_and_Hatch:
|
|
uploadOutline();
|
|
uploadHatch();
|
|
break;
|
|
case Arc.eHatchMarkType.Hatch_and_Outline:
|
|
uploadHatch();
|
|
uploadOutline();
|
|
break;
|
|
case Arc.eHatchMarkType.Hatch_Only:
|
|
uploadHatch();
|
|
break;
|
|
}
|
|
}
|
|
// 해칭 미사용시 아크만 업로드
|
|
else {
|
|
LoadArcScannerParam(arcObj);
|
|
count++;
|
|
}
|
|
count++;
|
|
} else if (obj is Arc3Point) {
|
|
LoadArc3PScannerParam((Arc3Point)obj);
|
|
count++;
|
|
} else if (obj is ZigZag) {
|
|
LoadZigzagScannerParam((ZigZag)obj);
|
|
count++;
|
|
} else if (obj is Group) {
|
|
count += LoadGroupScannerParam((Group)obj);
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
public ScannerParam getScannerParameter(IDrawObject obj)
|
|
{
|
|
ScannerParam ret = null;
|
|
if (obj is Line line)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[line.ScannerParamNo];
|
|
else if ( obj is Dot dot)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[dot.ScannerParamNo];
|
|
else if ( obj is Spline spline)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[spline.ScannerParamNo];
|
|
else if ( obj is SnowMan snowM)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[snowM.ScannerParamNo];
|
|
else if (obj is Arc arc)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[arc.ScannerParamNo];
|
|
else if ( obj is Arc3Point acr3)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[acr3.ScannerParamNo];
|
|
else if ( obj is ZigZag zz)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[zz.ScannerParamNo];
|
|
else if( obj is Group group)
|
|
ret = ScannerCanvasUserCtrl.ScannerParams[group.ScannerParamNo];
|
|
|
|
return ret;
|
|
}
|
|
private void SetScannerProcessCondition(ScannerParam param, out float percentLaser1, out float percentLaser2)
|
|
{
|
|
//TrumpLaser의 경우 SetLaserTiming 함수로 Gate 신호를 살려줘야 함
|
|
//우선 무조건 셋팅하는 것으로 쓰고 Trump_IO Class 만들면 _laser type이 Trump의 경우에만 셋팅해주는 것으로 변경하자
|
|
//LaserFrequency = 10, LaserPulseDuration = 0.1로 셋팅하면 출사 되는 것 확인_241025
|
|
//if (_InitParam.NeedSetLaserTiming) {
|
|
// _Scanner.SetLaserTiming((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000), (uint)(param.LaserPulseDuration * 1000));
|
|
// Log.D(string.Format($"[SetLaserTiming] LaserFrequency : {param.LaserFrequency}, LaserPulseDuration : {param.LaserPulseDuration}"));
|
|
//}
|
|
|
|
// 1.레이저 ON/OFF delay 설정
|
|
_Scanner.SetLaesrDelay(param.LaserOnDelay, param.LaserOffDelay);
|
|
|
|
// 2.Mark delay 설정
|
|
_Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay);
|
|
|
|
// 3.DA(레이저 파워값) 설정
|
|
if (param.LaserPower1 == 0 && param.LaserPower2 == 0)
|
|
_CenterRingRatio = 100;
|
|
else
|
|
_CenterRingRatio = (int)Math.Round((double)(100 * param.LaserPower1) / (double)(param.LaserPower1 + param.LaserPower2), 0); // Discrete 한 값이라서 Ring은 오차 발생
|
|
|
|
//if (_Laser.Config.TruFiberType == eTruFiberType.TruFiberS) { // TruFiberS Type은 비율 제어
|
|
// if (_CenterRingRatio == 0) { // Center가 0인경우
|
|
// //percentLaser1 = (float)_LaserPowerCalParam.CalibrateWattToPercent((double)param.LaserPower2, (uint)eAnalogPortOut.DA1);
|
|
// percentLaser1 = (float)(_LaserPowerCalParam.CalibrateWattToMeasuredVoltage((double)param.LaserPower2, (uint)LaserPowerCalParam.beamMode.Center));
|
|
// percentLaser1 = percentLaser1 * 10; // 스캐너에 입렵하기 위한 연산 ( 1V : 10 ~~ 10V : 100 )
|
|
// } else {
|
|
// //percentLaser1 = (float)_LaserPowerCalParam.CalibrateWattToPercent((double)param.LaserPower1 / (double)_CenterRingRatio * 100.0, (uint)eAnalogPortOut.DA1);
|
|
// percentLaser1 = (float)(_LaserPowerCalParam.CalibrateWattToMeasuredVoltage((double)param.LaserPower1 / (double)_CenterRingRatio * 100.0, (uint)LaserPowerCalParam.beamMode.Center));
|
|
// percentLaser1 = percentLaser1 * 10; // 스캐너에 입렵하기 위한 연산 ( 1V : 10 ~~ 10V : 100 )
|
|
// }
|
|
// percentLaser2 = 0;
|
|
// Log.D(string.Format("TruFiber S Models:: Original Power1 : {0}; Original Power2 : {1}; Calibrated Percent1 :{2:0.000}; Calibrated Percent2 :{3:0.000}; CenterRingRatio :{4:0.000}", param.LaserPower1, param.LaserPower2,percentLaser1,percentLaser2,_CenterRingRatio));
|
|
//} else if (_Laser.Config.TruFiberType == eTruFiberType.TruFiberP) { // Power제어
|
|
// percentLaser1 = 100;
|
|
// percentLaser2 = 0;
|
|
// Log.D(string.Format("TruFiber P Models:: Original Power1 : {0}; Original Power2 : {1}; Calibrated Percent1 :{2:0.000}; Calibrated Percent2 :{3:0.000}; CenterRingRatio :{4:0.000}", param.LaserPower1, param.LaserPower2, percentLaser1, percentLaser2, _CenterRingRatio));
|
|
//} else if (_Laser.Config.TruFiberType == eTruFiberType.CalPercentToMeasuredVoltage) {
|
|
// percentLaser1 = (float)_LaserPowerCalParam.CalibrateWattToMeasuredVoltage(param.LaserPower1, (uint)LaserPowerCalParam.beamMode.Center) * 10;
|
|
// percentLaser2 = (float)_LaserPowerCalParam.CalibrateWattToMeasuredVoltage(param.LaserPower2, (uint)LaserPowerCalParam.beamMode.Ring) * 10;
|
|
// Log.D(string.Format("CalPercentToMeasuredVoltage Models:: Original Power1 : {0}; Original Power2 : {1}; Calibrated Percent1 :{2:0.000}; Calibrated Percent2 :{3:0.000}; CenterRingRatio :{4:0.000}", param.LaserPower1, param.LaserPower2, percentLaser1, percentLaser2, _CenterRingRatio));
|
|
//} else {
|
|
percentLaser1 = (float)_LaserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1);
|
|
percentLaser2 = (float)_LaserPowerCalParam.CalibrateWattToPercent(param.LaserPower2, (uint)eAnalogPortOut.DA2);
|
|
Log.D(string.Format("Normal Models:: Original Power1 : {0}; Original Power2 : {1}; Calibrated Percent1 :{2:0.000}; Calibrated Percent2 :{3:0.000}; CenterRingRatio :{4:0.000}", param.LaserPower1, param.LaserPower2, percentLaser1, percentLaser2, _CenterRingRatio));
|
|
//}
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
|
|
// 4.점프 및 마크 속도 설정
|
|
_Scanner.SetJumpSpeed(param.JumpSpeed);
|
|
_Scanner.SetMarkSpeed(param.MarkSpeed);
|
|
|
|
}
|
|
|
|
private PowerProfilesList ReadPowerProfile(int powerProfileID)
|
|
{
|
|
//추후 경로 변경 필요
|
|
// TODO: ian0513.kim, DataPath 를 설정해서 경로를 빼주자
|
|
var json = File.ReadAllText("PowerProfileTest.json");
|
|
var root = JsonConvert.DeserializeObject<TopRootObject>(json);
|
|
|
|
PowerProfilesList powerProfile = new PowerProfilesList();
|
|
for (int i = 0; i < root.PowerProfilesLists[powerProfileID].PowerProfiles.Count; i++) {
|
|
PowerProfile profile = new PowerProfile();
|
|
profile.PowerProfileParams.Add(new PowerProfileParam());
|
|
profile.PowerProfileParams[0].Copy(root.PowerProfilesLists[powerProfileID].PowerProfiles[i].PowerProfileParams[0]);
|
|
powerProfile.PowerProfiles.Add(profile);
|
|
}
|
|
return powerProfile;
|
|
}
|
|
|
|
private void LoadLineScannerParam(Line obj)
|
|
{
|
|
//m_scannerToCameraReferenceOffsets은 SystemParameter에서 설정된 값, Cal하고나면 해당 Offset은 현재 필요없는거같은데 확인 필요, 필요시 Camera setting에 추가해주면됨
|
|
//m_externalCommandOffset은 AutoRun시 PLC에서 받아오는 offset임, 현재 LASA에서 BhAutoRun 클래스에 CCW라인에서만 사용하던데 실제 사용하는지 확인 필요
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1. 스캐너 가공 조건 설정
|
|
// TODO: ScannerCanvasUserCtrl 의 값이 제대로 가져와 지는지 확인 필요함. mainPage 로 접근해서 가져와야 할 것인데.
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0.0f;
|
|
float percentLaser2 = 0.0f;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
Log.I(string.Format($"[Line Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
// 2.1. Wobbel 관련 설정
|
|
if (param.WobbelEnable) {
|
|
// SnowMan 와블인 경우
|
|
if (param.SnowManEnable) {
|
|
int dx = 0;
|
|
int dy = 0;
|
|
|
|
double radian = (param.TiltingAngle - 90) * Math.PI / 180;
|
|
dx = (int)(Math.Cos(radian) * 100);
|
|
dy = (int)(Math.Sin(radian) * 100);
|
|
|
|
_Scanner.SetWobbelDirection(dx, dy);
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(true, 1, 1, 1, 2);
|
|
|
|
//Wobbel Vector 리스트 초기화
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
|
|
List<double> dTrans = new List<double>();
|
|
List<double> dLong = new List<double>();
|
|
|
|
param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0);
|
|
}
|
|
|
|
param.LoadWobbelVectorForBody(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0);
|
|
}
|
|
}
|
|
|
|
// Zigzag 와블인 경우
|
|
if (param.ZigzagWobbelEnable) {
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
_Scanner.SetWobbelMode(true, 1, 1, 1, 2);
|
|
|
|
//Wobbel Vector 리스트 초기화
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
|
|
List<double> dTrans = new List<double>();
|
|
List<double> dLong = new List<double>();
|
|
|
|
param.CreateWobbelVectorForZigzagPointList();
|
|
|
|
_Scanner.SetMarkSpeed(param.zigzagTotalSpeed);
|
|
|
|
param.LoadZigZagWobbelVector(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.m_zigzagPeriod[i + 1], 0);
|
|
}
|
|
}
|
|
|
|
// 일반적인 와블인 경우
|
|
if (!param.SnowManEnable && !param.ZigzagWobbelEnable) {
|
|
_Scanner.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal,
|
|
param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape);
|
|
}
|
|
|
|
Log.I(string.Format($"[Line Weld] Item No({obj.No + 1}) Wobbel Setting : Use({param.WobbelEnable}), Transversal({param.WobbelTransversal}), Longitudinal({param.WobbelLongditudinal}), Frequency({param.WobbelFrequency}), WobbelShape({param.WobbelShape})"));
|
|
|
|
} else {
|
|
//_Scanner.SetWobbelDirection(0, 0);
|
|
//_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
//_Scanner.SetWobbelMode(false, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, 0);
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
_Scanner.SetWobbelMode(false, 0, 0, 0, 0);
|
|
}
|
|
|
|
// 2.2. Ramping & PowerProfile 관련 설정
|
|
if (param.UsePowerProfile) {
|
|
PowerProfilesList powerProfile = ReadPowerProfile(param.PowerProfileID);
|
|
|
|
// START- 시작위치 점프 관련 설정
|
|
if (powerProfile.PowerProfiles.Count != 0) {
|
|
float power = percentLaser1 * (float)powerProfile.PowerProfiles[0].PowerProfileParams[0].StartPowerPercent * 0.01f;
|
|
|
|
//Param 명령을 주기 위해서는 Polygon Delay 를 0으로 한다.
|
|
_Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0);
|
|
|
|
// 지그재그는 벡터 기반 컨트롤
|
|
_Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, (uint)eAutoControlParameter.AnalogOut1);
|
|
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.02 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.02) {
|
|
//같은 위치인 경우 점프 딜레이 0으로 현재 위치(상대 위치 0,0)으로 점프 실행줘야 한다. --> Para함수는 Write_da 함수가 적용되지 않고, 마지막 Para 함수의 파워값으로 설정되기 때
|
|
_Scanner.SetScannerDelay(0, param.MarkDelay, 0);
|
|
_Scanner.ParaJumpRel(0, 0, power);
|
|
} else {
|
|
_Scanner.ParaJumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, power);
|
|
}
|
|
|
|
//첫번째 Profile Param
|
|
double totalTime = powerProfile.PowerProfiles[0].PowerProfileParams[0].Time;
|
|
double speed = param.ZigzagWobbelEnable ? param.zigzagTotalSpeed : param.MarkSpeed;
|
|
double profileDistance = totalTime * speed * 0.001f;
|
|
|
|
double x = profileDistance * (obj.P2.X - obj.P1.X) / obj.Distance + obj.P1.X;
|
|
double y = profileDistance * (obj.P2.Y - obj.P1.Y) / obj.Distance + obj.P1.Y;
|
|
|
|
power = percentLaser1 * (float)powerProfile.PowerProfiles[0].PowerProfileParams[0].EndPowerPercent * 0.01f;
|
|
_Scanner.ParaMarkAbs(x + xOffset, y + yOffset, power);
|
|
|
|
if (powerProfile.PowerProfiles.Count > 1) {
|
|
for (int i = 1; i < powerProfile.PowerProfiles.Count; i++) {
|
|
totalTime += powerProfile.PowerProfiles[i].PowerProfileParams[0].Time;
|
|
profileDistance = totalTime * speed * 0.001f;
|
|
|
|
if (profileDistance < obj.Distance) {
|
|
power = percentLaser1 * (float)powerProfile.PowerProfiles[i].PowerProfileParams[0].StartPowerPercent * 0.01f;
|
|
|
|
_Scanner.SetScannerDelay(0, param.MarkDelay, 0);
|
|
_Scanner.ParaJumpRel(0, 0, power);
|
|
|
|
x = profileDistance * (obj.P2.X - obj.P1.X) / obj.Distance + obj.P1.X;
|
|
y = profileDistance * (obj.P2.Y - obj.P1.Y) / obj.Distance + obj.P1.Y;
|
|
|
|
power = percentLaser1 * (float)powerProfile.PowerProfiles[i].PowerProfileParams[0].EndPowerPercent * 0.01f;
|
|
|
|
_Scanner.ParaMarkAbs(x + xOffset, y + yOffset, power);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (profileDistance < obj.Distance) {
|
|
_Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, power);
|
|
}
|
|
|
|
} else {
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.02 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.02) {
|
|
// 점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
}
|
|
|
|
//Write_da 함수는 시작점으로 점프한 이후 Mark 명령 직전에 해준다.
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
|
|
_Scanner.MarkAbs(obj.PF2.X + xOffset, obj.PF2.Y + yOffset);
|
|
}
|
|
// END- 시작위치 점프 관련 설정
|
|
|
|
} else {
|
|
// Wobble, PowerProfile, Ramping을 사용하지 않는 일반적인 경우 이쪽으로 들어옴
|
|
|
|
// START- Jump(Line Shot)
|
|
// @deprecated 굉장히 위험한 코드임. 충분히 검증하고 다시 코드 구현할 것. 첫번째 item의 경우 무조건 Jump 명령을 날려줘야 함.
|
|
// 안그러면 초기 위치를 0에서 시작 하기 때문에 위험함.
|
|
// RCC 검증을 위해 일단 주석 해제
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.02 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.02) {
|
|
// 점프 안함
|
|
} else {
|
|
// Jump 할 때는 Analog Out 값을 0으로 변경
|
|
#warning 251211 Laser Off Delay가 다 수행되기 전에 power를 0으로 해버려서, Laser OffDelay 동작을 안하는 현상
|
|
//_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST);
|
|
//_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST);
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
|
|
Log.I(string.Format($"[Line Weld] Jump ({obj.PF1.X},{obj.PF1.Y})"));
|
|
}
|
|
// END- Jump(Line Shot)
|
|
|
|
// START- Mark
|
|
if ((param.RampingStartDist > 0 || param.RampingEndDist > 0) && obj.MadebyRCC) {
|
|
// RCC Ramping 의 경우
|
|
|
|
// RCC 로 만들어진 object 는 경로정보가 여러개로 쪼개져 있기 때문에 기존의 ramping 구간을 사용하면 안된다.
|
|
// Ramping 에 대한 정보 자체를 RCC 인 경우에 한해 ratio 를 생성할때 같이 만들어줬다.
|
|
// ratio 는 0~1 의 값으로 되어 있다. 생성할때 interlock 처리했으나 여기서도 추가로 확인한다.
|
|
|
|
float powerratio = obj.RCC_PowerRatio;
|
|
if (powerratio < 0) {
|
|
powerratio = 0;
|
|
} else if (powerratio > 1) {
|
|
powerratio = 1;
|
|
}
|
|
|
|
float analogPercentLaserPower1 = percentLaser1 * powerratio; // center laser
|
|
float analogPercentLaserPower2 = percentLaser2 * powerratio; // ring laser
|
|
|
|
_Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, analogPercentLaserPower1, eFunctionType.LIST);
|
|
|
|
// 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다.
|
|
// 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다.
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, analogPercentLaserPower2, eFunctionType.LIST);
|
|
|
|
_Scanner.MarkAbs(obj.PF2.X + xOffset, obj.PF2.Y + yOffset);
|
|
|
|
Log.I(string.Format($"[RCC Subpath Line Weld] Mark(Ramping) ({obj.PF2.X},{obj.PF2.Y})"));
|
|
|
|
} else if ((param.RampingStartDist > 0 || param.RampingEndDist > 0) && (param.RampingEndDist + param.RampingStartDist <= obj.Distance)) {
|
|
// RCC 가 아닌 경우
|
|
_Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0);
|
|
_Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0);
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
if (param.RampingStartDist > 0) {
|
|
_Scanner.ParaMarkRel(0, 0, percentLaser1 * (float)param.RampingStartPower * 0.01f);
|
|
|
|
// Start Ramping이 있는 경우, Start Ramping 끝지점 위치 계산
|
|
x = param.RampingStartDist * (obj.P2.X - obj.P1.X) / obj.Distance + obj.P1.X;
|
|
y = param.RampingStartDist * (obj.P2.Y - obj.P1.Y) / obj.Distance + obj.P1.Y;
|
|
|
|
if (param.RampingStartSlopeMode) {
|
|
_Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1);
|
|
} else {
|
|
_Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1 * (float)param.RampingStartPower * 0.01f);
|
|
_Scanner.ParaMarkRel(0, 0, percentLaser1);
|
|
}
|
|
} else {
|
|
_Scanner.ParaMarkRel(0, 0, percentLaser1);
|
|
}
|
|
|
|
if (param.RampingEndDist > 0) {
|
|
// End Ramping이 있는 경우, End Ramping 시작지점 위치 계산
|
|
x = param.RampingEndDist * (obj.P1.X - obj.P2.X) / obj.Distance + obj.P2.X;
|
|
y = param.RampingEndDist * (obj.P1.Y - obj.P2.Y) / obj.Distance + obj.P2.Y;
|
|
|
|
_Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1);
|
|
|
|
//Ramping End 끝지점 까지
|
|
if (param.RampingEndSlopeMode) {
|
|
_Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, percentLaser1 * (float)param.RampingEndPower * 0.01f);
|
|
} else {
|
|
_Scanner.ParaMarkRel(0, 0, percentLaser1 * (float)param.RampingEndPower * 0.01f);
|
|
_Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, percentLaser1 * (float)param.RampingEndPower * 0.01f);
|
|
}
|
|
} else {
|
|
_Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, percentLaser1);
|
|
}
|
|
|
|
_Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay);
|
|
_Scanner.SetVectorControl((uint)eAutoControlParameter.NoUse, 0);
|
|
|
|
Log.I(string.Format($"[Line Weld] Mark(Ramping) ({obj.PF2.X},{obj.PF2.Y})"));
|
|
|
|
} else {
|
|
// Ramping 이 없는 경우
|
|
_Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0);
|
|
|
|
//_scanner._scannerObj.SetScannerDelay(param.JumpDelay, 0, 0);
|
|
//_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1);
|
|
//_scanner._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay);
|
|
//_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
//_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
//_scanner._scannerObj.ParaMarkAbs(obj.PF2.X + XOffset, obj.PF2.Y + YOffset, percentLaser1);
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
_Scanner.MarkAbs(obj.PF2.X + xOffset, obj.PF2.Y + yOffset);
|
|
|
|
//_scanner._scannerObj.SetVectorControl((uint)eAutoControlParameter.NoUse, 0);
|
|
|
|
Log.I(string.Format($"[Line Weld] Mark(Ramping) ({obj.PF2.X},{obj.PF2.Y})"));
|
|
}
|
|
// END- Mark
|
|
|
|
}
|
|
|
|
_LastX = obj.PF2.X + xOffset;
|
|
_LastY = obj.PF2.Y + yOffset;
|
|
|
|
Log.I(string.Format($"[Line Weld] Mark Start/End Point (Start Point : {obj.PF1.X},{obj.PF1.Y}, End Point : {obj.PF2.X},{obj.PF2.Y})"));
|
|
}
|
|
|
|
private void LoadDotScannerParam(Dot obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1. 스캐너 가공 조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0.0f;
|
|
float percentLaser2 = 0.0f;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
Log.I(string.Format($"[Point Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
// 2.1. Jump(Point Shot)
|
|
// Jump 할 때는 Analog Out 값을 0으로 변경
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST);
|
|
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
Log.I(string.Format($"[Point Weld] Jump ({obj.PF1.X + xOffset},{obj.PF1.Y + yOffset})"));
|
|
|
|
//// 2.2. Mark(Point Shot)
|
|
//_Scanner.SetLaserTiming((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000), (uint)(param.LaserPulseDuration * 1000));
|
|
|
|
// @deprecated 해당 코드는 사용에 주의가 필요 함.. 만약 사용시 원복할 필요가 있음..
|
|
// 이후 공정에 영향을 미치는 인자이므로
|
|
// _Scanner.SetStandby(10, 0);
|
|
|
|
_Scanner.SetScannerDelay(param.JumpDelay, 0, 0);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
//_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1); // 위치 이동 없이 Power만 변경
|
|
|
|
// Laser On Time 만큼 레이저 On 실행
|
|
_Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay);
|
|
_Scanner.LaserOnList(param.SpotShotTime);
|
|
|
|
Log.I(string.Format($"[Point Weld] Mark ({obj.PF1.X + xOffset},{obj.PF1.Y + yOffset})"));
|
|
|
|
//Dot도 Last값 추가
|
|
_LastX = obj.PF1.X + xOffset;
|
|
_LastY = obj.PF1.Y + yOffset;
|
|
}
|
|
|
|
private void LoadSplineScannerParam(Spline obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1.스캐너 가공조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0;
|
|
float percentLaser2 = 0;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
// Spline 의 경우 Wobbel 해제
|
|
_Scanner.SetWobbelMode(false, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape);
|
|
|
|
Log.I(string.Format($"[Spline Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
int pointCount = obj.P1.Count;
|
|
switch (obj.DrawWay) {
|
|
case Spline.DrawWayType.OUT_OUT: {
|
|
//P1 OUT에서 시작
|
|
_Scanner.JumpAbs(obj.P1[pointCount - 1].X + xOffset, obj.P1[pointCount - 1].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = obj.P1.Count - 2; i >= 0; i--) {
|
|
_Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset);
|
|
}
|
|
|
|
//tornado 의 경우 P2까지
|
|
if (obj.SplineTornado) {
|
|
//P2 OUT에서 시작
|
|
_Scanner.JumpAbs(obj.P2[pointCount - 1].X + xOffset, obj.P2[pointCount - 1].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = obj.P2.Count - 2; i >= 0; i--) {
|
|
_Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Spline.DrawWayType.OUT_IN: {
|
|
//P1 OUT에서 시작
|
|
_Scanner.JumpAbs(obj.P1[pointCount - 1].X + xOffset, obj.P1[pointCount - 1].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = obj.P1.Count - 2; i >= 0; i--) {
|
|
_Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset);
|
|
}
|
|
|
|
//tornado 의 경우 P2까지
|
|
if (obj.SplineTornado) {
|
|
//P2 IN에서 시작
|
|
_Scanner.JumpAbs(obj.P2[0].X + xOffset, obj.P2[0].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = 1; i < obj.P2.Count; i++) {
|
|
_Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Spline.DrawWayType.IN_OUT: {
|
|
//P1 IN에서 시작
|
|
_Scanner.JumpAbs(obj.P1[0].X + xOffset, obj.P1[0].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = 1; i < obj.P1.Count; i++) {
|
|
_Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset);
|
|
}
|
|
|
|
//tornado 의 경우 P2까지
|
|
if (obj.SplineTornado) {
|
|
//P2 OUT에서 시작
|
|
_Scanner.JumpAbs(obj.P2[pointCount - 1].X + xOffset, obj.P2[pointCount - 1].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = obj.P2.Count - 2; i >= 0; i--) {
|
|
_Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Spline.DrawWayType.IN_IN: {
|
|
//P1 IN에서 시작
|
|
_Scanner.JumpAbs(obj.P1[0].X + xOffset, obj.P1[0].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = 1; i < obj.P1.Count; i++) {
|
|
_Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset);
|
|
}
|
|
|
|
//tornado 의 경우 P2까지
|
|
if (obj.SplineTornado) {
|
|
//P2 IN에서 시작
|
|
_Scanner.JumpAbs(obj.P2[0].X + xOffset, obj.P2[0].Y + yOffset, eFunctionType.LIST);
|
|
for (int i = 1; i < obj.P2.Count; i++) {
|
|
_Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
Log.I(string.Format($"[Spline Weld] Draw Way : {obj.DrawWay}, Tornado 사용 : {obj.SplineTornado})"));
|
|
|
|
_LastX = obj.PF2.X + xOffset;
|
|
_LastY = obj.PF2.Y + yOffset;
|
|
Log.I(string.Format($"[Spline Weld] Mark Start/End Point (Start Point : {obj.PF1.X},{obj.PF1.Y}, End Point : {obj.PF2.X},{obj.PF2.Y})"));
|
|
}
|
|
|
|
private void LoadSnowManScannerParam(SnowMan obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1.스캐너 가공조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0;
|
|
float percentLaser2 = 0;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
Log.I(string.Format($"[SnowMan Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
// SnowMan 로드 시작
|
|
Math.Cos(obj.TiltingAngle * Math.PI / 180);
|
|
|
|
// Wobbel 각도 설정
|
|
_Scanner.SetWobbelDirection((int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100), (int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100));
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(true, 1, 1, 1, 2);
|
|
|
|
// Wobbel Vector 리스트 초기화
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0); // period=0은 초기화
|
|
|
|
List<double> dTrans = new List<double>();
|
|
List<double> dLong = new List<double>();
|
|
|
|
// 확인 2025.03.06, SnowMan 을 사용하지 않기 때문에 해당 함수 확인 불필요 (LoadLineScannerParam() 에서는 param 으로 부터 설정을 하는데, 여기서는 obj 로 부터 설정)
|
|
obj.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)obj.HeadPeriod, 0);
|
|
}
|
|
|
|
obj.LoadWobbelVectorForBody(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)obj.BodyPeriod, 0);
|
|
}
|
|
|
|
//서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
_Scanner.MarkAbs(obj.PF2.X + xOffset, obj.PF2.Y + yOffset);
|
|
|
|
Log.I(string.Format($"[Line Weld] Set Mark StartPoint/EndPoint(SP:{obj.PF1.X},{obj.PF1.Y},EP:{obj.PF2.X},{obj.PF2.Y})"));
|
|
|
|
// 확인 2025.03.06, SnowMan 을 사용하지 않기 때문에 저장 해 놓지 않음. (Line 에서 와블은 SnowMan 사용)
|
|
// 여기는 LastX, LastY 저장이 불필요
|
|
}
|
|
|
|
private void LoadArcScannerParam(Arc obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
Log.I($"[Arc Weld] Offset Value : {xOffset},{yOffset}");
|
|
// 1.스캐너 가공조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0;
|
|
float percentLaser2 = 0;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
Log.I(string.Format($"[Arc Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
// 2.1. Wobbel 관련 설정
|
|
// Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행
|
|
if (!param.SnowManEnable) {
|
|
if (param.WobbelEnable) {
|
|
// Wobbel 각도 설정
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape);
|
|
|
|
Log.I(string.Format($"[Arc Weld] Item No({obj.No + 1}) Wobbel Setting : Use({param.WobbelEnable}), Transversal({param.WobbelTransversal}), Longitudinal({param.WobbelLongditudinal}), Frequency({param.WobbelFrequency}), WobbelShape({param.WobbelShape})"));
|
|
} else {
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
_Scanner.SetWobbelMode(false, 0, 0, 0, 0);
|
|
}
|
|
|
|
//서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
//_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST);
|
|
|
|
// @deprecated 해당코드 검증 필요 !!
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.02 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.02) {
|
|
//점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
Log.I(string.Format($"[Arc Weld] Jump ({obj.PF1.X},{obj.PF1.Y})"));
|
|
}
|
|
|
|
} else {
|
|
int dx = 0;
|
|
int dy = 0;
|
|
|
|
double radian = (param.TiltingAngle - 90) * Math.PI / 180;
|
|
dx = (int)(Math.Cos(radian) * 100);
|
|
dy = (int)(Math.Sin(radian) * 100);
|
|
|
|
_Scanner.SetWobbelDirection(dx, dy);
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(true, 1, 1, 1, 2);
|
|
|
|
// Wobbel Vector 리스트 초기화
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0); //period=0은 초기화
|
|
|
|
List<double> dTrans = new List<double>();
|
|
List<double> dLong = new List<double>();
|
|
|
|
param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0);
|
|
}
|
|
|
|
param.LoadWobbelVectorForBody(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0);
|
|
}
|
|
|
|
// 서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
//_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST);
|
|
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.02 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.02) {
|
|
//점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
Log.I(string.Format($"[Arc Weld] Jump ({obj.PF1.X},{obj.PF1.Y})"));
|
|
}
|
|
}
|
|
|
|
// 2.2 Ramping 설정
|
|
double radius = Math.Sqrt((obj.CenterPointF.X - obj.PF1.X) * (obj.CenterPointF.X - obj.PF1.X) + (obj.CenterPointF.Y - obj.PF1.Y) * (obj.CenterPointF.Y - obj.PF1.Y));
|
|
double length = param.ArcRampingInterval; // ArcRamping 간격 추가
|
|
double theta = 0;
|
|
|
|
// 2.2.0. Sweep 방향에 따른 회전 방향 설정
|
|
if (obj.Direction == Arc.eDirection.CCW) {
|
|
theta = (length / radius) * (180 / Math.PI);
|
|
}
|
|
if (obj.Direction == Arc.eDirection.CW) {
|
|
theta = (-length / radius) * (180 / Math.PI);
|
|
}
|
|
|
|
if ((param.RampingStartDist > 0 || param.RampingEndDist > 0) && obj.MadebyRCC) {
|
|
// RCC 로 만들어진 object 는 경로정보가 여러개로 쪼개져 있기 때문에 기존의 ramping 구간을 사용하면 안된다.
|
|
// Ramping 에 대한 정보 자체를 RCC 인 경우에 한해 ratio 를 생성할때 같이 만들어줬다.
|
|
// ratio 는 0~1 의 값으로 되어 있다. 생성할때 interlock 처리했으나 여기서도 추가로 확인한다.
|
|
float powerratio = obj.RCC_PowerRatio;
|
|
if (powerratio < 0) {
|
|
powerratio = 0;
|
|
} else if (powerratio > 1) {
|
|
powerratio = 1;
|
|
}
|
|
|
|
float analogPercentLaserPower1 = percentLaser1 * powerratio; // center laser
|
|
float analogPercentLaserPower2 = percentLaser2 * powerratio; // ring laser
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, analogPercentLaserPower1, eFunctionType.LIST);
|
|
|
|
// 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다.
|
|
// 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다.
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, analogPercentLaserPower2, eFunctionType.LIST);
|
|
|
|
//Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle);
|
|
} else if ((param.RampingStartDist > 0 || param.RampingEndDist > 0)
|
|
&& (param.RampingStartDist + param.RampingEndDist < radius * Math.Abs(obj.SweepAngle))) {
|
|
//&& !param.WobbelEnable && !param.SnowManEnable) {
|
|
|
|
// 기존 코드 유지
|
|
// @SMW/LHS Wobbel 사용 시 Lamping도 사용 할 수 있도록 조건문 수정 및 Ring빔도 Ramping 가능하도록 수정
|
|
|
|
// 2.2.1.1. 데이터테이블 기준으로 파워 동작
|
|
//percentLaser1 = (float)_laserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1);
|
|
|
|
// 2.2.1.2. Ramping을 위한 변수 설정
|
|
int risingEdgeCount = (int)(param.RampingStartDist / length);
|
|
int fallingEdgeCount = (int)(param.RampingEndDist / length);
|
|
//int totalCount = (int)(Math.Abs(obj.SweepAngle) / theta);
|
|
int totalCount = (int)(Math.Abs(obj.SweepAngle / theta));
|
|
|
|
// 2.2.2.1. Rising Edge 시작 파워 설정
|
|
float startingPercentLaser1 = percentLaser1 * (float)param.RampingStartPower / 100 <= 100 ?
|
|
percentLaser1 * (float)param.RampingStartPower / 100 : 100;
|
|
float risingEdgePercentLaser1 = 0;
|
|
float startingPercentLaser2 = percentLaser2 * (float)param.RampingStartPower / 100 <= 100 ?
|
|
percentLaser2 * (float)param.RampingStartPower / 100 : 100;
|
|
float risingEdgePercentLaser2 = 0;
|
|
|
|
|
|
// 2.2.2.2. Rising Edge 구간 파워 및 위치 변경
|
|
for (int iter = 0; iter < risingEdgeCount; iter++) {
|
|
risingEdgePercentLaser1 = (percentLaser1 - startingPercentLaser1) / (float)(risingEdgeCount) * (float)(iter) + startingPercentLaser1;
|
|
risingEdgePercentLaser2 = (percentLaser2 - startingPercentLaser2) / (float)(risingEdgeCount) * (float)(iter) + startingPercentLaser2;
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, risingEdgePercentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, risingEdgePercentLaser2, eFunctionType.LIST);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.3.1. Constant Range 파워 설정
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
|
|
// 2.2.3.2. Constant Range 구간 위치 변경
|
|
for (int iter = risingEdgeCount; iter < totalCount - fallingEdgeCount; iter++) {
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.4.1. Falling Edge 마지막 파워 설정
|
|
float endingPercentLaser1 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ?
|
|
percentLaser1 * (float)param.RampingEndPower / 100 : 100;
|
|
float fallingEdgePercentLaser1 = 0;
|
|
float endingPercentLaser2 = percentLaser2 * (float)param.RampingEndPower / 100 <= 100 ?
|
|
percentLaser2 * (float)param.RampingEndPower / 100 : 100;
|
|
float fallingEdgePercentLaser2 = 0;
|
|
|
|
// 2.2.4.2. Falling Edge 구간 파워 및 위치 변경
|
|
for (int iter = totalCount - fallingEdgeCount; iter < totalCount; iter++) {
|
|
// Falling Edge 구간 시작하는 순간부터 Power 변경 원하므로 (iter - (totalCount - fallingEdgeCount - 1))
|
|
fallingEdgePercentLaser1 = (endingPercentLaser1 - percentLaser1) / (float)(fallingEdgeCount) * (float)(iter - (totalCount - fallingEdgeCount - 1)) + percentLaser1;
|
|
fallingEdgePercentLaser2 = (endingPercentLaser2 - percentLaser2) / (float)(fallingEdgeCount) * (float)(iter - (totalCount - fallingEdgeCount - 1)) + percentLaser2;
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, fallingEdgePercentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, fallingEdgePercentLaser2, eFunctionType.LIST);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.5. 마지막 위치까지 이동해줌.
|
|
double lastSweep = obj.SweepAngle - (totalCount * theta);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, lastSweep);
|
|
|
|
} else {
|
|
//Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle);
|
|
}
|
|
|
|
_LastX = obj.PF2.X + xOffset;
|
|
_LastY = obj.PF2.Y + yOffset;
|
|
if (obj.MadebyRCC) {
|
|
Log.I(string.Format($"[RCC SubPath Arc Weld] Arc center ({obj.CenterPointF.X},{obj.CenterPointF.Y}), Sweep angle : ({obj.SweepAngle})"));
|
|
} else {
|
|
Log.I(string.Format($"[Arc Weld] Arc center ({obj.CenterPointF.X},{obj.CenterPointF.Y}), Sweep angle : ({obj.SweepAngle})"));
|
|
}
|
|
|
|
}
|
|
|
|
private void LoadArc3PScannerParam(Arc3Point obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1.스캐너 가공조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0;
|
|
float percentLaser2 = 0;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
Log.I(string.Format($"[Arc3P Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 2. 스캐너 가공 작업
|
|
// 2.1. Wobbel 관련 설정
|
|
// Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행
|
|
if (!param.SnowManEnable) {
|
|
if (param.WobbelEnable) {
|
|
// Wobbel 각도 설정
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape);
|
|
|
|
Log.I(string.Format($"[Arc3P Weld] Item No({obj.No + 1}) Wobbel Setting : Use({param.WobbelEnable}), Transversal({param.WobbelTransversal}), Longitudinal({param.WobbelLongditudinal}), Frequency({param.WobbelFrequency}), WobbelShape({param.WobbelShape})"));
|
|
|
|
} else {
|
|
_Scanner.SetWobbelDirection(0, 0);
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0);
|
|
_Scanner.SetWobbelMode(false, 0, 0, 0, 0);
|
|
}
|
|
|
|
// 서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.01 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.01) {
|
|
//점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
Log.I(string.Format($"[Arc3P Weld] Jump ({obj.PF1.X},{obj.PF1.Y})"));
|
|
}
|
|
|
|
} else {
|
|
int dx = 0;
|
|
int dy = 0;
|
|
|
|
double radian = (param.TiltingAngle - 90) * Math.PI / 180;
|
|
|
|
dx = (int)(Math.Cos(radian) * 100);
|
|
dy = (int)(Math.Sin(radian) * 100);
|
|
|
|
_Scanner.SetWobbelDirection(dx, dy);
|
|
|
|
// Wobbel 모드 설정
|
|
_Scanner.SetWobbelMode(true, 1, 1, 1, 2);
|
|
|
|
//Wobbel Vector 리스트 초기화
|
|
_Scanner.SetWobbelVector(0, 0, 0, 0); //period=0은 초기화
|
|
|
|
List<double> dTrans = new List<double>();
|
|
List<double> dLong = new List<double>();
|
|
|
|
param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0);
|
|
}
|
|
|
|
param.LoadWobbelVectorForBody(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor);
|
|
for (int i = 0; i < dTrans.Count; i++) {
|
|
_Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0);
|
|
}
|
|
|
|
// 서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.01 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.01) {
|
|
//점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
Log.I(string.Format($"[Arc3P Weld] Jump ({obj.PF1.X},{obj.PF1.Y})"));
|
|
}
|
|
|
|
}
|
|
|
|
// 2.2. Ramping 설정
|
|
double radius = Math.Sqrt((obj.CenterPointF.X - obj.PF1.X) * (obj.CenterPointF.X - obj.PF1.X) + (obj.CenterPointF.Y - obj.PF1.Y) * (obj.CenterPointF.Y - obj.PF1.Y));
|
|
double length = param.ArcRampingInterval; // ArcRamping 간격 추가
|
|
double theta = 0;
|
|
|
|
// 2.2.0. Sweep 방향에 따른 회전 방향 설정
|
|
if (obj.Direction == Arc3Point.eDirection.CCW) {
|
|
theta = (length / radius) * (180 / Math.PI);
|
|
}
|
|
if (obj.Direction == Arc3Point.eDirection.CW) {
|
|
theta = (-length / radius) * (180 / Math.PI);
|
|
}
|
|
|
|
if ((param.RampingStartDist > 0 || param.RampingEndDist > 0)
|
|
&& (param.RampingStartDist + param.RampingEndDist < radius * Math.Abs(obj.SweepAngle))) {
|
|
//&& !param.WobbelEnable && !param.SnowManEnable)
|
|
|
|
if (obj.MadebyRCC) {
|
|
// RCC 로 만들어진 object 는 경로정보가 여러개로 쪼개져 있기 때문에 기존의 ramping 구간을 사용하면 안된다.
|
|
// Ramping 에 대한 정보 자체를 RCC 인 경우에 한해 ratio 를 생성할때 같이 만들어줬다.
|
|
// ratio 는 0~1 의 값으로 되어 있다. 생성할때 interlock 처리했으나 여기서도 추가로 확인한다.
|
|
|
|
float powerratio = obj.RCC_PowerRatio;
|
|
if (powerratio < 0) {
|
|
powerratio = 0;
|
|
} else if (powerratio > 1) {
|
|
powerratio = 1;
|
|
}
|
|
|
|
float analogPercentLaserPower1 = percentLaser1 * powerratio; // center laser
|
|
float analogPercentLaserPower2 = percentLaser2 * powerratio; // ring laser
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, analogPercentLaserPower1, eFunctionType.LIST);
|
|
|
|
// 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다.
|
|
// 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다.
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, analogPercentLaserPower2, eFunctionType.LIST);
|
|
|
|
//Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle);
|
|
|
|
} else {
|
|
// 기존 코드 유지
|
|
// @SMW/LHS Wobbel 사용 시 Lamping도 사용 할 수 있도록 조건문 수정 및 Ring빔도 Ramping 가능하도록 수정
|
|
|
|
// 2.2.1.1. 데이터테이블 기준으로 파워 동작
|
|
//percentLaser1 = (float)_laserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1);
|
|
|
|
// 2.2.1.2. Ramping을 위한 변수 설정
|
|
int risingEdgeCount = (int)(param.RampingStartDist / length);
|
|
int fallingEdgeCount = (int)(param.RampingEndDist / length);
|
|
//int totalCount = (int)(Math.Abs(obj.SweepAngle) / theta);
|
|
int totalCount = (int)(Math.Abs(obj.SweepAngle / theta));
|
|
|
|
// 2.2.2.1. Rising Edge 시작 파워 설정
|
|
float startingPercentLaser1 = percentLaser1 * (float)param.RampingStartPower / 100 <= 100 ?
|
|
percentLaser1 * (float)param.RampingStartPower / 100 : 100;
|
|
float risingEdgePercentLaser1 = 0;
|
|
float startingPercentLaser2 = percentLaser2 * (float)param.RampingStartPower / 100 <= 100 ?
|
|
percentLaser2 * (float)param.RampingStartPower / 100 : 100;
|
|
float risingEdgePercentLaser2 = 0;
|
|
|
|
// 2.2. Rising Edge 구간 파워 및 위치 변경
|
|
for (int iter = 0; iter < risingEdgeCount; iter++) {
|
|
risingEdgePercentLaser1 = (percentLaser1 - startingPercentLaser1) / (float)(risingEdgeCount) * (float)(iter) + startingPercentLaser1;
|
|
risingEdgePercentLaser2 = (percentLaser2 - startingPercentLaser2) / (float)(risingEdgeCount) * (float)(iter) + startingPercentLaser2;
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, risingEdgePercentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, risingEdgePercentLaser2, eFunctionType.LIST);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.3.1. Constant Range 파워 설정
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST);
|
|
|
|
// 2.2.3.2. Constant Range 구간 위치 변경
|
|
for (int iter = risingEdgeCount; iter < totalCount - fallingEdgeCount; iter++) {
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.4.1. Falling Edge 마지막 파워 설정
|
|
float endingPercentLaser1 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ?
|
|
percentLaser1 * (float)param.RampingEndPower / 100 : 100;
|
|
float fallingEdgePercentLaser1 = 0;
|
|
float endingPercentLaser2 = percentLaser2 * (float)param.RampingEndPower / 100 <= 100 ?
|
|
percentLaser2 * (float)param.RampingEndPower / 100 : 100;
|
|
float fallingEdgePercentLaser2 = 0;
|
|
|
|
// 2.2.4.2. Falling Edge 구간 파워 및 위치 변경
|
|
for (int iter = totalCount - fallingEdgeCount; iter < totalCount; iter++) {
|
|
// Falling Edge 구간 시작하는 순간부터 Power 변경 원하므로 (iter - (totalCount - fallingEdgeCount - 1))
|
|
fallingEdgePercentLaser1 = (endingPercentLaser1 - percentLaser1) / (float)(fallingEdgeCount) * (float)(iter - (totalCount - fallingEdgeCount - 1)) + percentLaser1;
|
|
fallingEdgePercentLaser2 = (endingPercentLaser2 - percentLaser2) / (float)(fallingEdgeCount) * (float)(iter - (totalCount - fallingEdgeCount - 1)) + percentLaser2;
|
|
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, fallingEdgePercentLaser1, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, fallingEdgePercentLaser2, eFunctionType.LIST);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta);
|
|
}
|
|
|
|
// 2.2.5. 마지막 위치까지 이동해줌.
|
|
double lastSweep = obj.SweepAngle - (totalCount * theta);
|
|
_Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, lastSweep);
|
|
}
|
|
}
|
|
|
|
_LastX = obj.PF2.X + xOffset;
|
|
_LastY = obj.PF2.Y + yOffset;
|
|
if (obj.MadebyRCC) {
|
|
Log.I(string.Format($"[RCC SubPath Arc3P Weld] Arc center ({obj.CenterPointF.X},{obj.CenterPointF.Y}), Sweep angle : ({obj.SweepAngle})"));
|
|
} else {
|
|
Log.I(string.Format($"[Arc3P Weld] Arc center ({obj.CenterPointF.X},{obj.CenterPointF.Y}), Sweep angle : ({obj.SweepAngle})"));
|
|
}
|
|
|
|
}
|
|
|
|
private void LoadZigzagScannerParam(ZigZag obj)
|
|
{
|
|
// 카메라 오프셋 + Object의 Vision Offset + Fly 오프셋
|
|
double xOffset = _FlyOffsetX + _ExternalCommandOffset.X;
|
|
double yOffset = _FlyOffsetY + _ExternalCommandOffset.Y;
|
|
|
|
// 1.스캐너 가공조건 설정
|
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
|
float percentLaser1 = 0;
|
|
float percentLaser2 = 0;
|
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
|
|
|
Log.I(string.Format($"[Zigzag Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
|
|
// 1. 시작 위치로 점프
|
|
if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.01 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.01) {
|
|
//점프 안함
|
|
} else {
|
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
|
}
|
|
|
|
// 2. Ramping 설정
|
|
// 지그재그는 아직 Ramping 구현 안됨
|
|
|
|
// 3. 지그재그 순서대로 마킹
|
|
for (int i = 0; i < obj.ZigZagCount; i++) {
|
|
_Scanner.MarkAbs(obj.ArcStartPoints[i].X + xOffset, obj.ArcStartPoints[i].Y + yOffset);
|
|
|
|
float startAngle = (float)HitUtil.RadiansToDegrees(HitUtil.LineAngleR(obj.ArcCenterPoints[i], obj.ArcStartPoints[i], 0));
|
|
float endAngle = (float)HitUtil.RadiansToDegrees(HitUtil.LineAngleR(obj.ArcCenterPoints[i], obj.ArcEndPoints[i], 0));
|
|
float sweepAngle = 0;
|
|
|
|
if (i % 2 == 0) {
|
|
if (obj.DrawDirection == ZigZag.eDrawDirection.Left) {
|
|
sweepAngle = (-1) * Math.Abs(startAngle - endAngle);
|
|
if (sweepAngle < -180) {
|
|
sweepAngle = (360 + sweepAngle) * (-1);
|
|
}
|
|
_Scanner.ArcAbs(obj.ArcCenterPoints[i].X + xOffset, obj.ArcCenterPoints[i].Y + yOffset, sweepAngle);
|
|
|
|
} else {
|
|
sweepAngle = Math.Abs(startAngle - endAngle);
|
|
if (sweepAngle > 180) {
|
|
sweepAngle = (360 - sweepAngle);
|
|
}
|
|
_Scanner.ArcAbs(obj.ArcCenterPoints[i].X + xOffset, obj.ArcCenterPoints[i].Y + yOffset, sweepAngle);
|
|
}
|
|
|
|
} else {
|
|
if (obj.DrawDirection == ZigZag.eDrawDirection.Right) {
|
|
sweepAngle = (-1) * Math.Abs(startAngle - endAngle);
|
|
if (sweepAngle < -180) {
|
|
sweepAngle = (360 + sweepAngle) * (-1);
|
|
}
|
|
_Scanner.ArcAbs(obj.ArcCenterPoints[i].X + xOffset, obj.ArcCenterPoints[i].Y + yOffset, sweepAngle);
|
|
|
|
} else {
|
|
sweepAngle = Math.Abs(startAngle - endAngle);
|
|
if (sweepAngle > 180) {
|
|
sweepAngle = (360 - sweepAngle);
|
|
}
|
|
_Scanner.ArcAbs(obj.ArcCenterPoints[i].X + xOffset, obj.ArcCenterPoints[i].Y + yOffset, sweepAngle);
|
|
}
|
|
}
|
|
|
|
_Scanner.MarkAbs(obj.LineEndPoints[i].X + xOffset, obj.LineEndPoints[i].Y + yOffset);
|
|
}
|
|
|
|
_LastX = obj.LineEndPoints[obj.ZigZagCount - 1].X + xOffset;
|
|
_LastY = obj.LineEndPoints[obj.ZigZagCount - 1].Y + yOffset;
|
|
|
|
Log.I(string.Format($"[Zigzag Weld] Mark Start/End Point (Start Point : {obj.PF1.X},{obj.PF1.Y}, End Point : {obj.PF2.X},{obj.PF2.Y})"));
|
|
|
|
}
|
|
|
|
private SequenceActionResult MarkingOnTheFlyOff(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
if (_Scanner.Config.UseMarkingOnTheFly) {
|
|
if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) {
|
|
// Linear OTW의 경우, 각 Draw Tool에서 좌표 오프셋을 해 주고 있음
|
|
|
|
} else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) {
|
|
// 여기서 원래 레시피로 돌려주기
|
|
foreach (IDrawObject obj in _InitParam.SelectedDrawObjectList) {
|
|
obj.Rotate(ROTATION_DEGREE * -1, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // -15도 회전
|
|
}
|
|
}
|
|
|
|
// 추후, Parking Position 을 용접 시작 위치로 자동으로 계산되어 들어가게 개선 필요
|
|
_Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY);
|
|
|
|
// 엔코더 기록(용접 완료)
|
|
_Scanner.StoreEncoder(1);
|
|
_Scanner.SaveAndRestartTimer();
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult RecordSignalOff(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
if (_Scanner.Config.UseRecordSignal) {
|
|
_Scanner.SaveAndRestartTimer();
|
|
_Scanner.SetTrigger(0,
|
|
_Scanner.Config.RecordSignalType1, _Scanner.Config.RecordSignalType2,
|
|
_Scanner.Config.RecordSignalType3, _Scanner.Config.RecordSignalType4);
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
// 결과 Data 를 업데이트 함.
|
|
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true);
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
// 완료 비트 write 하는 Node 추가 필요. format 유지, SeqScoutNormal 없음
|
|
|
|
Log.D("UploadWeldingList Sequence WriteCompletionPLCBit");
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param)
|
|
{
|
|
RestoreDeviceStatus();
|
|
Log.I("UploadWeldingList Complete");
|
|
|
|
_UploadSpanTime = DateTime.Now.Subtract(_UploadstartTime);
|
|
Log.D(string.Format($"[SeqUploadWeldingList] UploadWeldingList Complete Time : {_UploadSpanTime.TotalMilliseconds}"));
|
|
|
|
context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult);
|
|
//SeqUploadWeldingList_OutParam result = new SeqUploadWeldingList_OutParam() { Success = seqResult };
|
|
result.Success = seqResult;
|
|
|
|
if (seqResult == false) {
|
|
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed);
|
|
}
|
|
|
|
Log.D("UploadWeldingList Sequence Complete");
|
|
return SequenceAction.Ok(result);
|
|
}
|
|
|
|
private bool RestoreDeviceStatus()
|
|
{
|
|
if (_InitParam.IncludeListStartEnd) {
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST);
|
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST);
|
|
_Scanner.SetEndList();
|
|
}
|
|
Log.I(string.Format($"SetEndList"));
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnForceError(SequenceContext arg1, string arg2)
|
|
{
|
|
Log.I("SequenceAction Ok : OnForceError");
|
|
}
|
|
|
|
private void OnStopped(SequenceContext obj)
|
|
{
|
|
Log.I("SequenceAction Ok : OnStopped");
|
|
}
|
|
|
|
}
|
|
|
|
public class SeqUploadWeldingList_InitParam : InitParam
|
|
{
|
|
public bool NeedSetLaserTiming { get; set; } // eLaserType.Trumpf_IO, eLaserType.Coherent_Arm_IO ==> true
|
|
public bool IncludeListStartEnd { get; set; }
|
|
|
|
public double CellMeasureCenterOffsetX { get; set; }
|
|
public double CellMeasureCenterOffsetY { get; set; }
|
|
|
|
public List<IDrawObject> SelectedDrawObjectList { get; set; }
|
|
public eListNo WeldingScannerListNo { get; set; }
|
|
}
|
|
|
|
public class SeqUploadWeldingList_OutParam : OutParam
|
|
{
|
|
public double SettingPower { get; set; }
|
|
public double SettingVelocity { get; set; }
|
|
public override void Clear()
|
|
{
|
|
base.Clear();
|
|
SettingPower = 0.0;
|
|
SettingVelocity = 0.0;
|
|
}
|
|
}
|
|
} |