diff --git a/Machines/ILSOS_PrismaticScanner/Sequences/Manual/SeqComponentTeachingRun.cs b/Machines/ILSOS_PrismaticScanner/Sequences/Manual/SeqComponentTeachingRun.cs index f5095db..1278ae7 100644 --- a/Machines/ILSOS_PrismaticScanner/Sequences/Manual/SeqComponentTeachingRun.cs +++ b/Machines/ILSOS_PrismaticScanner/Sequences/Manual/SeqComponentTeachingRun.cs @@ -1,7 +1,9 @@ using Aurora; using Aurora.Api; +using Aurora.Api.Devices; using Aurora.Api.Services; using Aurora.View; +using AuroraACS; using AuroraIO; using AuroraLaser; using AuroraLaser.Ekspla; @@ -68,6 +70,12 @@ namespace ILSOS_PrismaticScanner.Sequences const string SEQ_CHECK_END_LIST = "[SeqComponentTeachingRun] Check End List"; const string SEQ_END_WELDING = "[SeqComponentTeachingRun] End All Welding"; + #region 260408 NDY 노드 추가 + // Builder()에 노드 추가 + const string SEQ_MOVE_STAGE_ORIGIN = "[SeqComponentTeachingRun] Move Stage To Origin"; + const string SEQ_ENCODER_RESET = "[SeqComponentTeachingRun] Encoder Reset"; + #endregion + const int timeoutSeconds = 10; static class ContextKey { @@ -83,9 +91,12 @@ namespace ILSOS_PrismaticScanner.Sequences // 필드 선언 추가 (다른 필드들 옆에) // 변경 전 //private ScannerACS _ACS; + // 변경 후 private IScannerACS _ACS; // 26.04.06 NDY - MOTF용 ACS Stage X 제어 + private static ACSMotor _AxisX; // 26.04.08 NDY - MOTF용 Stage X 축 + private Laser _Laser; private ILaser _LaserDevice; private LaserTruFiber _LaserTruFiber; @@ -127,6 +138,12 @@ namespace ILSOS_PrismaticScanner.Sequences sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddAction(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 sb.AddAction(SEQ_SET_BLOW_ON, SetBlowOn); + #region 26.04.08 추가된 노드 NDY + // 26.04.08 필드 좌표 0,0으로 스테이지 이동 시퀸스 + EncoderReset 호출 + sb.AddAction(SEQ_MOVE_STAGE_ORIGIN, MoveStageToOrigin); + sb.AddAction(SEQ_ENCODER_RESET, EncoderReset); + #endregion + sb.AddAction(SEQ_START_WELDING, StartWelding); sb.AddDecision(SEQ_CHECK_END_LIST, CheckEndList); sb.AddAction(SEQ_UPDATE_COMPONENT_WELDING_PARAMETERS, UpdateComponentWeldingParameters); @@ -140,10 +157,19 @@ namespace ILSOS_PrismaticScanner.Sequences sb.AddAction(SEQ_COMPLETE, Complete); - + // 기존 흐름에서 SET_BLOW_ON → START_WELDING 사이에 끼워넣기 + #region 기존 흐름 26.04.08 + //sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_BLOW_ON] + // > sb[SEQ_START_WELDING] > sb[SEQ_CHECK_END_LIST]); + #endregion + #region 2개 노드 추가한 흐름 26.04.08 sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_SET_BLOW_ON] + > sb[SEQ_MOVE_STAGE_ORIGIN] // ← 추가 + > sb[SEQ_ENCODER_RESET] // ← 추가 > sb[SEQ_START_WELDING] > sb[SEQ_CHECK_END_LIST]); + #endregion + // 아래 두 흐름은 기존 그대로 유지 sb.Flows(sb[SEQ_CHECK_END_LIST] > sb[SEQ_UPDATE_COMPONENT_WELDING_PARAMETERS] > 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_DO_COMPONENT_WELDING] > sb[SEQ_CHECK_END_LIST]); @@ -158,9 +184,70 @@ namespace ILSOS_PrismaticScanner.Sequences return sb; } + #region 26.04.08 NDY + private SequenceActionResult EncoderReset(SequenceContext context, string id, SequenceActionResult param) + { + if (_ACS == null) + { + Log.W("[EncoderReset] ACS null - 스킵"); + return SequenceAction.Ok(); + } + if (!_Scanner.Config.UseMarkingOnTheFly) + { + Log.W("[EncoderReset] MOTF 비활성화 - 스킵"); + return SequenceAction.Ok(); + } + + Log.I("[EncoderReset] 시작"); + + // SeqUploadWeldingList.MarkingOnTheFlyOn 패턴 + _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 SequenceActionResult MoveStageToOrigin(SequenceContext context, string id, SequenceActionResult param) + { + if (_AxisX == null) + { + Log.W("[MoveStageToOrigin] AxisX2 null - 스킵"); + return SequenceAction.Ok(); + } + + Log.I("[MoveStageToOrigin] Stage X → 0 이동 시작"); + + // SeqTeachingPosMoveStageA.MoveXYStage 패턴 + _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(); + + var res = context.RetryUntilSuccess( + () => _AxisX.IsReachedTargetPosition(0), + 30 * 1000, 20, true); + + if (res == E2.TIMEOUT) { Log.E("[MoveStageToOrigin] TIMEOUT"); return null; } + if (res == E2.CANCELLED) { Log.E("[MoveStageToOrigin] CANCELLED"); return null; } + + Log.I("[MoveStageToOrigin] Stage X = 0 도달 완료"); + return SequenceAction.Ok(); + + } + #endregion 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; @@ -209,6 +296,10 @@ namespace ILSOS_PrismaticScanner.Sequences // 변경 후 try { _ACS = context.Devices[DeviceIds.ACS] as IScannerACS; } catch { _ACS = null; Log.W("ACS 디바이스 취득 실패 (null 처리)"); } + + //26.04.08 NDY 추가 _AxisX 가져오기 + try { _AxisX = context.Devices[CommonDeviceIds.AxisX2] as ACSMotor; } + catch { _AxisX = null; Log.W("AxisX2 취득 실패"); } } private bool CheckDeviceReady(SequenceContext context) { @@ -401,12 +492,30 @@ namespace ILSOS_PrismaticScanner.Sequences SlotNo = 1; // 결과 Data 를 업데이트 함. var power = Status.GetProcessingWeldingData().UploadProcessDatas.Where(data => data.DataName == $"Power_{SlotNo}_{_SequenceSetting.LastPageNo}").FirstOrDefault(); - power.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1 + ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2; - var velocity = Status.GetProcessingWeldingData().UploadProcessDatas.Where(data => data.DataName == $"Velocity_{SlotNo}_{_SequenceSetting.LastPageNo}").FirstOrDefault(); - velocity.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].MarkSpeed; - // FDC 데이터 상신 - _plc.UploadReportDatas(Status.GetProcessingWeldingData().UploadProcessDatas); + #region 26.04.08 NDY 캘리브레이션 노드 추가 테스트를 위해서 잠시 예외처리 코드 추가 + if (power != null) + power.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1 + + ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2; + #endregion + // 26.04.08 NDY 주석처리 - power null 예외 방지 (위 null 체크로 대체) + //power.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1 + ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2; + + + var velocity = Status.GetProcessingWeldingData().UploadProcessDatas.Where(data => data.DataName == $"Velocity_{SlotNo}_{_SequenceSetting.LastPageNo}").FirstOrDefault(); + #region 26.04.08 NDY velocity null에 대한 예외 처리 + if (velocity != null) + velocity.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].MarkSpeed; + #endregion + // 26.04.08 NDY 주석처리 - velocity null 예외 방지 (위 null 체크로 대체) + //velocity.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].MarkSpeed; + + + // 26.04.08 NDY - FDC 데이터 상신 -기존 코드 주석처리 + //_plc.UploadReportDatas(Status.GetProcessingWeldingData().UploadProcessDatas); + // 26.04.08 NDY - FDC 상신도 데이터 있을 때만 - 테스트 목적 예외 처리 추가 + if (Status.GetProcessingWeldingData().UploadProcessDatas.Count > 0) + _plc.UploadReportDatas(Status.GetProcessingWeldingData().UploadProcessDatas); _CenterBeamPower = (int)ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1; _RingBeamPower = (int)ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2; diff --git a/WeldingComponents/WeldingCommon/Sequences/Manual/SeqTeachingRun.cs b/WeldingComponents/WeldingCommon/Sequences/Manual/SeqTeachingRun.cs index d6de800..5955440 100644 --- a/WeldingComponents/WeldingCommon/Sequences/Manual/SeqTeachingRun.cs +++ b/WeldingComponents/WeldingCommon/Sequences/Manual/SeqTeachingRun.cs @@ -1,9 +1,13 @@ using Aurora.Api; +using Aurora.Api.Devices; using Aurora.Api.Services; +// 26.04.08 NDY 추가 - 비전 있는 오토 티칭 버튼은 MIL없어서 리스트만으로 테스트 시퀸스 확인하고자 추가 예정 +using AuroraACS; using AuroraIO; using AuroraLaserScanner; using AuroraLBAD; using AuroraLBAD.Services; +using AuroraMotionBoard.Ajin; using AuroraOCT; using CoreUnit.Control.UserControl.Canvas; using CoreUnit.Scanner.UserControl.ScannerCanvas; @@ -52,6 +56,12 @@ namespace WeldingCommon.Sequences const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqTeachingRun] Write Completion PLC Bit"; const string SEQ_COMPLETE = "[SeqTeachingRun] SEQ_COMPLETE"; // 완료 + #region 26.04.08 NDY 상수 추가 + const string SEQ_MOVE_STAGE_ORIGIN = "[SeqTeachingRun] Move Stage To Origin"; + const string SEQ_ENCODER_RESET = "[SeqTeachingRun] Encoder Reset"; + + #endregion + static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqTeachingRun"; @@ -64,6 +74,7 @@ namespace WeldingCommon.Sequences private OCT _OCT; private IODevice _IO; private StreamLBADClient _StreamLBADClient; + private ACSMotor _AxisX; // ← 26.04.08 NDY 필드 추가 private SystemParameter _SystemParameter; private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언 @@ -73,6 +84,9 @@ namespace WeldingCommon.Sequences private static TimeSpan _WeldingSpanTime; //TeacingRun 시퀀스에서 용접 소요시간 + + + public SequenceBuilder Builder() { var sb = new SequenceBuilder(1000, true); @@ -81,6 +95,12 @@ namespace WeldingCommon.Sequences sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 + #region 26.04.08 NDY 노드 추가 + sb.AddAction(SEQ_MOVE_STAGE_ORIGIN, MoveStageToOrigin); + sb.AddAction(SEQ_ENCODER_RESET, EncoderReset); + #endregion + + 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); @@ -95,12 +115,23 @@ namespace WeldingCommon.Sequences sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write sb.AddAction(SEQ_COMPLETE, Complete); + #region 기존 흐름 26.04.08 주석처리 + //sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] + // > 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_SET_BLOW_ON] > sb[SEQ_STREAM_LBAD_BEFORE_WELDLINES] > sb[SEQ_EXECUTE_WELDLINES] + // > sb[SEQ_SET_BLOW_OFF] > sb[SEQ_STREAM_LBAD_AFTER_WELDLINES] + // > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); + #endregion + #region 2개 노드 추가 흐름 26.04.08 - Test 중 sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] + > sb[SEQ_MOVE_STAGE_ORIGIN] // ← 추가 + > sb[SEQ_ENCODER_RESET] // ← 추가 > 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_SET_BLOW_ON] > sb[SEQ_STREAM_LBAD_BEFORE_WELDLINES] > sb[SEQ_EXECUTE_WELDLINES] > sb[SEQ_SET_BLOW_OFF] > sb[SEQ_STREAM_LBAD_AFTER_WELDLINES] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); + #endregion sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final); @@ -112,6 +143,64 @@ namespace WeldingCommon.Sequences return sb; } + #region 26.04.08 NDY 메서드 추가 + private SequenceActionResult EncoderReset(SequenceContext context, string id, SequenceActionResult param) + { + if (_AxisX == null) + { + Log.W("[EncoderReset] AxisX2 null - 스킵"); + return SequenceAction.Ok(); + } + + if (!_Scanner.Config.UseMarkingOnTheFly) + { + Log.W("[EncoderReset] MOTF 비활성화 - 스킵"); + return SequenceAction.Ok(); + } + + Log.I("[EncoderReset] 시작"); + + _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(); + } + + private SequenceActionResult MoveStageToOrigin(SequenceContext context, string id, SequenceActionResult param) + { + if (_AxisX == null) + { + Log.W("[MoveStageToOrigin] AxisX2 null - 스킵"); + return SequenceAction.Ok(); + } + + Log.I("[MoveStageToOrigin] Stage X → 0 이동 시작"); + + _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(); + + var res = context.RetryUntilSuccess( + () => _AxisX.IsReachedTargetPosition(0), + 30 * 1000, 20, true); + + if (res == E2.TIMEOUT) { Log.E("[MoveStageToOrigin] TIMEOUT"); return null; } + if (res == E2.CANCELLED) { Log.E("[MoveStageToOrigin] CANCELLED"); return null; } + + Log.I("[MoveStageToOrigin] Stage X = 0 도달 완료"); + return SequenceAction.Ok(); + } + #endregion private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { @@ -180,6 +269,14 @@ namespace WeldingCommon.Sequences // return SequenceAction.Error(); //} + + #region 26.04.08 NDY 수정 예외처리를 위해서 + + // ↓ 추가 + try { _AxisX = context.Devices[CommonDeviceIds.AxisX2] as ACSMotor; } + catch { _AxisX = null; Log.W("[SeqTeachingRun] AxisX2 취득 실패"); } + #endregion + } private bool CheckDeviceReady(SequenceContext context)