using MathNet.Numerics; using NPOI.OpenXml4Net.OPC.Internal; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Bcpg.Sig; using OxyPlot; using Prism.Commands; using Prism.Events; using Prism.Ioc; using Prism.Mvvm; using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using TeamAAS_VP.Controls; using TeamAAS_VP.Core; using TeamAAS_VP.Core.PLCs; using TeamAAS_VP.Core.ScrewDriver; using TeamAAS_VP.Data; using TeamAAS_VP.Enums; using TeamAAS_VP.Events; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; using TeamAAS_VP.Models.PLC; using TeamAAS_VP.Models.Torque; using TeamAAS_VP.Resources.Languages; using TeamAAS_VP.Services; using FileHelper = TeamAAS_VP.Core.FileHelper; namespace TeamAAS_VP.ViewModels.Home { public class TorqueCheckViewModel : BindableBase, IDialogAware { // 点检扭矩参数存放日志地址 public static readonly string CheckTorqueConfigurationPath = "..//Log//ScrewFeedersConfiguration.cfg"; IEventAggregator _eventAggregator; IConfigService _configService; IContainerProvider _container; IRobotService _robotService; IPlcService _plcService; TorqueService _torqueService; float Value { get; set; } = 0; #region 属性 private Management _management; public Management management { get { return _management; } set { SetProperty(ref _management, value); } } private bool CanExecute { get { // 命令可执行仅当机器人可执行且已选择点位 if (Robot != null && Robot.IsConnected && Robot.CanExecute) { return true; } return false; } } private IRobot _Robot; public IRobot Robot { get { return _Robot; } set { SetProperty(ref _Robot, value); } } private double _Distance = 1; public double Distance { get { return _Distance; } set { SetProperty(ref _Distance, value); try { if (Robot == null) { return; } _configService.UpdateRobotStepDistance(Robot.Id, value); } catch (Exception) { } } } private float _Z_Distance; public float Z_Distance { get { return _Z_Distance; } set { SetProperty(ref _Z_Distance, value); } } private float _torqueValue; public float TorqueValue { get { return _torqueValue; } set { SetProperty(ref _torqueValue, value); } } private string _TValue; public string TValue { get { return _TValue; } set { SetProperty(ref _TValue, value); } } private string _PValue; public string PValue { get { return _PValue; } set { SetProperty(ref _PValue, value); } } private string _SubValue; public string SubValue { get { return _SubValue; } set { SetProperty(ref _SubValue, value); } } private string _Result; public string Result { get { return _Result; } set { SetProperty(ref _Result, value); } } private string _FontColor; public string FontColor { get { return _FontColor; } set { SetProperty(ref _FontColor, value); } } private int _SelectedIndex; public int SelectedIndex { get { return _SelectedIndex; } set { SetProperty(ref _SelectedIndex, value); } } private ObservableCollection _Points = new ObservableCollection(); /// /// 点位集合 /// public ObservableCollection Points { get { return _Points; } set { SetProperty(ref _Points, value); } } private TorqueProduceModel _AllProductParameter = new TorqueProduceModel(); /// /// 所有产品的参数信息 /// public TorqueProduceModel AllProductParameter { get { return _AllProductParameter; } set { SetProperty(ref _AllProductParameter, value); } } private PlcPoint_Torque _selectedPointInDataGrid; public PlcPoint_Torque SelectedPointInDataGrid { get { return _selectedPointInDataGrid; } set { SetProperty(ref _selectedPointInDataGrid, value); // 可以同步到 SelectPoint 属性 SelectedPoint = value; AllProductParameter.TorquePoints = _Points; } } private PlcPoint_Torque _SelectedPoint; public PlcPoint_Torque SelectedPoint { get { return _SelectedPoint; } set { SetProperty(ref _SelectedPoint, value); } } #endregion #region 命令 private DelegateCommand _CancelCommand; public DelegateCommand CancelCommand => _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand)); private DelegateCommand _LoadedCommand; public DelegateCommand LoadedCommand => _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand)); private DelegateCommand _ConfirmCommand; public DelegateCommand ConfirmCommand => _ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand)); private DelegateCommand _MotorCommand; public DelegateCommand MotorCommand => _MotorCommand ?? (_MotorCommand = new DelegateCommand(ExecuteMotorCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute)); private DelegateCommand _JogCommand; public DelegateCommand JogCommand => _JogCommand ?? (_JogCommand = new DelegateCommand(ExecuteJogCommand).ObservesCanExecute(() => CanExecute).ObservesProperty(() => Robot).ObservesProperty(() => Robot.CanExecute)); private DelegateCommand _TechPointCommand; public DelegateCommand TechPointCommand => _TechPointCommand ?? (_TechPointCommand = new DelegateCommand(ExecuteTechPointCommand)); private DelegateCommand _MovePointCommand; public DelegateCommand MovePointCommand => _MovePointCommand ?? (_MovePointCommand = new DelegateCommand(ExecuteMovePointCommand)); private DelegateCommand _ModifyCommand; public DelegateCommand ModifyCommand => _ModifyCommand ?? (_ModifyCommand = new DelegateCommand(ExecuteModifyCommand)); private DelegateCommand _WorkCommand; public DelegateCommand WorkCommand => _WorkCommand ?? (_WorkCommand = new DelegateCommand(ExecuteWorkCommand)); private DelegateCommand _SavePointsCommand; public DelegateCommand SavePointsCommand => _SavePointsCommand ?? (_SavePointsCommand = new DelegateCommand(ExecuteSavePointsCommand)); #endregion #region 方法 public TorqueCheckViewModel(IEventAggregator ea, IConfigService configService, TorqueService torqueService, IContainerProvider container, IRobotService robotService, IPlcService plcService) { _eventAggregator = ea; _configService = configService; _container = container; _robotService = robotService; _plcService = plcService; _torqueService = torqueService; management = _container.Resolve(); } bool CanExecuteDeletePointCommand() { return SelectedPointInDataGrid != null; } void ExecuteCancelCommand() { IDialogParameters parameters = new DialogParameters(); RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel, parameters)); } void ExecuteConfirmCommand() { IDialogParameters parameters = new DialogParameters(); RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters)); } /// /// 电机 /// /// private async void ExecuteMotorCommand(string obj) { if (Robot == null || !Robot.IsConnected) return; try { await Robot.MotorAsync(Convert.ToBoolean(obj)); _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = $"{Lang.完成}!", Duration = 0.4 }); } catch (Exception ex) { LogHelper.WriteLogError("机器人点击操作时出错!", ex); _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 }); } } /// /// 点动 /// /// private async void ExecuteJogCommand(object obj) { if (Robot == null || !Robot.IsConnected) return; try { var items = ((string)obj).Split(':'); //如果移动距离大于10mm,则提示用户确认 double distance = double.Parse(items[1]); if (Math.Abs(distance) >= 10) { if (MessageBox.Show($"确认要点动距离 {distance} mm 吗?", "确认点动", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) { return; } } Robot.Timeout = 6000000; switch (items[0]) { case "X+": await Robot.JogAsync("X", distance); break; case "X-": await Robot.JogAsync("X", -distance); break; case "Y+": await Robot.JogAsync("Y", distance); break; case "Y-": await Robot.JogAsync("Y", -distance); break; case "Z+": await Robot.JogAsync("Z", distance); break; case "Z-": await Robot.JogAsync("Z", -distance); break; case "U+": await Robot.JogAsync("U", distance); break; case "U-": await Robot.JogAsync("U", -distance); break; case "V+": await Robot.JogAsync("V", distance); break; case "V-": await Robot.JogAsync("V", -distance); break; case "W+": await Robot.JogAsync("W", distance); break; case "W-": await Robot.JogAsync("W", -distance); break; default: break; } Robot.Timeout = 5000; _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = $"{Lang.完成}!", Duration = 0.4 }); } catch (Exception ex) { LogHelper.WriteLogError("机器人点位-机器人点动时出错", ex); _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 }); } } /// /// 示教点位 /// async void ExecuteTechPointCommand() { //弹窗用户是否确认要示教该点位 if (MessageBox.Show($"确认要示教点位吗?", "示教点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) { return; } if (SelectedPoint == null) { MessageBox.Show("请选择示教点位"); return; } var curpos = await Robot.GetRobotPosAsync(); SelectedPoint.X_Position = curpos.X; SelectedPoint.Y_Position = curpos.Y; SelectedPoint.Z_Position_Start = curpos.Z; SelectedPoint.Z_Position_Stop = 0; AllProductParameter.TorqueValue = this.TorqueValue; AllProductParameter.TorquePoints = Points; FileHelper.WriteJsonFile(AllProductParameter, FilePath.TorqueCheckPath); _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = $"{Lang.完成}!", Duration = 0.4 }); } /// /// 修改 /// async void ExecuteModifyCommand() { if (MessageBox.Show($"确认要修改扭力阈值吗?", "修改", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) { return; } var res = FileHelper.ReadJsonFile(FilePath.TorqueCheckPath); res.TorqueValue = this.TorqueValue; try { FileHelper.WriteJsonFile(res, FilePath.TorqueCheckPath); } catch (Exception) { MessageBox.Show("修改失败"); } _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.4 }); } async void ExecuteWorkCommand() { if (!File.Exists(FilePath.TorqueCheckPath)) { MessageBox.Show("还未示教,请先示教"); return; } if (Robot == null || !Robot.IsConnected) { return; } if (MessageBox.Show($"确认要进行点检吗?", "执行点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) { return; } try { if (await MoveRobot()) { _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.4 }); } else { _eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.失败, Duration = 0.4 }); } } catch (Exception ex) { LogHelper.WriteLogError("执行点检时出错!", ex); } } /// /// 点检扭矩总体流程 /// /// public async Task MoveRobot() { TorqueProduceModel Plc_Point = new TorqueProduceModel(); PlcAddressConfig addressConfig = _configService.GetPlcAddresses(); OpcUaClientPLC plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; try { Plc_Point = FileHelper.ReadJsonFile(FilePath.TorqueCheckPath); if (Plc_Point == null || addressConfig == null || plc == null) { return false; } //切换手动模式 if (await plc.WriteNodeAsync(addressConfig.OP_AutoManual.Address, false)) { //回设置的零点 if (await _torqueService.Safety_Position_Async(Robot, plc, addressConfig, Plc_Point)) { //执行抛螺丝动作 if (await _torqueService.Throw_Screw_Async(Robot, plc, addressConfig, Plc_Point)) { //执行取螺丝动作 if (await _torqueService.Pick_Screw_Async(Robot, plc, addressConfig, Plc_Point)) { //执行锁螺丝点位操作 if (await _torqueService.Screw_Torque_Async(Robot, plc, addressConfig, Plc_Point)) { //获取电批结果并显示曲线 if (await WatchAsync(plc, addressConfig)) { await DisplayResult(); return true; } MessageBox.Show("未获取到电批结果"); return false; } MessageBox.Show("执行锁螺丝点位操作失败"); return false; } MessageBox.Show("执行取螺丝动作失败"); return false; } MessageBox.Show("执行抛螺丝动作失败"); return false; } MessageBox.Show("执行回安全点失败"); return false; } MessageBox.Show("点检失败"); return false; } catch (Exception ex) { LogHelper.WriteLogError("执行点检移动时出错!", ex); return false; } finally { await _torqueService.Safety_Position_Async(Robot, plc, addressConfig, Plc_Point); } } public async Task DisplayResult() { try { await Task.Delay(100); TValue = management.SignalValue; double tvalue = double.Parse(TValue.Split(' ')[0]); double pvalue = Value; PValue = $"{Math.Round(pvalue, 3)} kgf.cm"; SubValue = $"{Math.Round(Math.Abs(tvalue - pvalue), 3)} kgf.cm"; double sub = Math.Abs(tvalue - pvalue); var res = FileHelper.ReadJsonFile(FilePath.TorqueCheckPath); if (res != null) { if (sub <= res.TorqueValue) { FontColor = "Green"; Result = "OK"; } else { FontColor = "Red"; Result = "NG"; } } else { if (sub <= TorqueValue) { FontColor = "Green"; Result = "OK"; } else { FontColor = "Red"; Result = "NG"; } } await _torqueService.Save_Torque_Log($"{DateTime.Now},{TValue},{PValue},{Math.Round(sub, 4)},{TorqueValue},{Result}"); SendTaskMessage("点检扭矩成功", MessageLevel.Info); } catch (Exception ex) { LogHelper.WriteLogError("执行点检显示时出错!", ex); } } public async Task WatchAsync(OpcUaClientPLC plc, PlcAddressConfig addressConfig) { object oking = null; object nging = null; int count = 0; while (count++ < 20) { await Task.Delay(100); oking = plc.ReadNode(addressConfig.Screw_OK.Address); nging = plc.ReadNode(addressConfig.Screw_NG.Address); if (oking != null && nging != null) { bool okin = (bool)oking; bool ngin = (bool)nging; //电批OKNG if (okin || ngin) { //获取电批结果 bool isSucced = management.ScrewDriver.GetData(); LockResult lockResult = new LockResult(); lockResult.LockTurns = (float)management.ScrewDriver.Truns; lockResult.LockTorque = (float)management.ScrewDriver.TorqueValue; lockResult.WaveDatas = management.ScrewDriver.WaveDatas; App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(lockResult); }); //await _systemDatabaseService.RecordLockResultAsync(lockResult); await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0); Value = lockResult.LockTorque; await plc.WriteNodeAsync(addressConfig.Check_ScrewTorque.Address, false); return true; } } } return false; } #endregion public string Title { get; set; } = "扭力点检"; public event Action RequestClose; public bool CanCloseDialog() { return true; } public void OnDialogClosed() { } public void OnDialogOpened(IDialogParameters parameters) { try { var res = FileHelper.ReadJsonFile(FilePath.TorqueCheckPath); if (res == null) { MessageBox.Show("还未示教,请先示教"); InitialTorquePoints(); } } catch (Exception) { MessageBox.Show("还未示教,请先示教"); InitialTorquePoints(); } if (Robot == null) { Robot = _robotService.GetRobotByNumber(1); } if (Robot != null && Robot.IsConnected) { this.Distance = _configService.GetRobotStepDistance(Robot.Id); Robot.EnterDebugMode = true; } else if (Robot != null) { Robot.EnterDebugMode = true; } } private void InitialTorquePoints() { TorqueProduceModel torques = new TorqueProduceModel() { TorquePoints = new ObservableCollection() { new PlcPoint_Torque(){Label="抛料点位"}, new PlcPoint_Torque(){Label="取料点位"}, new PlcPoint_Torque(){Label="锁螺丝点位"}, new PlcPoint_Torque(){Label="安全点位"}, } }; FileHelper.WriteJsonFile(torques, FilePath.TorqueCheckPath); } private void ExecuteLoadedCommand() { var res = FileHelper.ReadJsonFile(FilePath.TorqueCheckPath); this.Points = res.TorquePoints; this.TorqueValue = res.TorqueValue; } private void SendTaskMessage(string msg, MessageLevel level) { App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(new Models.MessageStruct() { Message = msg, level = level }); }); } private void ExecuteSavePointsCommand() { AllProductParameter.TorqueValue = this.TorqueValue; AllProductParameter.TorquePoints = Points; FileHelper.WriteJsonFile(AllProductParameter, FilePath.TorqueCheckPath); MessageBox.Show("参数保存成功"); } private async void ExecuteMovePointCommand() { if (MessageBox.Show($"确认要进行单独移动至点位吗?", "执行点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) { return; } PlcAddressConfig addressConfig = _configService.GetPlcAddresses(); OpcUaClientPLC plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; await _torqueService.Signal_Move_Async(Robot, plc, addressConfig, SelectedPoint); } } }