// WeldingCommon/Devices/ACS/ScannerACS.cs // Gun(PrismaticGunACS.cs) 기반으로 Scanner용으로 통합 // 변경점: // 1. 네임스페이스/클래스명 변경 (PrismaticGunACS → ScannerACS) // 2. MOTF 메서드 3개 추가 (MOTFStart/Stop/CheckMOTFComp) // 3. MOTF 파라미터 세팅 메서드 추가 (SetMOTFParams) // 4. 모터 취득 try-catch null-safe 적용 // 5. TeachingPosition 체크 로직 단순화 (Scanner는 X2축만 사용) // 6. xlsx 글로벌 변수 맵 기준 미사용 변수 제거 // - iAStageLCType (iPCset_ALINE_LCTYPE) → SetLCILserOn stub 처리 // - iALaserShotMode (iPCset_ALASER_SHOT_MODE) → SetWeldingType stub 처리 // - rLaserONOffset / rLaserOFFPosX / rLaserOFFOffset → SetLaserOnOff에서 제거 // 26.04.06 NDY 최초 작성 // 26.04.09 NDY xlsx 글로벌 변수 맵 기준 미사용 변수 정리, SetMOTFParams 추가 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 { // ── 인터페이스 ──────────────────────────────────────────────────────────── public interface IScannerACS { bool IsActivated(); // 홈 bool AllAxisHomeStart(); bool AllAxisHomeStop(); bool CheckAllAxisHome(); // MOTF (Scanner 전용 - Gun에 없음) bool SetMOTFParams(double posX, double negX, double velocity, double acc, int interval); bool MOTFStart(); bool MOTFStop(); bool CheckMOTFComp(); bool ResetMOTFComp(); // ← 여기에 추가 BUFFER 17에서 완료에 대한 플래그 리셋 0 으로 하는 것 260417 // OneShot bool SetOneShot(int msecShotTime, double secPhzShotPulse1, double secPhzShotPulse2); bool OneShotStart(); bool OneShotStop(); bool CheckOneShotComp(); // LineShot 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 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 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); // 레이저 bool SetLaserIOUse(bool on); bool SetLCILserOn(bool on); bool SetWeldingAxes(int axisXnum, int axisYnum); bool IsLaserOn(); // 알람 bool ResetAlarm(); void AllAxisServoOff(); } // ── 구현 ────────────────────────────────────────────────────────────────── public partial class ScannerACS : ACSDevice, IScannerACS { //IsReachedTeachingPosition private ACSDeviceSetting _setting; // Scanner는 Stage X (X2) 1축만 사용 | Z 축까지 사용 스캐너 높이 // Gun은 X1, X2, Y1, Y2, Z 5축 사용 private ACSMotor MotorStageX; // AxisX2 = Scanner Stage X private ACSMotor MotorStageZ; // 26.04.14 = AxisZ 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 확정 후 교체 // _setting = env.SettingEntry[ScannerSettingIds.ACS] as ACSDeviceSetting; // Scanner는 Stage X (X2) 1축만 취득 // null-safe: 변수 맵 수신 전 예외 방지 // TODO: 이정인 선임 변수 맵 수신 후 축 번호 검증 try { MotorStageX = env.DeviceManager[CommonDeviceIds.AxisX2] as ACSMotor; } catch { MotorStageX = null; } try { MotorStageZ = env.DeviceManager[CommonDeviceIds.AxisZ] as ACSMotor; } catch { MotorStageZ = null; } SetMonitoringService(UpdateACSParam, 50); StartMonitoringService(); return E1.OK; } private void UpdateACSParam() { // Scanner는 Stage X만 모니터링 if (MotorStageX != null) { _motorVariable.X2AxisPosition = MotorStageX.GetActualPos(); _motorVariable.X2InPosition = MotorStageX.IsInpos(); _motorVariable.X2AxisVelocity = MotorStageX.GetFeedbackVelocity(); _motorVariable.X2AxisAcceleration = MotorStageX.GetAcceleration(); _motorVariable.IsHome |= MotorStageX.GetServoStatus() == 1; } if (MotorStageZ != null) { _motorVariable.ZAxisPosition = MotorStageZ.GetActualPos(); _motorVariable.ZInPosition = MotorStageZ.IsInpos(); _motorVariable.ZAxisVelocity = MotorStageZ.GetFeedbackVelocity(); _motorVariable.ZAxisAcceleration = MotorStageZ.GetAcceleration(); _motorVariable.IsHome |= MotorStageZ.GetServoStatus() == 1; } // 알람 상태 갱신 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(); } // ── 홈 ─────────────────────────────────────────────────────────────── 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에 없음) ───────────────────────────────── // 26.04.09 NDY SetMOTFParams 추가 — xlsx 글로벌 변수 맵 기준 확정 bool IScannerACS.SetMOTFParams(double posX, double negX, double velocity, double acc, int interval) { if (WriteRealVariable(rMOTFPosX, posX) & WriteRealVariable(rMOTFNegX, negX) & WriteRealVariable(rMOTFVelocity, velocity) & WriteRealVariable(rMOTFAcc, acc) & WriteVariableInt(iMOTFInterval, interval)) { Log.I($"SetMOTFParams >> Complete | PosX:{posX} NegX:{negX} " + $"Vel:{velocity} Acc:{acc} Interval:{interval}ms"); return true; } Log.E("SetMOTFParams >> Fail"); return false; } // TODO: 이정인 선임 변수 맵 수신 후 버퍼 번호 및 완료 변수명 검증 bool IScannerACS.MOTFStart() { if (IsSimul) return true; if (RunBuffer((ProgramBuffer)eBuffer.MOTF_Start)) { Log.I("MOTFStart >> Complete"); return true; } Log.E("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; } // 260417여기 추가 bool IScannerACS.ResetMOTFComp() { if (IsSimul) return true; if (WriteVariableInt(iMOTFComplete, 0)) { Log.I("ResetMOTFComp >> Complete (iPCset_MOF_WEL_COMP = 0)"); return true; } Log.E("ResetMOTFComp >> Fail"); return false; } // ── OneShot ────────────────────────────────────────────────────────── 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 acs = this; acs.SetLCILserOn(false); StopBuffer((ProgramBuffer)eBuffer.Welding_OneShot); Log.D("OneShotStop >> Complete"); return true; } bool IScannerACS.CheckOneShotComp() => ReadVariableInt(iOneShotComplete) > 0; // ── LineShot ───────────────────────────────────────────────────────── 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 acs = this; acs.SetLCILserOn(false); StopBuffer((ProgramBuffer)eBuffer.Welding_Line); Log.D("LineShotStop >> Complete"); return true; } bool IScannerACS.CheckLineShotComp() => ReadVariableInt(iLineWeldingComplete) > 0; // ── Welding ────────────────────────────────────────────────────────── 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 acs = this; acs.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; } // 26.04.09 NDY iPCset_ALASER_SHOT_MODE — Scanner xlsx 기준 미사용 bool IScannerACS.SetWeldingType(eOutType type) { Log.D("SetWeldingType >> Not Used in Scanner"); return true; } 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; } // 26.04.09 NDY rLaserONOffset / rLaserOFFPosX / rLaserOFFOffset — xlsx 미사용 제거 // rLaserONPosX (rPCset_ALINE_LASER_ONPOS_X) 만 유효 bool IScannerACS.SetLaserOnOff(double onPosX, double onOffSet, double offPosX, double offOffSet, double camOffsetX, double camOffsetY) { if (WriteRealVariable(rLaserONPosX, onPosX + camOffsetX)) { 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 ───────────────────────────────────────────────── 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; } // ── 레이저 ─────────────────────────────────────────────────────────── bool IScannerACS.SetLaserIOUse(bool on) { if (WriteRealVariable(iLaserUse, on ? 1 : 0)) { Log.D($"SetLaserIOUse {on} >> Complete"); return true; } Log.D("SetLaserIOUse >> Fail"); return false; } // 26.04.09 NDY iPCset_ALINE_LCTYPE — Scanner xlsx 기준 미사용 bool IScannerACS.SetLCILserOn(bool on) { Log.D("SetLCILserOn >> Not Used in Scanner"); return true; } 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; } // ── 알람 ───────────────────────────────────────────────────────────── bool IScannerACS.ResetAlarm() { TerminalCommand("FCLEAR ALL"); return WriteVariableInt(AlarmReset, 1); } void IScannerACS.AllAxisServoOff() { if (!IsActivated || !IsConnected) return; SetMotorDisableAll(); } bool IScannerACS.IsActivated() => IsActivated; // 왜 없앴지.. 26.04.13 internal bool IsReachedTeachingPosition(eTeachingPosition targetPos) { switch (targetPos) { case eTeachingPosition.Load: return _motorVariable.IsLoadPosition; case eTeachingPosition.UnLoad: return _motorVariable.IsUnloadPosition; case eTeachingPosition.SafetyPosition: return _motorVariable.IsSafetyPosition; case eTeachingPosition.StageWeldingStartPos: return _motorVariable.IsWeldingStartPosition; default: return false; } } } }