From e98384906b5150e794f2dbf5ba6a4e1eb390455c Mon Sep 17 00:00:00 2001 From: RnD_Welder Date: Wed, 15 Apr 2026 16:34:49 +0900 Subject: [PATCH] =?UTF-8?q?feat:260415=20MOTF=EC=8B=9C=ED=80=B8=EC=8A=A4(A?= =?UTF-8?q?utoRunScanner)=EA=B4=80=EB=A0=A8=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuroraLaserScanner/ScannerConfig.cs | 7 +- .../Sequences/SeqAutoRunPrismaticScanner.cs | 63 ++++++++++++- .../LASA/GUI/Scanner/ScannerUnit.cs | 43 +++++++++ .../Sequences/Main/SeqUploadWeldingList.cs | 94 +++++++++---------- 4 files changed, 151 insertions(+), 56 deletions(-) diff --git a/AuroraDevices/AuroraLaserScanner/ScannerConfig.cs b/AuroraDevices/AuroraLaserScanner/ScannerConfig.cs index b5a9348..0595174 100644 --- a/AuroraDevices/AuroraLaserScanner/ScannerConfig.cs +++ b/AuroraDevices/AuroraLaserScanner/ScannerConfig.cs @@ -69,13 +69,18 @@ namespace AuroraLaserScanner public double MarkingOntheFlyOffsetY { get; set; } public double MarkingOntheFlyParkingPositionX { get; set; } public double MarkingOntheFlyParkingPositionY { get; set; } + public double MarkingStartX_1 { get; set; } + public double MarkingStartX_2 { get; set; } + public double XDiff_Page1and2 { get; set; } + public double XDiff_Page3and4 { get; set; } + public eWaitEncoderMode MarkingStartWaitMode { get; set; } public eOntheFlyCoordinate OnTheFlyCoordinate { get; set; } public double FlySpeedInterlock { get; set; } public double RotaryEncoderOffset { get; set; } public double MOTFStageSpeed { get; set; } - #region 26.04.08 NDY MOTF Limit(추적 오차 한계) 변수 추가 --- RTC5에 있는 보드num 과 x,y,z에 대한 limit bit수를 입력하면 해당 오차 벗어나면 알려주는 메소드가 존재합니다. 현재는 stop을 직접하니깐 변수 추가하고 메소드 추가추가해서 사용하는 방식으로 확인 부탁드립니다. + #region 26.04.08 NDY MOTF Limit(추적 오차 한계) 변수 추가 --- RTC5에 있는 보드num 과 x,y,z에 대한 limit bit수를 입력하면 해당 오차 벗어나면 알려주는 메소드가 존재합니다. 현재는 stop을 직접하니깐 변수 추가하고 메소드 추가추가해서 사용하는 방식으로 확인 부탁드립니다. [DisplayName("Tracking Error Limit X (mm)")] public double FlyLimitXmm { get; set; } = 28.0; // 60 FOV 기준 약 90% 지점 - bit로 자동 변환되는지를 확인 해야함. diff --git a/Machines/ILSOS_PrismaticScanner/Sequences/SeqAutoRunPrismaticScanner.cs b/Machines/ILSOS_PrismaticScanner/Sequences/SeqAutoRunPrismaticScanner.cs index 36f3488..60c59c8 100644 --- a/Machines/ILSOS_PrismaticScanner/Sequences/SeqAutoRunPrismaticScanner.cs +++ b/Machines/ILSOS_PrismaticScanner/Sequences/SeqAutoRunPrismaticScanner.cs @@ -48,6 +48,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Forms.VisualStyles; using System.Windows.Media.Imaging; +using System.Xml.Linq; using VisionCommon; using WeldingCommon; using WeldingCommon.Alarm; @@ -80,9 +81,11 @@ namespace ILSOS_PrismaticScanner.Sequences const string SEQ_ENTER = "SEQ_ENTER"; // inputParam 으로 받자. const string SEQ_CHECK_INIT_CONDITION = "Check Init Condition"; // Check Init Condition + const string SEQ_SET_BEFORE_UPLOAD = "Set Before Upload"; const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "Set Sequence Param (UploadWeldingList Seq)"; const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "Process (UploadWeldingList Seq)"; const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "Get Sequence Result (UploadWeldingList Seq)"; + const string SEQ_CHECK_AFTER_UPLOAD = "Check After Upload"; const string SEQ_COMPLETE = "SEQ_COMPLETE"; // 완료 @@ -133,6 +136,10 @@ namespace ILSOS_PrismaticScanner.Sequences private static TimeSpan _ScannerSaveLogTime; private static DateTime _partialWeldingStartTime; + private int _PageNum; + private double lastX, lastY; // 저장용 값 + private double _LastX, _LastY; // 진짜로 UploadWeldingList에 들어갈 값 + public SequenceBuilder Builder() { var sb = new SequenceBuilder(1000, true); @@ -145,9 +152,11 @@ namespace ILSOS_PrismaticScanner.Sequences sb.AddAction(SEQ_STANDBY_SCANNER, SetStandbyScanner); #endregion + sb.AddAction(SEQ_SET_BEFORE_UPLOAD, SetBeforeUpload); sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams); sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, CommonSequenceManager.GetSeqBuilder_SeqUploadWeldingList()); sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult); + sb.AddDecision(SEQ_CHECK_AFTER_UPLOAD, CheckAfterUpload); sb.AddAction(SEQ_DO_COMPONENT_WELDING, DoComponentWelding); sb.AddAction(SEQ_ACS_MOTION_SET, SetMotion); sb.AddAction(SEQ_ACS_MOTION_START, StartMotion); @@ -160,9 +169,11 @@ namespace ILSOS_PrismaticScanner.Sequences > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_STANDBY_MOTION] > sb[SEQ_STANDBY_SCANNER] + > sb[SEQ_SET_BEFORE_UPLOAD] > sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ] + > sb[SEQ_CHECK_AFTER_UPLOAD] > sb[SEQ_DO_COMPONENT_WELDING] > sb[SEQ_ACS_MOTION_SET] > sb[SEQ_ACS_MOTION_START] @@ -170,6 +181,9 @@ namespace ILSOS_PrismaticScanner.Sequences > sb[SEQ_COMPLETE] > sb.Final); + sb.Flows(sb[SEQ_CHECK_AFTER_UPLOAD] + > sb[SEQ_SET_BEFORE_UPLOAD]); + sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); @@ -238,7 +252,7 @@ namespace ILSOS_PrismaticScanner.Sequences } _ScannerSaveLogTime = TimeSpan.Zero; - + _PageNum = 2; var startTime = DateTime.Now; context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); @@ -302,15 +316,17 @@ namespace ILSOS_PrismaticScanner.Sequences Log.I("[EncoderReset] 시작"); // SeqUploadWeldingList.MarkingOnTheFlyOn 패턴 + _Scanner.SetStartList(_WeldingScannerListNo); _Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX); Log.I($"[EncoderReset] SetFlyX: {_Scanner.Config.MarkingOnTheFlyEncoderResolutionX}"); - _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX); - Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartEncoderPositionX}"); + // _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX); + // Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartEncoderPositionX}"); _Scanner.StoreEncoder(0); _Scanner.SaveAndRestartTimer(); + Log.I("[EncoderReset] 완료 - Stage(0) = Scanner(0) 동기화"); return SequenceAction.Ok(); } @@ -333,7 +349,34 @@ namespace ILSOS_PrismaticScanner.Sequences } #endregion + private SequenceActionResult SetBeforeUpload(SequenceContext context, string id, SequenceActionResult param) + { + var mainPage = CommonHelper.GetMainPage(); + _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; + _SelectedObjectList = _ScannerCanvasUserCtrl.Model.Layers[_PageNum-1].Objects; + _LastX = lastX; + _LastY = lastY; + if (_PageNum == 2 || _PageNum == 4) { + if (_PageNum == 0) { + _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartX_1); + Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartX_1}"); + } else { + _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartX_2); + Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartX_2}"); + } + foreach (IDrawObject obj in _SelectedObjectList) { + if (obj is Line) { + lastX = obj.PF2.X; + lastY = obj.PF2.Y; + } + } + } + + + Log.D(string.Format($"[SetBeforeUpload] Set Before UploadWeldingList")); + return SequenceAction.Ok(); + } private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param) { Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST); @@ -342,11 +385,14 @@ namespace ILSOS_PrismaticScanner.Sequences SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { NeedSetLaserTiming = _InitParam.NeedSetLaserTiming, - IncludeListStartEnd = true, + IncludeListStartEnd = false, CellMeasureCenterOffsetX = _SystemParameter.CellPosMeasureCenterOffsetX + _InitParam.CellCenterOffsetX, CellMeasureCenterOffsetY = _SystemParameter.CellPosMeasureCenterOffsetY + _InitParam.CellCenterOffsetY, SelectedDrawObjectList = _SelectedObjectList, WeldingScannerListNo = _WeldingScannerListNo, + PageNum = _PageNum, + LastX = _LastX, + LastY = _LastY }; Log.D(string.Format($"[ComponentTeachingRun] Set UploadWelindList Seq Param")); @@ -367,6 +413,13 @@ namespace ILSOS_PrismaticScanner.Sequences return SequenceAction.Ok(); } + private string CheckAfterUpload(SequenceContext context, string id, ICollection branches, SequenceActionResult param) + { + _PageNum += 1; + if (_PageNum == 5) _PageNum = 1; + if (_PageNum == 2) return SEQ_DO_COMPONENT_WELDING; + else return SEQ_SET_BEFORE_UPLOAD; + } private SequenceActionResult DoComponentWelding(SequenceContext context, string id, SequenceActionResult param) { @@ -445,6 +498,8 @@ namespace ILSOS_PrismaticScanner.Sequences _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); + _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY); + _Scanner.SetEndList(); var mesurementTime = DateTime.Now; diff --git a/WeldingComponents/LASA/GUI/Scanner/ScannerUnit.cs b/WeldingComponents/LASA/GUI/Scanner/ScannerUnit.cs index ea5ce5a..f4e72f5 100644 --- a/WeldingComponents/LASA/GUI/Scanner/ScannerUnit.cs +++ b/WeldingComponents/LASA/GUI/Scanner/ScannerUnit.cs @@ -116,6 +116,10 @@ namespace CoreUnit.Scanner double m_markingOntheFlyParkingPositionX; double m_markingOntheFlyParkingPositionY; + double m_markingStartX_1; + double m_markingStartX_2; + double m_XDiff_Page1and2; + double m_XDiff_Page3and4; double m_flySpeedInterlock; double m_rotaryEncoderOffset; @@ -522,6 +526,45 @@ namespace CoreUnit.Scanner get { return m_markingOntheFlyParkingPositionY; } } + [Browsable(true)] + [ReadOnly(false)] + [Category("Marking On The Fly(MOTF)")] + [DisplayName("Marking Start X 1 (mm)")] + [Description("Marking Start X 1 (mm)")] + public double MarkingStartX_1 { + set { m_markingStartX_1 = value; } + get { return m_markingStartX_1; } + } + + [Browsable(true)] + [ReadOnly(false)] + [Category("Marking On The Fly(MOTF)")] + [DisplayName("Marking Start X 2 (mm)")] + [Description("Marking Start X 2 (mm)")] + public double MarkingStartX_2 { + set { m_markingStartX_2 = value; } + get { return m_markingStartX_2; } + } + + [Browsable(true)] + [ReadOnly(false)] + [Category("Marking On The Fly(MOTF)")] + [DisplayName("X Diff Page 1 & 2 (mm)")] + [Description("X Diff Page 1 & 2 (mm)")] + public double XDiff_Page1and2 { + set { m_XDiff_Page1and2 = value; } + get { return m_XDiff_Page1and2; } + } + + [Browsable(true)] + [ReadOnly(false)] + [Category("Marking On The Fly(MOTF)")] + [DisplayName("X Diff Page 3 & 4 (mm)")] + [Description("X Diff Page 3 & 4 (mm)")] + public double XDiff_Page3and4 { + set { m_XDiff_Page3and4 = value; } + get { return m_XDiff_Page3and4; } + } [Browsable(true)] [ReadOnly(false)] [Category("Marking On The Fly(MOTF)")] diff --git a/WeldingComponents/WeldingCommon/Sequences/Main/SeqUploadWeldingList.cs b/WeldingComponents/WeldingCommon/Sequences/Main/SeqUploadWeldingList.cs index fb1f663..569920f 100644 --- a/WeldingComponents/WeldingCommon/Sequences/Main/SeqUploadWeldingList.cs +++ b/WeldingComponents/WeldingCommon/Sequences/Main/SeqUploadWeldingList.cs @@ -8,6 +8,7 @@ using DB; using Hermes; using Matrox.MatroxImagingLibrary; using Newtonsoft.Json; +using OpenCvSharp; using System; using System.Collections.Generic; using System.Configuration; @@ -72,7 +73,7 @@ namespace WeldingCommon.Sequences private static int _CenterRingRatio; // Center Ring의 파워 비율 private static float _LaserPowerRatio; // Laser에서 출력 파워 비율 - + private bool isFirst = true; private static SeqUploadWeldingList_OutParam result; const int ROTATION_DEGREE = 15; // 15도 설정, 하나의 지그가 30도 이므로, 15도부터 돌도록 설정됨. @@ -87,7 +88,7 @@ namespace WeldingCommon.Sequences 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_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); @@ -149,8 +150,13 @@ namespace WeldingCommon.Sequences _LaserPowerCalParam.Initialize(_LaserPowerCalParam.PowerCalibrationCenterBeamCSVFile, _LaserPowerCalParam.PowerCalibrationRingBeamCSVFile); _FlyOffsetX = 0; - _FlyOffsetY = 0; + _FlyOffsetY = 0; + if (_InitParam.PageNum == 1 || _InitParam.PageNum == 2) + _FlyOffsetY += _Scanner.Config.XDiff_Page1and2; + + else + _FlyOffsetY += _Scanner.Config.XDiff_Page3and4; return true; } @@ -225,41 +231,9 @@ namespace WeldingCommon.Sequences return SEQ_MARKING_ON_THE_FLY_ON; } - // MOTF 지원 중 + // 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(); } @@ -363,6 +337,20 @@ namespace WeldingCommon.Sequences } if (obj is Line) { + if (isFirst && (_InitParam.PageNum==2)) { // 이전 Point 정보가 있고 첫번째 Line인 경우 긴 Line 만들어 Upload + Line LongLine = new Line(); + LongLine.PF1 = new PointF((float)_InitParam.LastX, (float)_InitParam.LastY - (float)(_Scanner.Config.XDiff_Page3and4 - _Scanner.Config.XDiff_Page1and2)); + LongLine.PF2 = obj.PF1; + LoadLineScannerParam(LongLine); + isFirst = false; + } + if (isFirst && (_InitParam.PageNum == 4)) { // 이전 Point 정보가 있고 첫번째 Line인 경우 긴 Line 만들어 Upload + Line LongLine = new Line(); + LongLine.PF1 = new PointF((float)_InitParam.LastX, (float)_InitParam.LastY + (float)(_Scanner.Config.XDiff_Page3and4 - _Scanner.Config.XDiff_Page1and2)); + LongLine.PF2 = obj.PF1; + LoadLineScannerParam(LongLine); + isFirst = false; + } LoadLineScannerParam((Line)obj); count++; } else if (obj is Dot) { @@ -1497,24 +1485,24 @@ namespace WeldingCommon.Sequences private SequenceActionResult MarkingOnTheFlyOff(SequenceContext context, string id, SequenceActionResult param) { - if (_Scanner.Config.UseMarkingOnTheFly) { - if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) { - // Linear OTW의 경우, 각 Draw Tool에서 좌표 오프셋을 해 주고 있음 + //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도 회전 - } - } + // } 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); + // // 추후, Parking Position 을 용접 시작 위치로 자동으로 계산되어 들어가게 개선 필요 + // _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY); - // 엔코더 기록(용접 완료) - _Scanner.StoreEncoder(1); - _Scanner.SaveAndRestartTimer(); - } + // // 엔코더 기록(용접 완료) + // _Scanner.StoreEncoder(1); + // _Scanner.SaveAndRestartTimer(); + //} return SequenceAction.Ok(); } @@ -1600,6 +1588,10 @@ namespace WeldingCommon.Sequences public List SelectedDrawObjectList { get; set; } public eListNo WeldingScannerListNo { get; set; } + + public double PageNum { get; set; } + public double LastX { get; set; } + public double LastY { get; set; } } public class SeqUploadWeldingList_OutParam : OutParam