// WeldingCommon/Devices/ACS/ScannerACS.cs // Gun(PrismaticGunACS.cs) 기반으로 Scanner용으로 통합 // 변경점: // 1. 네임스페이스/클래스명 변경 (PrismaticGunACS → ScannerACS) // 2. MOTF 메서드 3개 추가 (MOTFStart/Stop/CheckMOTFComp) // 3. 모터 취득 try-catch null-safe 적용 // 4. TeachingPosition 체크 로직 단순화 (Scanner는 X2축만 사용) // 26.04.06 NDY using Aurora; using Aurora.Api; using Aurora.Api.Devices; using AuroraACS; using ACS.SPiiPlusNET; using Hermes; using System.Windows; using WeldingCommon.Settings; using AuroraOCT; using WeldingCommon.Device.ACS; namespace WeldingCommon.Devices.ACS { // ── 인터페이스 ──────────────────────────────────────────────────────────── // Gun의 IPrismaticGunACS 기반 + MOTF 3개 추가 public interface IScannerACS { bool IsActivated(); // 홈 bool AllAxisHomeStart(); bool AllAxisHomeStop(); bool CheckAllAxisHome(); // MOTF (Scanner 전용 추가 - Gun에 없음) // TODO: 이정인 선임 변수 맵 수신 후 주석 해제하여 사용 bool MOTFStart(); bool MOTFStop(); bool CheckMOTFComp(); // OneShot (Gun과 동일) bool SetOneShot(int msecShotTime, double secPhzShotPulse1, double secPhzShotPulse2); bool OneShotStart(); bool OneShotStop(); bool CheckOneShotComp(); // LineShot (Gun과 동일) bool SetLineShot(double corePower, double ringPower, double startPosX, double endPosX, double startPosY, double endPosY, double velocity, double acc); bool LineShotStart(); bool LineShotStop(); bool CheckLineShotComp(); // Welding (Gun과 동일) bool SetWeldingVel(double acc, double svel, double cvel); bool SetWeldingPos(double startPosX, double startPosY, double endPosX, double endPosY, double camOffsetX, double camOffsetY); bool SetWeldingArc(double point1, double point2, double point3, double point4); bool SetWeldingType(eOutType type); bool SetWeldingPulse(double coreMaxPower, double coreMinPower, double ringMaxPower, double ringMinPower); bool SetLaserOnOff(double onPosX, double onOffSet, double offPosX, double offOffSet, double camOffsetX, double camOffsetY); bool SetRamppingOffParameter(double pos, double overlap, double endpower, double camOffsetX, double camOffsetY); bool SetRamppingOnParameter(double overlap, double startpower); bool WeldingStart(); bool WeldingStop(); bool CheckWeldingComp(); // Teaching Position (Gun과 동일) bool SetWeldingTeachingPosition1(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition2(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition3(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition4(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition5(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition6(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition7(double PosX, double PosY, double camOffsetX, double camOffsetY); bool SetWeldingTeachingPosition8(double PosX, double PosY, double camOffsetX, double camOffsetY); // 레이저 (Gun과 동일) bool SetLaserIOUse(bool on); bool SetLCILserOn(bool on); bool SetWeldingAxes(int axisXnum, int axisYnum); bool IsLaserOn(); // 알람 (Gun과 동일) bool ResetAlarm(); void AllAxisServoOff(); } // ── 구현 ────────────────────────────────────────────────────────────────── public partial class ScannerACS : ACSDevice, IScannerACS { // Gun과 동일한 필드 private ACSDeviceSetting _setting; // Scanner는 Stage X (X2) 1축만 사용 // Gun은 X1, X2, Y1, Y2, Z 5축 사용 private ACSMotor MotorStageX; // AxisX2 = Scanner Stage X public MotionVariable _motorVariable; public bool HasHeavyAlarm { get; private set; } public bool HasLightAlarm { get; private set; } public int[] HaveAlarmCodes { get => _HaveAlarmCodes; } private int[] _HaveAlarmCodes = new int[11]; public ScannerACS(bool isSimulation, bool useTerminateUMD = false) : base(isSimulation, useTerminateUMD) { _motorVariable = new MotionVariable(); } protected override int DoActivate(IDeviceConfig config) { if (base.DoActivate(config) != E1.OK) return E2.ABORTED; var env = Application.Current.AuroraEnv(); // TODO: Scanner용 SettingIds 확정 후 교체 // Gun: _setting = env.SettingEntry[SettingIds.ACS] as ACSDeviceSetting; // _setting = env.SettingEntry[ScannerSettingIds.ACS] as ACSDeviceSetting; // Scanner는 Stage X (X2) 1축만 취득 // Gun은 X1, X2, Y1, Y2, Z 전부 취득 // null-safe: 변수 맵 수신 전 예외 방지 // TODO: 이정인 선임 변수 맵 수신 후 축 번호 검증 try { MotorStageX = env.DeviceManager[CommonDeviceIds.AxisX2] as ACSMotor; } catch { MotorStageX = null; } SetMonitoringService(UpdateACSParam, 50); StartMonitoringService(); return E1.OK; } private void UpdateACSParam() { // Scanner는 Stage X만 모니터링 // Gun은 X1, X2, Y1, Y2, Z 전부 모니터링 if (MotorStageX != null) { _motorVariable.X2AxisPosition = MotorStageX.GetActualPos(); _motorVariable.X2InPosition = MotorStageX.IsInpos(); _motorVariable.X2AxisVelocity = MotorStageX.GetFeedbackVelocity(); _motorVariable.X2AxisAcceleration = MotorStageX.GetAcceleration(); _motorVariable.IsHome = MotorStageX.GetServoStatus() == 1; } // 알람 상태 갱신 (Gun과 동일) HasHeavyAlarm = ReadVariableInt(HeavyAlarm) == 1; HasLightAlarm = ReadVariableInt(LightAlarm) == 1; ReadVariableIntArrRef(AlarmCodes, ref _HaveAlarmCodes, ProgramBuffer.ACSC_NONE, 0, 10); } protected override int DoDeactivate() { StopMonitoringService(); return base.DoDeactivate(); } // ── 홈 (Gun과 동일) ─────────────────────────────────────────────────── bool IScannerACS.AllAxisHomeStart() { if (RunBuffer((ProgramBuffer)eBuffer.All_Axis_Home)) { Log.D("AllAxisHomeStart >> Complete"); return true; } Log.D("AllAxisHomeStart >> Fail"); return false; } bool IScannerACS.AllAxisHomeStop() { StopBuffer((ProgramBuffer)eBuffer.All_Axis_Home); Log.D("AllAxisHomeStop >> Complete"); return true; } bool IScannerACS.CheckAllAxisHome() => ReadVariableInt(iAllAxisHomeComplete) > 0; // ── MOTF (Scanner 전용 추가 - Gun에 없음) ──────────────────────────── // TODO: 이정인 선임 변수 맵 수신 후 버퍼 번호 및 변수명 교체 bool IScannerACS.MOTFStart() { if (IsSimul) return true; if (RunBuffer((ProgramBuffer)eBuffer.MOTF_Start)) { Log.I("MOTFStart >> Complete"); return true; } Log.D("MOTFStart >> Fail"); return false; } bool IScannerACS.MOTFStop() { StopBuffer((ProgramBuffer)eBuffer.MOTF_Start); Log.D("MOTFStop >> Complete"); return true; } bool IScannerACS.CheckMOTFComp() { if (IsSimul) return true; return ReadVariableInt(iMOTFComplete) > 0; } // ── OneShot (Gun과 동일) ────────────────────────────────────────────── bool IScannerACS.SetOneShot(int msecShotTime, double secPhzShotPulse1, double secPhzShotPulse2) { if (WriteRealVariable(rOneShotTime, msecShotTime) & WriteRealVariable(rOneShotCoreVoltage, secPhzShotPulse1) & WriteRealVariable(rOneShotRingVoltage, secPhzShotPulse2)) { Log.D("SetOneShot >> Complete"); return true; } Log.D("SetOneShot >> Fail"); return false; } bool IScannerACS.OneShotStart() { if (RunBuffer((ProgramBuffer)eBuffer.Welding_OneShot)) { Log.D("OneShotStart >> Complete"); return true; } Log.D("OneShotStart >> Fail"); return false; } bool IScannerACS.OneShotStop() { IScannerACS motion = this; motion.SetLCILserOn(false); StopBuffer((ProgramBuffer)eBuffer.Welding_OneShot); Log.D("OneShotStop >> Complete"); return true; } bool IScannerACS.CheckOneShotComp() => ReadVariableInt(iOneShotComplete) > 0; // ── LineShot (Gun과 동일) ───────────────────────────────────────────── bool IScannerACS.SetLineShot(double corePower, double ringPower, double startPosX, double endPosX, double startPosY, double endPosY, double velocity, double acc) { if (WriteRealVariable(rLineWeldingLaserOnX, startPosX) & WriteRealVariable(rLineWeldingLaserOnY, startPosY) & WriteRealVariable(rLineWeldingLaserOffX, endPosX) & WriteRealVariable(rLineWeldingLaserOffY, endPosY) & WriteRealVariable(rLineWeldingVel, velocity) & WriteRealVariable(rLineWeldingAcc, acc) & WriteRealVariable(rLineWeldingCoreVoltage, corePower) & WriteRealVariable(rLineWeldingRingVoltage, ringPower)) { Log.D("SetLineShot >> Complete"); return true; } Log.D("SetLineShot >> Fail"); return false; } bool IScannerACS.LineShotStart() { if (RunBuffer((ProgramBuffer)eBuffer.Welding_Line)) { Log.D("LineShotStart >> Complete"); return true; } Log.D("LineShotStart >> Fail"); return false; } bool IScannerACS.LineShotStop() { IScannerACS motion = this; motion.SetLCILserOn(false); StopBuffer((ProgramBuffer)eBuffer.Welding_Line); Log.D("LineShotStop >> Complete"); return true; } bool IScannerACS.CheckLineShotComp() => ReadVariableInt(iLineWeldingComplete) > 0; // ── Welding (Gun과 동일) ────────────────────────────────────────────── bool IScannerACS.WeldingStart() { if (IsSimul) return true; if (RunBuffer((ProgramBuffer)eBuffer.Welding_AllRound)) { Log.I("WeldingStart >> Complete"); return true; } Log.D("WeldingStart >> Fail"); return false; } bool IScannerACS.WeldingStop() { IScannerACS motion = this; motion.SetLCILserOn(false); StopBuffer((ProgramBuffer)eBuffer.Welding_AllRound); Log.D("WeldingStop >> Complete"); return true; } bool IScannerACS.CheckWeldingComp() { if (IsSimul) return true; return ReadVariableInt(iWeldingComplete) > 0; } bool IScannerACS.SetWeldingVel(double acc, double svel, double cvel) { if (WriteRealVariable(rWeldingAcc, acc) & WriteRealVariable(rWeldingSVel, svel) & WriteRealVariable(rWeldingCVel, cvel)) { Log.D("SetWeldingVel >> Complete"); return true; } Log.D("SetWeldingVel >> Fail"); return false; } bool IScannerACS.SetWeldingPos(double startPosX, double startPosY, double endPosX, double endPosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingStartPosX, startPosX + camOffsetX) & WriteRealVariable(rWeldingStartPosY, startPosY + camOffsetY) & WriteRealVariable(rWeldingEndPosX, endPosX + camOffsetX) & WriteRealVariable(rWeldingEndPosY, endPosY + camOffsetY)) { Log.D("SetWeldingPos >> Complete"); return true; } Log.D("SetWeldingPos >> Fail"); return false; } bool IScannerACS.SetWeldingArc(double point1, double point2, double point3, double point4) { if (WriteRealVariable(rWeldingEdgePointRad1, point1) & WriteRealVariable(rWeldingEdgePointRad2, point2) & WriteRealVariable(rWeldingEdgePointRad3, point3) & WriteRealVariable(rWeldingEdgePointRad4, point4)) { Log.D("SetWeldingArc >> Complete"); return true; } Log.D("SetWeldingArc >> Fail"); return false; } bool IScannerACS.SetWeldingType(eOutType type) { if (WriteVariableInt(iALaserShotMode, (int)type)) { Log.D("SetWeldingType >> Complete"); return true; } Log.D("SetWeldingType >> Fail"); return false; } bool IScannerACS.SetWeldingPulse(double coreMaxPower, double coreMinPower, double ringMaxPower, double ringMinPower) { if (WriteRealVariable(rWeldingCorePowerMax, coreMaxPower) & WriteRealVariable(rWeldingCorePowerMin, coreMinPower) & WriteRealVariable(rWeldingRingPowerMax, ringMaxPower) & WriteRealVariable(rWeldingRingPowerMin, ringMinPower)) { Log.D("SetWeldingPulse >> Complete"); return true; } Log.D("SetWeldingPulse >> Fail"); return false; } bool IScannerACS.SetLaserOnOff(double onPosX, double onOffSet, double offPosX, double offOffSet, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rLaserONPosX, onPosX + camOffsetX) & WriteRealVariable(rLaserONOffset, onOffSet) & WriteRealVariable(rLaserOFFPosX, offPosX + camOffsetX) & WriteRealVariable(rLaserOFFOffset, offOffSet)) { Log.D("SetLaserOnOff >> Complete"); return true; } Log.D("SetLaserOnOff >> Fail"); return false; } bool IScannerACS.SetRamppingOffParameter(double pos, double overlap, double endpower, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rRampingOFFStartPosX, pos + camOffsetX) & WriteRealVariable(rRampingOFFOverlapDist, overlap) & WriteRealVariable(rRampingOFFEndPower, endpower)) { Log.D("SetRamppingOffParameter >> Complete"); return true; } Log.D("SetRamppingOffParameter >> Fail"); return false; } bool IScannerACS.SetRamppingOnParameter(double overlap, double startpower) { if (WriteRealVariable(rRampingONOverlapDist, overlap) & WriteRealVariable(rRampingONStartPower, startpower)) { Log.D("SetRamppingOnParameter >> Complete"); return true; } Log.D("SetRamppingOnParameter >> Fail"); return false; } // ── Teaching Position (Gun과 동일) ──────────────────────────────────── bool IScannerACS.SetWeldingTeachingPosition1(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition1PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition1PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition1 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition1 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition2(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition2PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition2PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition2 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition2 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition3(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition3PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition3PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition3 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition3 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition4(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition4PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition4PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition4 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition4 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition5(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition5PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition5PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition5 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition5 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition6(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition6PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition6PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition6 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition6 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition7(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition7PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition7PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition7 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition7 >> Fail"); return false; } bool IScannerACS.SetWeldingTeachingPosition8(double PosX, double PosY, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rWeldingPosition8PosX, PosX + camOffsetX) & WriteRealVariable(rWeldingPosition8PosY, PosY + camOffsetY)) { Log.D($"SetWeldingTeachingPosition8 ({PosX}/{PosY}) >> Complete"); return true; } Log.D("SetWeldingTeachingPosition8 >> Fail"); return false; } // ── 레이저 (Gun과 동일) ─────────────────────────────────────────────── bool IScannerACS.SetLaserIOUse(bool on) { if (WriteRealVariable(iLaserUse, on ? 1 : 0)) { Log.D($"SetLaserIOUse {on} >> Complete"); return true; } Log.D("SetLaserIOUse >> Fail"); return false; } bool IScannerACS.SetLCILserOn(bool on) { if (WriteRealVariable(iAStageLCType, on ? 1 : 0)) { Log.D($"SetLCILserOn {on} >> Complete"); return true; } Log.D("SetLCILserOn >> Fail"); return false; } bool IScannerACS.SetWeldingAxes(int axisXnum, int axisYnum) { if (WriteVariableInt(iXAxisNumber, axisXnum) & WriteVariableInt(iYAxisNumber, axisYnum)) { Log.D("SetWeldingAxes >> Complete"); return true; } Log.D("SetWeldingAxes >> Fail"); return false; } bool IScannerACS.IsLaserOn() { if (!IsActivated || !IsConnected) return false; return ReadVariableInt(IsLaserOn) > 0; } // ── 알람 (Gun과 동일) ───────────────────────────────────────────────── bool IScannerACS.ResetAlarm() { TerminalCommand("FCLEAR ALL"); return WriteVariableInt(AlarmReset, 1); } void IScannerACS.AllAxisServoOff() { if (!IsActivated || !IsConnected) return; SetMotorDisableAll(); } bool IScannerACS.IsActivated() => IsActivated; } }