diff --git a/Machines/ILSOS_PrismaticRD_PTOP/Alarm/AlarmCode_PTOP.cs b/Machines/ILSOS_PrismaticRD_PTOP/Alarm/AlarmCode_PTOP.cs index 9bcbff2..259e158 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/Alarm/AlarmCode_PTOP.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/Alarm/AlarmCode_PTOP.cs @@ -23,5 +23,7 @@ namespace ILSOS_PrismaticRD_PTOP.Alarm public const int ALARM_DEVICE_IO_FanAlarm4 = 210612; public const int ALARM_DEVICE_IO_FanAlarm5 = 210613; public const int ALARM_DEVICE_IO_FanAlarm6 = 210614; + + public const int ALARM_LASER_HEAD_THETA_INTERLOCK = 210620; } } diff --git a/Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs b/Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs index 274bc26..a9e53a1 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs @@ -91,7 +91,7 @@ namespace ILSOS_PrismaticRD_PTOP.Device EMPTY_07, EMPTY_08, EMPTY_09, - EMPTY_10, + HEAD_THETA_POSITION, // D70510 (Laser1 Head Theta), index 10 EMPTY_11, EMPTY_12, EMPTY_13, diff --git a/Machines/ILSOS_PrismaticRD_PTOP/EquipDef.cs b/Machines/ILSOS_PrismaticRD_PTOP/EquipDef.cs index 01f1853..650dc81 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/EquipDef.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/EquipDef.cs @@ -29,6 +29,11 @@ namespace ILSOS_PrismaticRD_PTOP } + internal class SettingIds : CommonSettingIds + { + public const string LaserInterlock = "LaserInterlock"; + } + public class StreamMessageNames { public const string MESSAGE_NAME_STRING = "MessageNameString"; diff --git a/Machines/ILSOS_PrismaticRD_PTOP/EquipmentSetup.cs b/Machines/ILSOS_PrismaticRD_PTOP/EquipmentSetup.cs index 044cb97..b5f9438 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/EquipmentSetup.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/EquipmentSetup.cs @@ -224,6 +224,7 @@ namespace ILSOS_PrismaticRD_PTOP base.RegisterSettings(register); register(CommonSettingIds.UploadDatas, new SettingUploadDataListForPTOP()); + register(SettingIds.LaserInterlock, new LaserInterlockSetting()); } public override void RegisterServices(IServiceRegistry register) diff --git a/Machines/ILSOS_PrismaticRD_PTOP/ILSOS_PrismaticRD_PTOP.csproj b/Machines/ILSOS_PrismaticRD_PTOP/ILSOS_PrismaticRD_PTOP.csproj index 9107b93..79bba3b 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/ILSOS_PrismaticRD_PTOP.csproj +++ b/Machines/ILSOS_PrismaticRD_PTOP/ILSOS_PrismaticRD_PTOP.csproj @@ -118,6 +118,7 @@ + UCMainAutoRun.xaml diff --git a/Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs b/Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs index 5f91676..9affe59 100644 --- a/Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs +++ b/Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs @@ -18,6 +18,9 @@ using WeldingCommon.Devices; using WeldingCommon.Devices.Laser; using WeldingCommon.Sequences; using WeldingCommon.Utils; +using WeldingCommon.Alarm; +using ILSOS_PrismaticRD_PTOP.Alarm; +using ILSOS_PrismaticRD_PTOP.Settings; using static AuroraIO.AJINEXTEK.AjinIO.IOModuleInfo; using static ILSOS_PrismaticRD_PTOP.Device.PLCControllerPTOP; using static WeldingCommon.Devices.PLCController; @@ -721,6 +724,38 @@ namespace ILSOS_PrismaticRD_PTOP.Sequences Status.SetWorkingPosition(eWorkingPosition.EXECUTING_WELD); // 현재 시퀸스 위치 + // === Head Theta 인터락: 수평/수직(±tol)에서만 발진 허용 (체크박스 사용 시) === + var thetaSetting = Application.Current.AuroraEnv().SettingEntry[SettingIds.LaserInterlock] as LaserInterlockSetting; + if (thetaSetting != null && thetaSetting.HeadThetaInterlockEnabled) + { + bool blocked = false; + if (_PLC == null || !_PLC.IsActivated) + { + Log.W("[ExecuteWelding] HeadTheta 인터락 - PLC 미연결/미활성 → 발진 차단"); + blocked = true; // fail-closed + } + else + { + short thetaRaw = _PLC.ReadWord(eWordInput.HEAD_THETA_POSITION).data; + double scale = thetaSetting.HeadThetaPlcScale != 0 ? thetaSetting.HeadThetaPlcScale : 1; // 0 가드 + double thetaDeg = thetaRaw / scale; + bool okH = Math.Abs(thetaDeg - thetaSetting.HeadThetaHorizontal) <= thetaSetting.HeadThetaTolerance; + bool okV = Math.Abs(thetaDeg - thetaSetting.HeadThetaVertical) <= thetaSetting.HeadThetaTolerance; + Log.I($"[ExecuteWelding] HeadTheta raw={thetaRaw}, deg={thetaDeg:F1} (H={thetaSetting.HeadThetaHorizontal}/V={thetaSetting.HeadThetaVertical}/±{thetaSetting.HeadThetaTolerance})"); + if (!okH && !okV) + { + Log.W($"[ExecuteWelding] HeadTheta 인터락 → 수평/수직 ±{thetaSetting.HeadThetaTolerance}° 벗어남(deg={thetaDeg:F1}) → 발진 차단"); + blocked = true; + } + } + if (blocked) + { + try { AlarmManager.Alarm(AlarmCode_PTOP.ALARM_LASER_HEAD_THETA_INTERLOCK); } + catch (Exception ex) { Log.E($"[ExecuteWelding] HeadTheta 알람 표시 실패(테이블 미등록?): {ex.Message}"); } + return null; // 발진 차단 + 시퀀스 중단 + } + } + _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePrismaticDOAddress.CoreLaser_Control), true); _IO._iOUnit.WriteDoBit(Convert.ToInt32(ePrismaticDOAddress.RingLaser_Control), true); Log.I($"[ExecuteWelding] Laser Gate ON (Core+Ring)"); diff --git a/Machines/ILSOS_PrismaticRD_PTOP/Settings/LaserInterlockSetting.cs b/Machines/ILSOS_PrismaticRD_PTOP/Settings/LaserInterlockSetting.cs new file mode 100644 index 0000000..c5c0285 --- /dev/null +++ b/Machines/ILSOS_PrismaticRD_PTOP/Settings/LaserInterlockSetting.cs @@ -0,0 +1,41 @@ +using Aurora.Api; +using PropertyTools.DataAnnotations; + +namespace ILSOS_PrismaticRD_PTOP.Settings +{ + // Laser 발진 인터락 세팅 (세팅 메뉴에 PropertyGrid로 자동 노출) + public class LaserInterlockSetting : ISettingItem + { + // 체크 시 인터락 동작, 해제 시 미동작 (기본 false: 설정·검증 후 사용) + [Browsable(true)] + [ReadOnly(false)] + [Category("Head Theta Interlock")] + [DisplayName("인터락 사용")] + public bool HeadThetaInterlockEnabled { get; set; } = false; + + [Browsable(true)] + [ReadOnly(false)] + [Category("Head Theta Interlock")] + [DisplayName("수평 각도(deg)")] + public double HeadThetaHorizontal { get; set; } = 0; + + [Browsable(true)] + [ReadOnly(false)] + [Category("Head Theta Interlock")] + [DisplayName("수직 각도(deg)")] + public double HeadThetaVertical { get; set; } = 90; + + [Browsable(true)] + [ReadOnly(false)] + [Category("Head Theta Interlock")] + [DisplayName("허용 오차(±deg)")] + public double HeadThetaTolerance { get; set; } = 2.5; + + // PLC Head_Theta_Position 스케일. deg×10 가정(미확정) → 실값 확인 후 조정. + [Browsable(true)] + [ReadOnly(false)] + [Category("Head Theta Interlock")] + [DisplayName("PLC 스케일(deg×?)")] + public double HeadThetaPlcScale { get; set; } = 10; + } +}