using Aurora; using Aurora.Api; using Aurora.Api.Devices; using Aurora.Api.Manager; using Aurora.View; using AuroraACS; // 26.04.06 NDY 추가 using AuroraLaser; using AuroraLaserScanner; using AuroraMotionBoard.Ajin; using HarfBuzzSharp; using Microsoft.Office.Interop.Excel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using System.Windows.Threading; namespace WeldingCommon.Views { public enum eAxisType { AXIS_X, AXIS_Y } public enum eJogDirection { MINUS, PLUS } public enum eMotionMode { ABS, REL }; public class UCScannerMotionViewModel : NotifyPropertyChangedBase { private readonly Logger Log = new Logger("UCScannerMotionViewModel"); public ICommand CMD_VisibleChanged { get; } public ICommand CMD_SpeedChanged { get; } public ICommand CMD_MotionModeChanged { get; } public ICommand CMD_JogMove { get; } public ICommand CMD_CommandPosMove { get; } private readonly IAuroraEnvironment _Aurora; private readonly Scanner _Scanner; private readonly Laser _Laser; private readonly ScannerConfig _ScannerConfig; private double _ScannerXPos; public double ScannerXPos { get => _ScannerXPos; set => SetProperty(ref _ScannerXPos, value); } private double _ScannerYPos; public double ScannerYPos { get => _ScannerYPos; set => SetProperty(ref _ScannerYPos, value); } private bool _IsScannerBusy; public bool IsScannerBusy { get => _IsScannerBusy; set => SetProperty(ref _IsScannerBusy, value); } private double _StepValue; public double StepValue { get => _StepValue; set => SetProperty(ref _StepValue, value); } private double _CommandPosX; public double CommandPosX { get => _CommandPosX; set => SetProperty(ref _CommandPosX, value); } private double _CommandPosY; public double CommandPosY { get => _CommandPosY; set => SetProperty(ref _CommandPosY, value); } private double _CommandPosLimitMinX; public double CommandPosLimitMinX { get => _CommandPosLimitMinX; set => SetProperty(ref _CommandPosLimitMinX, value); } private double _CommandPosLimitMaxX; public double CommandPosLimitMaxX { get => _CommandPosLimitMaxX; set => SetProperty(ref _CommandPosLimitMaxX, value); } private double _CommandPosLimitMinY; public double CommandPosLimitMinY { get => _CommandPosLimitMinY; set => SetProperty(ref _CommandPosLimitMinY, value); } private double _CommandPosLimitMaxY; public double CommandPosLimitMaxY { get => _CommandPosLimitMaxY; set => SetProperty(ref _CommandPosLimitMaxY, value); } private double _VelocityRate; private eMotionMode _MotionMode; private readonly DispatcherTimer _MonitorTimer; // 26.04.06 NDY Stage X 관련 필드 추가 ================== private ACSMotor _MotorX; private ACSMotor _MotorZ; private double _StageXPos; public double StageXPos { get => _StageXPos; set => SetProperty(ref _StageXPos, value); } private double _StageZPos; public double StageZPos { get => _StageZPos; set => SetProperty(ref _StageZPos, value); } private bool _IsStageXActivated; public bool IsStageXActivated { get => _IsStageXActivated; set => SetProperty(ref _IsStageXActivated, value); } private bool _IsStageZActivated; public bool IsStageZActivated { get => _IsStageZActivated; set => SetProperty(ref _IsStageZActivated, value); } // ======================================================== // PAM, RUW 처럼 2개 이상의 scanner 를 사용하는 경우가 있어, scannerId 를 받는 형태로 생성 public UCScannerMotionViewModel(IAuroraEnvironment aurora, string scannerId) { _Aurora = aurora; _Scanner = _Aurora.DeviceManager[scannerId] as Scanner; _Laser = _Aurora.DeviceManager[CommonDeviceIds.Laser] as Laser; _ScannerConfig = _Aurora.DeviceManager.GetDeviceConfig(scannerId) as ScannerConfig; // 26.04.06 NDY Stage X 모터 연결 추가 =============== try { _MotorX = _Aurora.DeviceManager["AxisX2"] as ACSMotor; } catch { _MotorX = null; } try { _MotorZ = _Aurora.DeviceManager["AxisZ"] as ACSMotor; } catch { _MotorZ = null; } // ==================================================== InitVariable(); CMD_VisibleChanged = new DelegateCommand(VisibleChanged); CMD_SpeedChanged = new DelegateCommand(PerformCmdSpeedChanged); CMD_MotionModeChanged = new DelegateCommand(PerformCmdMotionModeChanged); CMD_JogMove = new DelegateCommand(PerformCmdJogMove); CMD_CommandPosMove = new DelegateCommand(PerformCmdCommandPosMove); _MonitorTimer = new DispatcherTimer(); _MonitorTimer.Tick += OnMonitoring; _MonitorTimer.Interval = TimeSpan.FromMilliseconds(100); } private void InitVariable() { _VelocityRate = 1; _MotionMode = eMotionMode.ABS; } private void VisibleChanged(object obj) { bool visible = (bool)obj; if (visible) { Init_XYLimitPos(); _MonitorTimer.Start(); } else { _MonitorTimer.Stop(); } } private void Init_XYLimitPos() { CommandPosLimitMinX = -1 * _ScannerConfig.ScanXSize / 2; CommandPosLimitMaxX = _ScannerConfig.ScanXSize / 2; CommandPosLimitMinY = -1 * _ScannerConfig.ScanYSize / 2; CommandPosLimitMaxY = _ScannerConfig.ScanYSize / 2; } private void OnMonitoring(object sender, EventArgs e) { // 기존 Scanner 모니터링 double xPos, yPos; if (_Scanner != null && _Scanner.IsActivated) { _Scanner.GetXYPos(out xPos, out yPos); ScannerXPos = xPos; ScannerYPos = yPos; IsScannerBusy = _Scanner.GetBusyStatus(); } else { ScannerXPos = 0; ScannerYPos = 0; IsScannerBusy = false; } // 26.04.06 NDY Stage X 모니터링 추가 ================ if (_MotorX != null && _MotorX.IsActivated) { StageXPos = _MotorX.GetActualPos(); IsStageXActivated = true; } else { IsStageXActivated = false; } if (_MotorZ != null && _MotorZ.IsActivated) { StageZPos = _MotorZ.GetActualPos(); IsStageZActivated = true; } else { IsStageZActivated = false; } // ==================================================== } private void PerformCmdSpeedChanged(object commandParameter) { switch ((string)commandParameter) { case "Low": _VelocityRate = 0.5; break; case "Mid": _VelocityRate = 1; break; case "High": _VelocityRate = 1.5; break; } } private void PerformCmdMotionModeChanged(object commandParameter) { switch ((string)commandParameter) { case "ABS": _MotionMode = eMotionMode.ABS; break; case "REL": _MotionMode = eMotionMode.REL; break; } } private void PerformCmdJogMove(object commandParameter) { var MainSequence = _Aurora.SequenceEntry[CommonSequenceIds.SeqAutoRun].RunState; if (MainSequence == SequenceRunState.Running) return; switch ((string)commandParameter) { case "Left": MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.MINUS); break; case "Right": MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.PLUS); break; case "Up": MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.PLUS); break; case "Down": MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.MINUS); break; case "Home": MoveJogHome(); break; // 26.04.06 NDY Stage X 버튼 추가 ================= case "Stage_X_Left": MoveStageX(eJogDirection.MINUS); break; case "Stage_X_Right": MoveStageX(eJogDirection.PLUS); break; case "Stage_Z_Left": MoveStageZ(eJogDirection.MINUS); break; case "Stage_Z_Right": MoveStageZ(eJogDirection.PLUS); break; // ================================================= } } // 26.04.06 NDY Stage X 이동 메서드 추가 ================== private void MoveStageX(eJogDirection direction) { if (_MotorX == null || !_MotorX.IsActivated) return; // 이미지 기준 방향 반전 적용 double step = direction == eJogDirection.PLUS ? -StepValue : +StepValue; Log.I($"Stage X Move : {step}mm"); _MotorX.SetTargetPos(step, TargetPosType.REL); _MotorX.SetVelocityImm(_MotorX.GetJogSpeed(AuroraACS.Speed.L) * _VelocityRate); _MotorX.Move(); } private void MoveStageZ(eJogDirection direction) { if (_MotorZ == null || !_MotorZ.IsActivated) return; // 이미지 기준 방향 반전 적용 double step = direction == eJogDirection.PLUS ? -StepValue : +StepValue; Log.I($"Stage Z Move : {step}mm"); _MotorZ.SetTargetPos(step, TargetPosType.REL); _MotorZ.SetVelocityImm(_MotorZ.GetJogSpeed(AuroraACS.Speed.L) * _VelocityRate); _MotorZ.Move(); } // ========================================================= private void MoveJogXYPos(eAxisType axisType, eJogDirection direction) { double xPos = 0.0; double yPos = 0.0; switch (axisType) { case eAxisType.AXIS_X: { if (direction == eJogDirection.MINUS) { xPos = StepValue * -1; yPos = 0; } else if (direction == eJogDirection.PLUS) { xPos = StepValue; yPos = 0; } } break; case eAxisType.AXIS_Y: { if (direction == eJogDirection.MINUS) { xPos = 0; yPos = StepValue * -1; } else if (direction == eJogDirection.PLUS) { xPos = 0; yPos = StepValue; } } break; } if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) { Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다."); return; } double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); _Scanner.JumpRel(xPos, yPos); _Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed); } private void MoveJogHome() { double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); _Scanner.JumpAbs(0, 0); _Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed); } private void PerformCmdCommandPosMove(object commandParameter) { switch ((string)commandParameter) { case "X": MoveCommandXYPos(eAxisType.AXIS_X); break; case "Y": MoveCommandXYPos(eAxisType.AXIS_Y); break; } } private void MoveCommandXYPos(eAxisType axisType) { double xPos = 0.0; double yPos = 0.0; switch (axisType) { case eAxisType.AXIS_X: { xPos = CommandPosX; yPos = _MotionMode == eMotionMode.ABS ? _Scanner.GetCommandPosY() : 0.0; } break; case eAxisType.AXIS_Y: { xPos = _MotionMode == eMotionMode.ABS ? _Scanner.GetCommandPosX() : 0.0; yPos = CommandPosY; } break; } if (_MotionMode == eMotionMode.ABS) { if (CheckOverLimitPos(xPos, yPos)) { Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다."); return; } } else { if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) { Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다."); return; } } double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); if (_MotionMode == eMotionMode.ABS) _Scanner.JumpAbs(xPos, yPos); else _Scanner.JumpRel(xPos, yPos); _Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed); } private bool CheckOverLimitPos(double calcPosX, double calcPosY) { if (calcPosX < CommandPosLimitMinX || calcPosX > CommandPosLimitMaxX) return true; if (calcPosY < CommandPosLimitMinY || calcPosY > CommandPosLimitMaxY) return true; return false; } } }