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;
+ }
+}