using Aurora; using Aurora.Api; using Aurora.Api.Manager; using Aurora.View; using AuroraLaser; using AuroraLaserScanner; 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; // 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; 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() { // TODO: Limit 값을 Min, Max 로 따로 Setting 입력값으로 가져와야 할 수도 있음. 우선 현상태 유지 CommandPosLimitMinX = -1 * _ScannerConfig.ScanXSize / 2; CommandPosLimitMaxX = _ScannerConfig.ScanXSize / 2; CommandPosLimitMinY = -1 * _ScannerConfig.ScanYSize / 2; CommandPosLimitMaxY = _ScannerConfig.ScanYSize / 2; //CommandPosXLimit = string.Format($"{-1 * _ScannerConfig.ScanXSize / 2} ~ {_ScannerConfig.ScanXSize / 2}"); //CommandPosYLimit = string.Format($"{-1 * _ScannerConfig.ScanYSize / 2} ~ {_ScannerConfig.ScanYSize / 2}"); } private void OnMonitoring(object sender, EventArgs e) { 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; } } 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) { // TODO: Left, Right, Up, Down 은 장비 Scanner 의 방향에 따라 달라질 수 있다 // 양산중에는 동작 하면 안됨 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; } } 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; default: break; } // 현재 Curruent Pos 기준으로, 입력방향으로 입력값이 Limit 를 넘어 서는지 확인 (Rel 임) if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) { Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다.")); return; } double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); _Scanner.JumpRel(xPos, yPos); //Jump 후 Speed 원복 _Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed); } private void MoveJogHome() { double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); _Scanner.JumpAbs(0, 0); //Jump 후 Speed 원복 _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; if (_MotionMode == eMotionMode.ABS) { yPos = _Scanner.GetCommandPosY(); } else { yPos = 0.0; } } break; case eAxisType.AXIS_Y: { if (_MotionMode == eMotionMode.ABS) { xPos = _Scanner.GetCommandPosX(); } else { xPos = 0.0; } yPos = CommandPosY; } break; default: break; } // 현재 Curruent Pos 기준으로, 입력방향으로 입력값이 Limit 를 넘어 서는지 확인 if (_MotionMode == eMotionMode.ABS) { if (CheckOverLimitPos(xPos, yPos)) { Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다.")); return; } } else { if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) { Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다.")); return; } } double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate; _Scanner.SetJumpSpeedCtrl(finalVelocity); if (_MotionMode == eMotionMode.ABS) { _Scanner.JumpAbs(xPos, yPos); } else { _Scanner.JumpRel(xPos, yPos); } //Jump 후 Speed 원복 _Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed); } private bool CheckOverLimitPos(double calcPosX, double calcPosY) { if (calcPosX < CommandPosLimitMinX || calcPosX > CommandPosLimitMaxX) { return true; } else if (calcPosY < CommandPosLimitMinY || calcPosY > CommandPosLimitMaxY) { return true; } return false; } } }