using Aurora; using Aurora.Api; using Aurora.Api.Devices; using Aurora.Api.Manager; using Aurora.View; using AuroraACS; using AuroraCellTracker; using AuroraIO; using AuroraLaser; using AuroraLaser.Trumpf; using AuroraLaserScanner; using AuroraLBAD; using AuroraLight; using AuroraOCT; using AuroraPLC; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; using DB; using DB.Recipe; using Hermes; using Hermes.Functional.Option; using ILSOS_PrismaticScanner.Device; using ILSOS_PrismaticScanner.Models; using Matrox.MatroxImagingLibrary; using MilCommon; using MilUI; using OpenCvSharp; using OpenCvSharp.Dnn; using OpenCvSharp.WpfExtensions; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.Data; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.IO.Pipes; using System.Linq; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Remoting.Contexts; using System.Text; using System.Text.RegularExpressions; using System.Threading; 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; using WeldingCommon.Data; using WeldingCommon.Devices; using WeldingCommon.Devices.ACS; using WeldingCommon.Models; using WeldingCommon.Sequences; using WeldingCommon.Sequences.Main; using WeldingCommon.Settings; using WeldingCommon.Utils; using WeldingCommon.Views; using WeldingCommon.Vision.WeldingObjectGenerator; using static Aurora.Api.SequenceBuilder; using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo; using static AuroraIO.Vendor.PAIX.PAIXIO; using static ILSOS_PrismaticScanner.Device.PLCControllerPrismaticScanner; using static WeldingCommon.Devices.PLCController; using static WeldingCommon.Sequences.Main.SeqExecutePlcBitInterface_InitParam; namespace ILSOS_PrismaticScanner.Sequences { /// /// 각형 스캐너 타입 자동 운전을 위한 시퀸스 /// public class SeqAutoRunPrismaticScanner { static readonly Logger Log = new Logger("SeqAutoRunPrismaticScanner"); 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"; // 완료 const string SEQ_START_WELDING = "Start All Welding"; const string SEQ_DO_COMPONENT_WELDING = "Do Component Welding"; const string SEQ_ACS_MOTION_SET = "Set ACS Motion Parameter"; const string SEQ_ACS_MOTION_START = "ACS Motion Start"; const string SEQ_CHECK_MOTION_END = "Check ACS Motion Complete"; #region 260408 NDY 노드 추가 // Builder()에 노드 추가 const string SEQ_STANDBY_MOTION = "Move Stage To Origin"; const string SEQ_STANDBY_SCANNER = "Encoder Reset"; #endregion const int timeoutSeconds = 10; static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqAutoRunPrismaticScanner"; public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqAutoRunPrismaticScanner"; } private SeqTeachingRun_InitParam _InitParam; private static Scanner _Scanner; // 필드 선언 추가 (다른 필드들 옆에) // 변경 전 //private ScannerACS _ACS; // 변경 후 private IScannerACS _ACS; // 26.04.06 NDY - MOTF용 ACS Stage X 제어 private static ACSMotor _AxisX, _AxisZ; // 26.04.08 NDY - MOTF용 Stage X 축 private SystemParameter _SystemParameter; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 private static SequenceSetting _SequenceSetting; private eListNo _WeldingScannerListNo; private List _SelectedObjectList; private List _TargetObjects; private static DateTime _SequenceCompleteTime; // 시퀸스 시간 private static TimeSpan _MeasurementSpanTime; //측정 시간 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); sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddAction(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 #region 26.04.08 추가된 노드 NDY // 26.04.08 필드 좌표 0,0으로 스테이지 이동 시퀸스 + EncoderReset 호출 sb.AddAction(SEQ_STANDBY_MOTION, SetStandbyMotion); 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); sb.AddAction(SEQ_CHECK_MOTION_END, EndWelding); sb.AddAction(SEQ_COMPLETE, Complete); sb.Flows(sb.Init > sb[SEQ_ENTER] > 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] > sb[SEQ_CHECK_MOTION_END] > sb[SEQ_COMPLETE] > sb.Final); sb.Flows(sb[SEQ_CHECK_AFTER_UPLOAD] > sb[SEQ_SET_BEFORE_UPLOAD]); sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); //sb.Draw("SeqAutoRunPrismaticScanner.pdf"); return sb; } private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("===== SeqTeachingRun Sequence_Enter 진입 ====="); // 임시 추가 Log.I("SeqTeachingRun Start"); _InitParam = param.Param as SeqTeachingRun_InitParam; _SystemParameter = context.Settings[CommonSettingIds.SystemParameter] as SystemParameter; _SequenceSetting = context.Settings[CommonSettingIds.Sequence] as SequenceSetting; _Scanner = context.Devices[DeviceIds.Scanner] as Scanner; if (_Scanner == null) { MessageUtil.ShowErrorToast("Scanner not Ready", Log); return null; } _ACS = context.Devices[DeviceIds.ACS] as ScannerACS; if (_ACS == null) { MessageUtil.ShowErrorToast("ACS not Ready", Log); return null; } _AxisX = context.Devices[CommonDeviceIds.AxisX2] as ACSMotor; if (_AxisX == null) { MessageUtil.ShowErrorToast("AxisX not Ready", Log); return null; } _AxisZ = context.Devices[CommonDeviceIds.AxisZ] as ACSMotor; if (_AxisZ == null) { MessageUtil.ShowErrorToast("AxisZ not Ready", Log); return null; } //Check Device if (!CheckDeviceReady(context)) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_DeviceNotReady); Log.E("The devices are not active."); return null; } return SequenceAction.Ok(); } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { DeviceIds.ACS, CommonDeviceIds.Scanner, CommonDeviceIds.AxisX2, CommonDeviceIds.AxisZ }; //List deviceListToCheck = new List() { CommonDeviceIds.Scanner, CommonDeviceIds.IODevice,DeviceIds.ACS }; 변수 맵 수신 후 ACS 주석 해제 위에 주석 처리 bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private SequenceActionResult CheckInitCondition(SequenceContext context, string id, SequenceActionResult param) { bool boolian = AlarmManager.HasAlarmLevelHigh(); if (boolian) { Log.E($"Clear Heavy Alarms For Welding!"); MessageUtil.ShowWarningToast(string.Format("Clear Heavy Alarms For Welding!")); return null; } _ScannerSaveLogTime = TimeSpan.Zero; _PageNum = 2; var startTime = DateTime.Now; context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); Log.D("ComponentTeachingRun Sequence CheckInitCondition"); return SequenceAction.Ok(); } #region 26.04.08 NDY private SequenceActionResult SetStandbyMotion(SequenceContext context, string id, SequenceActionResult param) { if (_AxisX == null) { Log.W("[MoveStageToOrigin] AxisX2 null - 스킵"); return SequenceAction.Ok(); } Log.I("[MoveStageToOrigin] Stage X → 0 이동 시작"); // (스캐너의 0,0 && 용접 대상의 시작 위치) >> X축을 이동 _AxisX.SetTargetPos(0, TargetPosType.ABS); _AxisX.SetMoveVelocityImm(AuroraACS.Speed.M); _AxisX.AccelerationImm(AuroraACS.Speed.M); _AxisX.DecelerationImm(AuroraACS.Speed.M); _AxisX.JerkImm(AuroraACS.Speed.M); _AxisX.Move(); // Laser FocusPosition Move _AxisZ.SetTargetPos(0, TargetPosType.ABS); _AxisZ.SetMoveVelocityImm(AuroraACS.Speed.M); _AxisZ.AccelerationImm(AuroraACS.Speed.M); _AxisZ.DecelerationImm(AuroraACS.Speed.M); _AxisZ.JerkImm(AuroraACS.Speed.M); _AxisZ.Move(); var res = context.RetryUntilSuccess( () => _AxisX.IsReachedTargetPosition(0) && _AxisZ.IsReachedTargetPosition(0), 30 * 1000, 20, true); if (res == E2.TIMEOUT) { Log.E("[MoveStageToOrigin] TIMEOUT"); return null; } else if (res == E2.CANCELLED) { Log.E("[MoveStageToOrigin] CANCELLED"); return null; } Log.I("[MoveStageToOrigin] Stage X = 0 도달 완료"); return SequenceAction.Ok(); } private SequenceActionResult SetStandbyScanner(SequenceContext context, string id, SequenceActionResult param) { // Scanner Default Setting var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; _WeldingScannerListNo = eListNo.LIST1; //_SelectedObjectList = FindObjects(); // 중복 주석 처리 260417 //Vision Correction File 선택 _Scanner.SelectCorrectionTable(2); if (!_Scanner.Config.UseMarkingOnTheFly) { Log.W("[EncoderReset] MOTF 비활성화 - 스킵"); return SequenceAction.Ok(); } 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.StoreEncoder(0); _Scanner.SaveAndRestartTimer(); Log.I("[EncoderReset] 완료 - Stage(0) = Scanner(0) 동기화"); return SequenceAction.Ok(); } //SeqTeachingPosMoveStageA패턴 참고 - 기존 GUN 프로젝트 시퀸스 private List FindObjects() { if (_InitParam.IsUseExternalObjects) { return _InitParam.ExternalObjects; } else if (_InitParam.IsObjectSelectAll) { return _ScannerCanvasUserCtrl.Model.ActiveLayer.Objects; } else { return _ScannerCanvasUserCtrl.Canvas.Model.SelectedObjects; } } #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); bool _isUseInitParam = _InitParam == null ? false : true; // TeachingRun에는 용접 시퀀스만 정의해서 Auto Run에서도 사용하므로 Offset 넣어줘야 함 SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() { NeedSetLaserTiming = _isUseInitParam ? _InitParam.NeedSetLaserTiming : true, IncludeListStartEnd = false, CellMeasureCenterOffsetX = _SystemParameter.CellPosMeasureCenterOffsetX + (_isUseInitParam ? _InitParam.CellCenterOffsetX :0), CellMeasureCenterOffsetY = _SystemParameter.CellPosMeasureCenterOffsetY + (_isUseInitParam ? _InitParam.CellCenterOffsetY : 0), SelectedDrawObjectList = _SelectedObjectList, WeldingScannerListNo = _WeldingScannerListNo, PageNum = _PageNum, LastX = _LastX, LastY = _LastY }; Log.D(string.Format($"[ComponentTeachingRun] Set UploadWelindList Seq Param")); return SequenceAction.Ok(seqParams); } private SequenceActionResult GetUploadWeldingList_SeqResult(SequenceContext context, string id, SequenceActionResult param) { Log.D(string.Format($"[ComponentTeachingRun] Get UploadWelindList Seq Param")); var resultOutParam = param.Param as SeqUploadWeldingList_OutParam; if (resultOutParam.Success == false) { Log.E(string.Format($"[ComponentTeachingRun] Failed UploadWeldingList Sequence")); return null; } 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) { Log.I("ExecuteList Start"); Log.I($"Welding List Space : {_Scanner.GetListSpace()}"); DateTime weldingTime = DateTime.Now; _Scanner.ExecuteList(_WeldingScannerListNo); // ── 26.04.06 NDY 추가: ACS Stage X 이동 ────────────── // MOTF: Scanner List 실행과 동시에 Stage X 이동 시작 // Stage X 엔코더가 트리거 → WaitForEncoderX 조건 도달 시 갈바노 마킹 // TODO: 변수 맵 수신 후 _ACS.MOTFStart()로 교체 // _ACS?.MOTFStart(); // ──────────────────────────────────────────────────── // ── 26.04.06 NDY 추가: ACS 완료 대기 ───────────────── // TODO: 변수 맵 수신 후 활성화 // while (!_ACS.CheckMOTFComp()) { Thread.Sleep(10); } // ──────────────────────────────────────────────────── if (_Scanner.Config.UseRecordSignal) { DateTime startTime = DateTime.Now; _Scanner.StackRecord(); _ScannerSaveLogTime += DateTime.Now.Subtract(startTime); } // excel 파일 작성 SaveScannerRecordFileForamt(); Log.D(string.Format($"[ComponentTeachingRun] SaveScannerRecordFileForamt Time : {_ScannerSaveLogTime.TotalMilliseconds}")); var PartialTactTime = DateTime.Now.Subtract(_partialWeldingStartTime); Log.D(string.Format($"[TactTime] Complete Partial Component Weld : {PartialTactTime.TotalMilliseconds}")); _ScannerCanvasUserCtrl.TimeLabelUpdate(_MeasurementSpanTime.TotalMilliseconds, PartialTactTime.TotalMilliseconds); return SequenceAction.Ok(); } private SequenceActionResult SetMotion(SequenceContext context, string id, SequenceActionResult param) { #region 디바이스 세팅 값만 가져오기 var _scannerConfig = _Scanner.Config; #endregion Log.I("[SetMotion] 정방향 파라미터 세팅 시작"); Log.I($"[SetMotion] PosX={_scannerConfig.MarkingStartX_1}, NegX={_scannerConfig.MarkingStartX_2}, Vel={_scannerConfig.MOTFStageSpeed}"); // 메뉴얼 화면에서 셋팅이 필요해보임 - 출발, 도착, 스피드,rPCset_MOF_WEL_ACC,iPCset_MOF_WEL_MOTION_INTERVAL // iMOTFComplete 리셋 _ACS.ResetMOTFComp(); // 0 으로 바꿔주는 거 다시 추가해줘야함. Log.I("[SetMotion] ResetMOTFComp 완료"); // 정방향 파라미터 세팅 (310 → 640) bool result = _ACS.SetMOTFParams( posX: _scannerConfig.MarkingStartX_1, negX: _scannerConfig.MarkingStartX_2, velocity: _scannerConfig.MOTFStageSpeed, acc: 5000, interval: 100 ); if (!result) { Log.E("[SetMotion] SetMOTFParams 실패"); return null; } Log.I("[SetMotion] SetMOTFParams 완료"); _ACS.SetMOTFParams(_scannerConfig.MarkingStartX_1, _scannerConfig.MarkingStartX_2, _scannerConfig.MarkSpeed, 0, 0); return SequenceAction.Ok(); } private SequenceActionResult StartMotion(SequenceContext context, string id, SequenceActionResult param) { #region //_ACS.MOTFStart(); //// 모션 동작시키고 바로 확인하면 그냥 빠져나올 것 같음 //var res = context.Wait(1000, 100); //if (res == E2.TIMEOUT) {;} //else if (res == E2.CANCELLED) { Log.E("[MOTF] Motion CANCELLED"); return null; } //res = context.RetryUntilSuccess(() => _ACS.CheckMOTFComp(), 1000 * 20, 100, true); //if (res == E2.TIMEOUT) { Log.E("[MOTF] Motion TIMEOUT"); return null; } //else if (res == E2.CANCELLED) { Log.E("[MOTF] Motion CANCELLED"); return null; } //return SequenceAction.Ok(); #endregion var config = _Scanner.Config; // ── 정방향 실행 (310 → 640) ── Log.I("[StartMotion] 정방향 MOTFStart 호출"); _ACS.MOTFStart(); // 출발 후 50mm 이동 시간만큼 대기 // 50mm / velocity(mm/s) * 1000 = ms int waitMs = (int)((50.0 / config.MOTFStageSpeed) * 1000) + 200; // 여유 200ms Log.I($"[StartMotion] 정방향 50mm 이동 대기 {waitMs}ms"); var res = context.Wait(waitMs, 10); if (res == E2.CANCELLED) { Log.E("[StartMotion] 정방향 50mm 대기 CANCELLED"); return null; } // 정방향 완료 대기 Log.I("[StartMotion] 정방향 CheckMOTFComp 대기 시작"); res = context.RetryUntilSuccess(() => _ACS.CheckMOTFComp(), 1000 * 30, 100, true); if (res == E2.TIMEOUT) { Log.E("[StartMotion] 정방향 TIMEOUT"); return null; } else if (res == E2.CANCELLED) { Log.E("[StartMotion] 정방향 CANCELLED"); return null; } Log.I("[StartMotion] 정방향 완료"); // ── 역방향 세팅 (640 → 310) ── Log.I("[StartMotion] 역방향 파라미터 세팅 시작"); _ACS.ResetMOTFComp(); Log.I("[StartMotion] 역방향 ResetMOTFComp 완료"); bool result = _ACS.SetMOTFParams( posX: config.MarkingStartX_2, // 640 출발 negX: config.MarkingStartX_1, // 310 도착 velocity: config.MOTFStageSpeed, acc: 5000, interval: 100 ); if (!result) { Log.E("[StartMotion] 역방향 SetMOTFParams 실패"); return null; } Log.I($"[StartMotion] 역방향 SetMOTFParams 완료 | PosX={config.MarkingStartX_2}, NegX={config.MarkingStartX_1}"); // ── 역방향 실행 (640 → 310) ── Log.I("[StartMotion] 역방향 MOTFStart 호출"); _ACS.MOTFStart(); // 출발 후 50mm 이동 대기 Log.I($"[StartMotion] 역방향 50mm 이동 대기 {waitMs}ms"); res = context.Wait(waitMs, 10); if (res == E2.CANCELLED) { Log.E("[StartMotion] 역방향 50mm 대기 CANCELLED"); return null; } // 역방향 완료 대기 Log.I("[StartMotion] 역방향 CheckMOTFComp 대기 시작"); res = context.RetryUntilSuccess(() => _ACS.CheckMOTFComp(), 1000 * 30, 100, true); if (res == E2.TIMEOUT) { Log.E("[StartMotion] 역방향 TIMEOUT"); return null; } else if (res == E2.CANCELLED) { Log.E("[StartMotion] 역방향 CANCELLED"); return null; } Log.I("[StartMotion] 역방향 완료 → EndWelding 진입"); return SequenceAction.Ok(); } private SequenceActionResult EndWelding(SequenceContext context, string id, SequenceActionResult param) { _Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut); Log.I("ExecuteList Complete"); _MeasurementSpanTime = DateTime.Now.Subtract(_SequenceCompleteTime); Log.D(string.Format($"[TactTime] Complete All Component Weld : {_MeasurementSpanTime.TotalMilliseconds}")); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 5, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 5, eFunctionType.COMMAND); _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY); _Scanner.SetEndList(); var mesurementTime = DateTime.Now; //용접 완료 후 CorrectionFile Vision으로 원복 _Scanner.SelectCorrectionTable(1); _MeasurementSpanTime = DateTime.Now.Subtract(mesurementTime); Log.D(string.Format($"[ComponentTeachingRun] Change SelectCorrectionTable Time : {_MeasurementSpanTime.TotalMilliseconds}")); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); SeqTeachingRun_OutParam result = new SeqTeachingRun_OutParam() { Success = seqResult }; if (seqResult == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_TeachingRun_ResultFailed); } Log.D("ComponentTeachingRun Sequence Complete"); return SequenceAction.Ok(result); } private void SaveScannerRecordFileForamt() { if (_Scanner.Config.UseRecordSignal) { DateTime startTime = DateTime.Now; _Scanner.SaveStackRecord("Normal"); _ScannerSaveLogTime += DateTime.Now.Subtract(startTime); } } private void OnForceError(SequenceContext context, string arg2) { // Scanner Log 저장 SaveScannerRecordFileForamt(); //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 // 복귀 시 Scanner Busy 상태일 수 있으므로 진행중인 작업이 끝날 때까지 대기 Thread.Sleep(10); _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Thread.Sleep(10); Log.I("SequenceAction Ok : OnForceError"); } private void OnStopped(SequenceContext context) { // Scanner Log 저장 SaveScannerRecordFileForamt(); //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); _Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 // 복귀 시 Scanner Busy 상태일 수 있으므로 진행중인 작업이 끝날 때까지 대기 Thread.Sleep(10); _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Thread.Sleep(10); Log.I("SequenceAction Ok : OnStopped"); } } // TODO: UseStream 으로 TeachingRun 을 할 필요가 있을까?? 확인 필요 public class SeqAutoRunPrismaticScanner_InitParam : InitParam { public bool IsObjectSelectAll { get; set; } // All == true, Selected Object == false public bool UseStream { get; set; } public bool UseBlow { get; set; } public int IntervalTimeBlowOn { get; set; } public int IntervalTimeBlowOff { get; set; } public bool NeedSetLaserTiming { get; set; } // For SubSequence, SeqUploadWeldingList } public class SeqAutoRunPrismaticScanner_OutParam : OutParam { } }