using Aurora.Api; using AuroraLaser; using AuroraLaserScanner; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using WeldingCommon.Data; using WeldingCommon.Settings; using eLaserType = AuroraLaser.eLaserType; namespace WeldingCommon.Sequences { public class SeqUploadWeldingList_Old { static readonly Logger Log = new Logger("SeqUploadWeldingList_Old"); #region SequenceID public const string SEQ_SET_START_LIST = "SetStartList"; public const string SEQ_MARKING_ON_THE_FLY_ON = "MarkingOnTheFlyOn"; public const string SEQ_RECORD_SIGNAL_ON = "RecordSignalOn"; public const string SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM = "LoadDrawObjectScannerParam"; public const string SEQ_MARKING_ON_THE_FLY_OFF = "MarkingOnTheFlyOff"; public const string SEQ_RECORD_SIGNAL_OFF = "RecordSignalOff"; public const string SEQ_SET_END_LIST = "SetEndList"; #endregion #region Property private static double _LastX = 0; private static double _LastY = 0; //private static int _LastScannerParamNo = -1; private static double _FlyOffsetX; private static double _FlyOffsetY; private static int _DrawObjectCount; private static bool _IncludeListStartEnd; private static Scanner _Scanner; private static Laser _Laser; private static LaserPowerCalParam _LaserPowerCalParam; //용접할 drawing객체에 대한 리스트 //public static List m_selectedDrawObjects = new List(); //public static List SelectedDrawObjects { // get { return m_selectedDrawObjects; } // set { m_selectedDrawObjects = value; } //} private static List _SelectedDrawObjects = new List(); private static PointF _ScannerToCameraReferenceOffsets; // TODO: ExternalCommandOffset??, 아래 delegate 와 연결 되어 있나??, 사용 하는 부분이 없는데 확인 필요 static PointF m_externalCommandOffset = new PointF(0, 0); public static PointF ExternalCommandOffset { get { return m_externalCommandOffset; } set { m_externalCommandOffset = value; } } // Model Type 별 setting 값이 다르게 적용해야 할때 사용, 이해 완료 후 주석 삭제 public delegate void ExternalCommandOffsetDelegate(SequenceContext context, out float offsetX, out float offsetY); public static ExternalCommandOffsetDelegate OffsetDelegate; // OffsetDelegate 로 대체됨, 향후 이해 완료 후, 주석 삭제 //private static SystemParameter _SystemParameter; //private static LHSModel _ModelItem; private static DateTime _UploadstartTime; private static TimeSpan _UploadSpanTime; #endregion public static SequenceBuilder Builder() { SequenceBuilder sb = new SequenceBuilder(1000); //MOTF와 RecordSignal이 동시 수행 가능한지 모르니깐 우선 순차적으로 실행될 수 있도록 LASA와 동일하게 구성.. //동시 수행 가능하면 Fork로 구성해도 될 듯 sb.AddAction(SEQ_SET_START_LIST, SetStartList); 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_SET_END_LIST, SetEndList); sb.Flows(sb.Init > sb[SEQ_SET_START_LIST] > 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_SET_END_LIST] > sb.Final); //sb.Draw("SeqUploadWeldingList_Old.pdf"); return sb; } private static SequenceActionResult SetStartList(SequenceContext context, string id, SequenceActionResult param) { _UploadstartTime = DateTime.Now; _Scanner = context.GetLaserScanner(); _Laser = context.GetLaser(); _LaserPowerCalParam = context.GetSetting(CommonSettingIds.LaserPowerCalParam);//우선 AuroraRecipe로 상속받아서 함수 사용하도록 함 eListNo m_weldingScannerListNo = Status.GetProcessingWeldingData().WeldingScannerListNo; //SelectedDrawObjects = context.GetValue>(SELECTED_DRAW_OBJECTS); _SelectedDrawObjects = Status.GetProcessingWeldingData().SelectedDrawObjectList; //AutoRunMPAbw에서는 메인시퀀스에서 LoadList로 List 불러오기 때문에 UploadWeldingList의 SetStartList를 하지 않음, IncludeListStartEnd를 false로 넘겨 주면됨 _IncludeListStartEnd = Status.GetProcessingWeldingData().IncludeListStartEnd; //laserPowerCalParam 초기화(CSV 파일 불러오기) _LaserPowerCalParam.Initialize(_LaserPowerCalParam.PowerCalibrationCenterBeamCSVFile, _LaserPowerCalParam.PowerCalibrationRingBeamCSVFile); if (_IncludeListStartEnd) { //_scanner._scannerObj.SetStartList(m_weldingScannerListNo); _Scanner.SetStartList(m_weldingScannerListNo); } return SequenceAction.Ok(); } private static SequenceActionResult MarkingOnTheFlyOn(SequenceContext context, string id, SequenceActionResult param) { if (_Scanner.Config.UseMarkingOnTheFly) { if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) { // 1. Linear Track OTF 활성화 및 엔코더 초기화 //_scanner._scannerObj.SetFlyX(_scanner.Config.MarkingOnTheFlyEncoderResolutionX); _Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX); _FlyOffsetX = _Scanner.Config.MarkingOntheFlyOffsetX; _FlyOffsetY = _Scanner.Config.MarkingOntheFlyOffsetY; // 2. 엔코더 특정 위치갈 때까지 대기 //_scanner._scannerObj.WaitForEncoderX(_scanner.Config.MarkingStartEncoderPositionX); _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX); } else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) { Log.I(string.Format("MOTF 사용, Rotate 보상")); // 1. 엔코더 값이 들어오면 바로 X(Rotary) Encoder 리셋 //_scanner._scannerObj.SetFlyRotate(_scanner.Config.MarkingOnTheFlyEncoderResolutionRotate); _Scanner.SetFlyRotate(_Scanner.Config.MarkingOnTheFlyEncoderResolutionRotate); // 2. 일괄 회전.(OTW 세팅시, Encoder가 0부터 시작하므로) foreach (IDrawObject obj in _SelectedDrawObjects) { obj.Rotate(15, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // +15도 회전 } // 3. 원하는 용접 시작 각도 올 때까지 기다리기. double weldingAngle = _Scanner.Config.MarkingRangeMinRotate + 15; //_scanner._scannerObj.WaitForEncoderRotateX(weldingAngle); // -5도부터 용접시작하고 싶으면 10도 넣으면 됨 _Scanner.WaitForEncoderRotateX(weldingAngle); // -5도부터 용접시작하고 싶으면 10도 넣으면 됨 } // 엔코더 기록(용접 시작) //_scanner._scannerObj.StoreEncoder(0); //_scanner._scannerObj.SaveAndRestartTimer(); // 이전 용접의 T/T을 가져가고 싶으면 여기서 Reset 하기 전에 GetTime으로 읽어가야 함 _Scanner.StoreEncoder(0); _Scanner.SaveAndRestartTimer(); // 이전 용접의 T/T을 가져가고 싶으면 여기서 Reset 하기 전에 GetTime으로 읽어가야 함 } else { _FlyOffsetX = 0; _FlyOffsetY = 0; } return SequenceAction.Ok(); } private static SequenceActionResult RecordSignalOn(SequenceContext context, string id, SequenceActionResult param) { if (_Scanner.Config.UseRecordSignal) { //_scanner._scannerObj.SaveAndRestartTimer(); //_scanner._scannerObj.SetTrigger(_scanner.Config.RecordPeriod, _scanner.Config.RecordSignalType1, _scanner.Config.RecordSignalType2, _scanner.Config.RecordSignalType3, _scanner.Config.RecordSignalType4); _Scanner.SaveAndRestartTimer(); _Scanner.SetTrigger(_Scanner.Config.RecordPeriod, _Scanner.Config.RecordSignalType1, _Scanner.Config.RecordSignalType2, _Scanner.Config.RecordSignalType3, _Scanner.Config.RecordSignalType4); } return SequenceAction.Ok(); } private static SequenceActionResult LoadDrawObjectScannerParam(SequenceContext context, string id, SequenceActionResult param) { //객체에 대한 파라미터 Load 전 lastX,Y를 현재 스캐너 위치로 받아옴 //_scanner._scannerObj.GetXYPos(out lastX, out lastY); _Scanner.GetXYPos(out _LastX, out _LastY); // 현재는 SMW의 AutorunCellPositionMeasure에서 시퀀스 진행 시 Offset 값을 받오도록 되어있음 // LHS는 모델에 등록된 값을 받아오도록 하자. 그럼 Autorun과 Teachingrun 모두 적용됨 // CommandOffset로딩방식이 다른 장비. 정지명 if (OffsetDelegate != null) { OffsetDelegate(context, out float offsetX, out float offsetY); m_externalCommandOffset.X = offsetX; m_externalCommandOffset.Y = offsetY; } else { m_externalCommandOffset.X = (float)Status.GetProcessingWeldingData().CellMeasureCenterOffsetX; m_externalCommandOffset.Y = (float)Status.GetProcessingWeldingData().CellMeasureCenterOffsetY; } FuncLoadDrawObjectScannerParam(_SelectedDrawObjects); return SequenceAction.Ok(); } private static 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 _SelectedDrawObjects) { obj.Rotate(-15, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // -15도 회전 } } // 추후, Parking Position 을 용접 시작 위치로 자동으로 계산되어 들어가게 개선 필요 //_scanner._scannerObj.Fly_Return(_scanner.Config.MarkingOntheFlyParkingPositionX, _scanner.Config.MarkingOntheFlyParkingPositionY); _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY); // 엔코더 기록(용접 완료) //_scanner._scannerObj.StoreEncoder(1); //_scanner._scannerObj.SaveAndRestartTimer(); _Scanner.StoreEncoder(1); _Scanner.SaveAndRestartTimer(); } return SequenceAction.Ok(); } private static SequenceActionResult RecordSignalOff(SequenceContext context, string id, SequenceActionResult param) { if (_Scanner.Config.UseRecordSignal) { //_scanner._scannerObj.SaveAndRestartTimer(); //_scanner._scannerObj.SetTrigger(0, _scanner.Config.RecordSignalType1, _scanner.Config.RecordSignalType2, _scanner.Config.RecordSignalType3, _scanner.Config.RecordSignalType4); _Scanner.SaveAndRestartTimer(); _Scanner.SetTrigger(0, _Scanner.Config.RecordSignalType1, _Scanner.Config.RecordSignalType2, _Scanner.Config.RecordSignalType3, _Scanner.Config.RecordSignalType4); } return SequenceAction.Ok(); } private static SequenceActionResult SetEndList(SequenceContext context, string id, SequenceActionResult param) { if (_IncludeListStartEnd) { //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST); //_scanner._scannerObj.SetEndList(); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST); _Scanner.SetEndList(); } _UploadSpanTime = DateTime.Now.Subtract(_UploadstartTime); Log.D(string.Format($"[SeqUploadWeldingList_Old] UploadWeldingList Complete Time : {_UploadSpanTime.TotalMilliseconds}")); return SequenceAction.Ok(); } private static void FuncLoadDrawObjectScannerParam(List objects) { _DrawObjectCount = 0; foreach (IDrawObject obj in objects) { _DrawObjectCount += FuncLoadDrawObjectScannerParamSelec(obj); } } private static int FuncLoadDrawObjectScannerParamSelec(IDrawObject obj) { int count = 0; if (obj.Enabled == true) { 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 Group) { count += LoadGroupScannerParam((Group)obj); } else if (obj is Arc) { LoadArcScannerParam((Arc)obj); count++; } else if (obj is ZigZag) { LoadZigzagScannerParam((ZigZag)obj); count++; } else if (obj is Arc3Point) { LoadArc3PScannerParam((Arc3Point)obj); count++; } } return count; } private static 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 (_Laser.Config.Type == eLaserType.Trumpf_IO || _Laser.Config.Type == eLaserType.Coherent_Arm_IO) { //_scanner._scannerObj.SetLaserTiming((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000), (uint)(param.LaserPulseDuration * 1000)); _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._scannerObj.SetLaesrDelay(param.LaserOnDelay, param.LaserOffDelay); _Scanner.SetLaesrDelay(param.LaserOnDelay, param.LaserOffDelay); //2.Mark delay 설정 //_scanner._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay); _Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay); //3.DA(레이저 파워값) 설정 percentLaser1 = (float)_LaserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1); percentLaser2 = (float)_LaserPowerCalParam.CalibrateWattToPercent(param.LaserPower2, (uint)eAnalogPortOut.DA2); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); //4.점프 및 마크 속도 설정 //_scanner._scannerObj.SetJumpSpeed(param.JumpSpeed); //_scanner._scannerObj.SetMarkSpeed(param.MarkSpeed); _Scanner.SetJumpSpeed(param.JumpSpeed); _Scanner.SetMarkSpeed(param.MarkSpeed); } private static void LoadLineScannerParam(Line obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0.0f; float percentLaser2 = 0.0f; //5. Offset 설정(Camera Offset + Object의 Vision Offset) //m_scannerToCameraReferenceOffsets은 SystemParameter에서 설정된 값, Cal하고나면 해당 Offset은 현재 필요없는거같은데 확인 필요, 필요시 Camera setting에 추가해주면됨 //m_externalCommandOffset은 AutoRun시 PLC에서 받아오는 offset임, 현재 LASA에서 BhAutoRun 클래스에 CCW라인에서만 사용하던데 실제 사용하는지 확인 필요 double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 1. 스캐너 가공 조건 설정 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})")); #endregion #region 2. 스캐너 가공 작업 #region 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._scannerObj.SetWobbelDirection(dx, dy); //_scanner._scannerObj.SetWobbelDirection(0, 0); _Scanner.SetWobbelDirection(dx, dy); _Scanner.SetWobbelDirection(0, 0); //5.Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(true, 1, 1, 1, 2); _Scanner.SetWobbelMode(true, 1, 1, 1, 2); //Wobbel Vector 리스트 초기화 //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0); _Scanner.SetWobbelVector(0, 0, 0, 0); List dTrans = new List(); List dLong = new List(); param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor); for (int i = 0; i < dTrans.Count; i++) { //_scanner._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0); _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._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); _Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); } } //Zigzag 와블인 경우 if (param.ZigzagWobbelEnable) { //5.Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelDirection(0, 0); //_scanner._scannerObj.SetWobbelMode(true, 1, 1, 1, 2); _Scanner.SetWobbelDirection(0, 0); _Scanner.SetWobbelMode(true, 1, 1, 1, 2); //Wobbel Vector 리스트 초기화 //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0); _Scanner.SetWobbelVector(0, 0, 0, 0); List dTrans = new List(); List dLong = new List(); param.CreateWobbelVectorForZigzagPointList(); //_scanner._scannerObj.SetMarkSpeed(param.zigzagTotalSpeed); _Scanner.SetMarkSpeed(param.zigzagTotalSpeed); param.LoadZigZagWobbelVector(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor); for (int i = 0; i < dTrans.Count; i++) { //_scanner._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.m_zigzagPeriod[i + 1], 0); _Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.m_zigzagPeriod[i + 1], 0); } } //일반적인 와블인 경우 if (!param.SnowManEnable && !param.ZigzagWobbelEnable) { //_scanner._scannerObj.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); _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._scannerObj.SetWobbelDirection(0, 0); //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0); //_scanner._scannerObj.SetWobbelMode(false, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, 0); _Scanner.SetWobbelDirection(0, 0); _Scanner.SetWobbelVector(0, 0, 0, 0); _Scanner.SetWobbelMode(false, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, 0); } #endregion #region Ramping & PowerProfile 관련 설정 if (param.UsePowerProfile) { PowerProfilesList powerProfile = ReadPowerProfile(param.PowerProfileID); #region 시작위치 점프 관련 설정 float power = 0; if (powerProfile.PowerProfiles.Count != 0) { power = percentLaser1 * (float)powerProfile.PowerProfiles[0].PowerProfileParams[0].StartPowerPercent * 0.01f; //Param 명령을 주기 위해서는 Polygon Delay 를 0으로 한다. //_scanner._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0); _Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0); // 지그재그는 벡터 기반 컨트롤 //_scanner._scannerObj.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, (uint)eAutoControlParameter.AnalogOut1); _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._scannerObj.SetScannerDelay(0, param.MarkDelay, 0); //_scanner._scannerObj.ParaJumpRel(0, 0, power); _Scanner.SetScannerDelay(0, param.MarkDelay, 0); _Scanner.ParaJumpRel(0, 0, power); } else { //_scanner._scannerObj.ParaJumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, power); _Scanner.ParaJumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, power); } //첫번째 Profile Param double x = 0; double y = 0; double totalTime = powerProfile.PowerProfiles[0].PowerProfileParams[0].Time; double speed = param.ZigzagWobbelEnable ? param.zigzagTotalSpeed : param.MarkSpeed; double profileDistance = totalTime * speed * 0.001f; 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[0].PowerProfileParams[0].EndPowerPercent * 0.01f; //_scanner._scannerObj.ParaMarkAbs(x + XOffset, y + YOffset, power); _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._scannerObj.SetScannerDelay(0, param.MarkDelay, 0); //_scanner._scannerObj.ParaJumpRel(0, 0, power); _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._scannerObj.ParaMarkAbs(x + XOffset, y + YOffset, power); _Scanner.ParaMarkAbs(x + xOffset, y + yOffset, power); } else { break; } } } if (profileDistance < obj.Distance) { //_scanner._scannerObj.ParaMarkAbs(obj.P2.X + XOffset, obj.P2.Y + YOffset, power); _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._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST); } //Write_da 함수는 시작점으로 점프한 이후 Mark 명령 직전에 해준다. //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); //_scanner._scannerObj.MarkAbs(obj.PF2.X + XOffset, obj.PF2.Y + YOffset); _Scanner.MarkAbs(obj.PF2.X + xOffset, obj.PF2.Y + yOffset); } #endregion } else { //Wobble, PowerProfile, Ramping을 사용하지 않는 일반적인 경우 이쪽으로 들어옴 #region 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으로 변경 //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST); //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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})")); } #endregion #region 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._scannerObj.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); _Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); // 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다. // 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다. //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); //_scanner._scannerObj.MarkAbs(obj.PF2.X + XOffset, obj.PF2.Y + YOffset); _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._scannerObj.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); //_scanner._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0); _Scanner.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); _Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, 0); double x = 0; double y = 0; if (0 < param.RampingStartDist) { //_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1 * (float)param.RampingStartPower * 0.01f); _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._scannerObj.ParaMarkAbs(x + XOffset, y + YOffset, percentLaser1); _Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1); } else { //_scanner._scannerObj.ParaMarkAbs(x + XOffset, y + YOffset, percentLaser1 * (float)param.RampingStartPower * 0.01f); //_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1); _Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1 * (float)param.RampingStartPower * 0.01f); _Scanner.ParaMarkRel(0, 0, percentLaser1); } } else { //_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1); _Scanner.ParaMarkRel(0, 0, percentLaser1); } if (0 < param.RampingEndDist) { // 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._scannerObj.ParaMarkAbs(x + XOffset, y + YOffset, percentLaser1); _Scanner.ParaMarkAbs(x + xOffset, y + yOffset, percentLaser1); //Ramping End 끝지점 까지 if (param.RampingEndSlopeMode) { //_scanner._scannerObj.ParaMarkAbs(obj.P2.X + XOffset, obj.P2.Y + YOffset, percentLaser1 * (float)param.RampingEndPower * 0.01f); _Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, percentLaser1 * (float)param.RampingEndPower * 0.01f); } else { //_scanner._scannerObj.ParaMarkRel(0, 0, percentLaser1 * (float)param.RampingEndPower * 0.01f); //_scanner._scannerObj.ParaMarkAbs(obj.P2.X + XOffset, obj.P2.Y + YOffset, percentLaser1 * (float)param.RampingEndPower * 0.01f); _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._scannerObj.ParaMarkAbs(obj.P2.X + XOffset, obj.P2.Y + YOffset, percentLaser1); _Scanner.ParaMarkAbs(obj.P2.X + xOffset, obj.P2.Y + yOffset, percentLaser1); } //_scanner._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay); //_scanner._scannerObj.SetVectorControl((uint)eAutoControlParameter.NoUse, 0); _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._scannerObj.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); _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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); //_scanner._scannerObj.MarkAbs(obj.PF2.X + XOffset, obj.PF2.Y + YOffset); _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})")); } #endregion } #endregion _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})")); } #endregion private static PowerProfilesList ReadPowerProfile(int powerProfileID) { //추후 경로 변경 필요 var json = File.ReadAllText("PowerProfileTest.json"); var root = JsonConvert.DeserializeObject(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 static void LoadDotScannerParam(Dot obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0.0f; float percentLaser2 = 0.0f; #region 1. 스캐너 가공 조건 설정 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})")); #endregion #region 2. 스캐너 가공 작업 //카메라 오프셋 + Object의 Vision Offset double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region Jump(Point Shot) // Jump 할 때는 Analog Out 값을 0으로 변경 //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST); //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, 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})")); #endregion #region Mark(Point Shot) //_scanner._scannerObj.SetVectorControl((uint)eAutoControlParameter.AnalogOut1, 0); //_scanner._scannerObj.SetLaserTiming((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000), (uint)(param.LaserPulseDuration * 1000)); _Scanner.SetLaserTiming((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000), (uint)(param.LaserPulseDuration * 1000)); // @deprecated 해당 코드는 사용에 주의가 필요 함.. 만약 사용시 원복할 필요가 있음.. // 이후 공정에 영향을 미치는 인자이므로 //_scanner._scannerObj.SetStandby((uint)param.LaserFrequency, (uint)(param.LaserPulseDuration * 1000)); //_scanner._scannerObj.SetStandby(10, 0); _Scanner.SetStandby(10, 0); //_scanner._scannerObj.SetScannerDelay(param.JumpDelay, 0, 0); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); _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._scannerObj.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay); //_scanner._scannerObj.LaserOnList(param.SpotShotTime); _Scanner.SetScannerDelay(param.JumpDelay, param.MarkDelay, param.PolygonDelay); _Scanner.LaserOnList(param.SpotShotTime); //_scanner._scannerObj.SetVectorControl((uint)eAutoControlParameter.NoUse, 0); Log.I(string.Format($"[Point Weld] Mark ({obj.PF1.X + xOffset},{obj.PF1.Y + yOffset})")); #endregion //Dot도 Last값 추가 _LastX = obj.PF1.X + xOffset; _LastY = obj.PF1.Y + yOffset; #endregion } private static void LoadSplineScannerParam(Spline obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0; float percentLaser2 = 0; double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 1.스캐너 가공조건 설정 SetScannerProcessCondition(param, out percentLaser1, out percentLaser2); //Spline 의 경우 Wobbel 해제 //_scanner._scannerObj.SetWobbelMode(false, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); _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})")); #endregion #region 2.스캐너 가공 작업 int pointCount = obj.P1.Count; switch (obj.DrawWay) { case Spline.DrawWayType.OUT_OUT: { //P1 OUT에서 시작 //_scanner._scannerObj.JumpAbs(obj.P1[pointCount - 1].X + XOffset, obj.P1[pointCount - 1].Y + YOffset, eFunctionType.LIST); _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._scannerObj.MarkAbs(obj.P1[i].X + XOffset, obj.P1[i].Y + YOffset); _Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset); } //tornado 의 경우 P2까지 if (obj.SplineTornado) { //P2 OUT에서 시작 //_scanner._scannerObj.JumpAbs(obj.P2[pointCount - 1].X + XOffset, obj.P2[pointCount - 1].Y + YOffset, eFunctionType.LIST); _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._scannerObj.MarkAbs(obj.P2[i].X + XOffset, obj.P2[i].Y + YOffset); _Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset); } } } break; case Spline.DrawWayType.OUT_IN: { //P1 OUT에서 시작 //_scanner._scannerObj.JumpAbs(obj.P1[pointCount - 1].X + XOffset, obj.P1[pointCount - 1].Y + YOffset, eFunctionType.LIST); _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._scannerObj.MarkAbs(obj.P1[i].X + XOffset, obj.P1[i].Y + YOffset); _Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset); } //tornado 의 경우 P2까지 if (obj.SplineTornado) { //P2 IN에서 시작 //_scanner._scannerObj.JumpAbs(obj.P2[0].X + XOffset, obj.P2[0].Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.P2[0].X + xOffset, obj.P2[0].Y + yOffset, eFunctionType.LIST); for (int i = 1; i < obj.P2.Count; i++) { //_scanner._scannerObj.MarkAbs(obj.P2[i].X + XOffset, obj.P2[i].Y + YOffset); _Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset); } } } break; case Spline.DrawWayType.IN_OUT: { //P1 IN에서 시작 //_scanner._scannerObj.JumpAbs(obj.P1[0].X + XOffset, obj.P1[0].Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.P1[0].X + xOffset, obj.P1[0].Y + yOffset, eFunctionType.LIST); for (int i = 1; i < obj.P1.Count; i++) { //_scanner._scannerObj.MarkAbs(obj.P1[i].X + XOffset, obj.P1[i].Y + YOffset); _Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset); } //tornado 의 경우 P2까지 if (obj.SplineTornado) { //P2 OUT에서 시작 //_scanner._scannerObj.JumpAbs(obj.P2[pointCount - 1].X + XOffset, obj.P2[pointCount - 1].Y + YOffset, eFunctionType.LIST); _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._scannerObj.MarkAbs(obj.P2[i].X + XOffset, obj.P2[i].Y + YOffset); _Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset); } } } break; case Spline.DrawWayType.IN_IN: { //P1 IN에서 시작 //_scanner._scannerObj.JumpAbs(obj.P1[0].X + XOffset, obj.P1[0].Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.P1[0].X + xOffset, obj.P1[0].Y + yOffset, eFunctionType.LIST); for (int i = 1; i < obj.P1.Count; i++) { //_scanner._scannerObj.MarkAbs(obj.P1[i].X + XOffset, obj.P1[i].Y + YOffset); _Scanner.MarkAbs(obj.P1[i].X + xOffset, obj.P1[i].Y + yOffset); } //tornado 의 경우 P2까지 if (obj.SplineTornado) { //P2 IN에서 시작 //_scanner._scannerObj.JumpAbs(obj.P2[0].X + XOffset, obj.P2[0].Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.P2[0].X + xOffset, obj.P2[0].Y + yOffset, eFunctionType.LIST); for (int i = 1; i < obj.P2.Count; i++) { //_scanner._scannerObj.MarkAbs(obj.P2[i].X + XOffset, obj.P2[i].Y + YOffset); _Scanner.MarkAbs(obj.P2[i].X + xOffset, obj.P2[i].Y + yOffset); } } } break; } #endregion Log.I(string.Format($"[Spline Weld] Draw Way : {obj.DrawWay}, Tornado 사용 : {obj.SplineTornado})")); } private static void LoadSnowManScannerParam(SnowMan obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0; float percentLaser2 = 0; double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 1.스캐너 가공조건 설정 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})")); #endregion #region 2. 스캐너 가공 작업 //SnowMan 로드 시작 Math.Cos(obj.TiltingAngle * Math.PI / 180); //wobbel 각도 설정 //_scanner._scannerObj.SetWobbelDirection((int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100), (int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100)); _Scanner.SetWobbelDirection((int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100), (int)(Math.Cos(obj.TiltingAngle * Math.PI / 180) * 100)); //5.Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(true, 1, 1, 1, 2); _Scanner.SetWobbelMode(true, 1, 1, 1, 2); //Wobbel Vector 리스트 초기화 //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 _Scanner.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 List dTrans = new List(); List dLong = new List(); obj.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor); for (int i = 0; i < dTrans.Count; i++) { //_scanner._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)obj.HeadPeriod, 0); _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._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)obj.BodyPeriod, 0); _Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)obj.BodyPeriod, 0); } //서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함 //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); //_scanner._scannerObj.MarkAbs(obj.PF2.X + XOffset, obj.PF2.Y + YOffset); _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})")); #endregion } private static 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 += FuncLoadDrawObjectScannerParamSelec(subObj); } } return count; } private static void LoadArcScannerParam(Arc obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0; float percentLaser2 = 0; //카메라 오프셋 + Object의 Vision Offset double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 스캐너 가공 조건 설정 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})")); #endregion #region Wobbel 관련 설정 //Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행 if (!param.SnowManEnable) { if (param.WobbelEnable) { //wobbel 각도 설정 //_scanner._scannerObj.SetWobbelDirection(0, 0); _Scanner.SetWobbelDirection(0, 0); //Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); _Scanner.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); //wobbel 모드 설정 로그 추가 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._scannerObj.SetWobbelDirection(0, 0); //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0); //_scanner._scannerObj.SetWobbelMode(false, 0, 0, 0, 0); _Scanner.SetWobbelDirection(0, 0); _Scanner.SetWobbelVector(0, 0, 0, 0); _Scanner.SetWobbelMode(false, 0, 0, 0, 0); } //2.스캐너 가공 작업 //서브객체인 경우에는 부모객체의 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._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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._scannerObj.SetWobbelDirection(dx, dy); _Scanner.SetWobbelDirection(dx, dy); //5.Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(true, 1, 1, 1, 2); _Scanner.SetWobbelMode(true, 1, 1, 1, 2); //Wobbel Vector 리스트 초기화 //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 _Scanner.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 List dTrans = new List(); List dLong = new List(); param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor); for (int i = 0; i < dTrans.Count; i++) { //_scanner._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0); _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._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); _Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); } //2.스캐너 가공 작업 //서브객체인 경우에는 부모객체의 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._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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})")); } } #endregion #region 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; // 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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); // 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다. // 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다. //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); //Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전 //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, obj.SweepAngle); _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 가능하도록 수정 // 1.1. 데이터테이블 기준으로 파워 동작 //percentLaser1 = (float)_laserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1); // 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.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 ? percentLaser1 * (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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, risingEdgePercentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, risingEdgePercentLaser2, eFunctionType.LIST); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _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); } // 3.1. Constant Range 파워 설정 //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); // 3.2. Constant Range 구간 위치 변경 for (int iter = risingEdgeCount; iter < totalCount - fallingEdgeCount; iter++) { //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta); } //4.1. Falling Edge 마지막 파워 설정 float endingPercentLaser1 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ? percentLaser1 * (float)param.RampingEndPower / 100 : 100; float fallingEdgePercentLaser1 = 0; float endingPercentLaser2 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ? percentLaser1 * (float)param.RampingEndPower / 100 : 100; float fallingEdgePercentLaser2 = 0; //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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, fallingEdgePercentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, fallingEdgePercentLaser2, eFunctionType.LIST); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _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); } // 5. 마지막 위치까지 이동해줌. double lastSweep = obj.SweepAngle - (totalCount * theta); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, lastSweep); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, lastSweep); } else { //Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전 //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, obj.SweepAngle); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle); } #endregion _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 static void LoadArc3PScannerParam(Arc3Point obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0; float percentLaser2 = 0; //카메라 오프셋 + Object의 Vision Offset double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 스캐너 가공 조건 설정 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})")); #endregion #region Wobbel 관련 설정 //Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행 if (!param.SnowManEnable) { if (param.WobbelEnable) { //wobbel 각도 설정 //_scanner._scannerObj.SetWobbelDirection(0, 0); _Scanner.SetWobbelDirection(0, 0); //Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); _Scanner.SetWobbelMode(param.WobbelEnable, param.WobbelTransversal, param.WobbelLongditudinal, param.WobbelFrequency, (int)param.WobbelShape); //wobbel 모드 설정 로그 추가 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._scannerObj.SetWobbelDirection(0, 0); //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0); //_scanner._scannerObj.SetWobbelMode(false, 0, 0, 0, 0); _Scanner.SetWobbelDirection(0, 0); _Scanner.SetWobbelVector(0, 0, 0, 0); _Scanner.SetWobbelMode(false, 0, 0, 0, 0); } //2.스캐너 가공 작업 //서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함 //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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._scannerObj.SetWobbelDirection(dx, dy); _Scanner.SetWobbelDirection(dx, dy); //5.Wobbel 모드 설정 //_scanner._scannerObj.SetWobbelMode(true, 1, 1, 1, 2); _Scanner.SetWobbelMode(true, 1, 1, 1, 2); //Wobbel Vector 리스트 초기화 //_scanner._scannerObj.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 _Scanner.SetWobbelVector(0, 0, 0, 0);//period=0은 초기화 List dTrans = new List(); List dLong = new List(); param.LoadWobbelVectorForHead(out dTrans, out dLong, (int)_Scanner.Config.ScaleXYFactor); for (int i = 0; i < dTrans.Count; i++) { //_scanner._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.HeadPeriod, 0); _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._scannerObj.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); _Scanner.SetWobbelVector(dTrans[i], dLong[i], (uint)param.BodyPeriod, 0); } //2.스캐너 가공 작업 //서브객체인 경우에는 부모객체의 scanner parameter 조건으로 설정되어야 함 //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _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})")); } } #endregion #region 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; // 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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, AnalogPercentLaserPower1, eFunctionType.LIST); // 기존 방식은 SetScannerProcessCondition 함수에서 center, ring 모두 ratio 100% 로 설정한다음, ramping 할때는 Ch1 만 power ratio 를 조정하고 있었다. // 여기에서도 center만 비율 조정하려면 아래 줄을 주석하면된다. 주석처리하지 않으면 center , ring 모두 ramping 거리 비율로 power 조정된다. //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, AnalogPercentLaserPower2, eFunctionType.LIST); //Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전 //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, obj.SweepAngle); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle); } else { // 기존 코드 유지 // @SMW/LHS Wobbel 사용 시 Lamping도 사용 할 수 있도록 조건문 수정 및 Ring빔도 Ramping 가능하도록 수정 // 1.1. 데이터테이블 기준으로 파워 동작 //percentLaser1 = (float)_laserPowerCalParam.CalibrateWattToPercent(param.LaserPower1, (uint)eAnalogPortOut.DA1); // 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.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 ? percentLaser1 * (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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, risingEdgePercentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, risingEdgePercentLaser2, eFunctionType.LIST); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _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); } // 3.1. Constant Range 파워 설정 //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, percentLaser1, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, percentLaser2, eFunctionType.LIST); // 3.2. Constant Range 구간 위치 변경 for (int iter = risingEdgeCount; iter < totalCount - fallingEdgeCount; iter++) { //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, theta); } //4.1. Falling Edge 마지막 파워 설정 float endingPercentLaser1 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ? percentLaser1 * (float)param.RampingEndPower / 100 : 100; float fallingEdgePercentLaser1 = 0; float endingPercentLaser2 = percentLaser1 * (float)param.RampingEndPower / 100 <= 100 ? percentLaser1 * (float)param.RampingEndPower / 100 : 100; float fallingEdgePercentLaser2 = 0; //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._scannerObj.WriteDA((uint)eAnalogPortOut.DA1, fallingEdgePercentLaser1, eFunctionType.LIST); //_scanner._scannerObj.WriteDA((uint)eAnalogPortOut.DA2, fallingEdgePercentLaser2, eFunctionType.LIST); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, theta); _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); } // 5. 마지막 위치까지 이동해줌. double lastSweep = obj.SweepAngle - (totalCount * theta); //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, lastSweep); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, lastSweep); } } else { //Arc 는 현재 위치에서 시작, 중심점 기준으로 각도 만큼 회전 //_scanner._scannerObj.ArcAbs(obj.CenterPointF.X + XOffset, obj.CenterPointF.Y + YOffset, obj.SweepAngle); _Scanner.ArcAbs(obj.CenterPointF.X + xOffset, obj.CenterPointF.Y + yOffset, obj.SweepAngle); } #endregion _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 static void LoadZigzagScannerParam(ZigZag obj) { ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo]; float percentLaser1 = 0; float percentLaser2 = 0; //카메라 오프셋 + Object의 Vision Offset + Fly 오프셋 double xOffset = _ScannerToCameraReferenceOffsets.X + _FlyOffsetX + m_externalCommandOffset.X; double yOffset = _ScannerToCameraReferenceOffsets.Y + _FlyOffsetY + m_externalCommandOffset.Y; #region 스캐너 가공 조건 설정 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})")); #endregion #region 시작 위치로 점프 //시작 위치로 점프 if (Math.Abs(_LastX - obj.PF1.X - xOffset) < 0.01 && Math.Abs(_LastY - obj.PF1.Y - yOffset) < 0.01) { //점프 안함 } else { //_scanner._scannerObj.JumpAbs(obj.PF1.X + XOffset, obj.PF1.Y + YOffset, eFunctionType.LIST); _Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST); } #endregion #region Ramping 설정 //지그재그는 아직 Ramping 구현 안됨 #endregion #region 지그재그 순서대로 마킹 for (int i = 0; i < obj.ZigZagCount; i++) { //_scanner._scannerObj.MarkAbs(obj.ArcStartPoints[i].X + XOffset, obj.ArcStartPoints[i].Y + YOffset); _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; bool clockwise = obj.DrawDirection == ZigZag.eDrawDirection.Left ? true : false; if (i % 2 == 0) { if (obj.DrawDirection == ZigZag.eDrawDirection.Left) { sweepAngle = (-1) * Math.Abs(startAngle - endAngle); if (sweepAngle < -180) { sweepAngle = (360 + sweepAngle) * (-1); } //_scanner._scannerObj.ArcAbs(obj.ArcCenterPoints[i].X + XOffset, obj.ArcCenterPoints[i].Y + YOffset, sweepAngle); _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._scannerObj.ArcAbs(obj.ArcCenterPoints[i].X + XOffset, obj.ArcCenterPoints[i].Y + YOffset, 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._scannerObj.ArcAbs(obj.ArcCenterPoints[i].X + XOffset, obj.ArcCenterPoints[i].Y + YOffset, sweepAngle); _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._scannerObj.ArcAbs(obj.ArcCenterPoints[i].X + XOffset, obj.ArcCenterPoints[i].Y + YOffset, sweepAngle); _Scanner.ArcAbs(obj.ArcCenterPoints[i].X + xOffset, obj.ArcCenterPoints[i].Y + yOffset, sweepAngle); } } //_scanner._scannerObj.MarkAbs(obj.LineEndPoints[i].X + XOffset, obj.LineEndPoints[i].Y + YOffset); _Scanner.MarkAbs(obj.LineEndPoints[i].X + xOffset, obj.LineEndPoints[i].Y + yOffset); } #endregion _LastX = obj.LineEndPoints[obj.ZigZagCount - 1].X + xOffset; _LastY = obj.LineEndPoints[obj.ZigZagCount - 1].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})")); } } }