|
|
@@ -0,0 +1,451 @@
|
|
|
+using MaterialDesignThemes.Wpf;
|
|
|
+using Newtonsoft.Json;
|
|
|
+using Prism.Commands;
|
|
|
+using Prism.Events;
|
|
|
+using Prism.Ioc;
|
|
|
+using Prism.Mvvm;
|
|
|
+using Prism.Regions;
|
|
|
+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.Web.UI.WebControls;
|
|
|
+using System.Windows;
|
|
|
+using System.Windows.Threading;
|
|
|
+using TeamAAS_VP.Core;
|
|
|
+using TeamAAS_VP.Core.PLCs;
|
|
|
+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 TeamAAS_VP.ViewModels.Product;
|
|
|
+using static TeamAAS_VP.ViewModels.Product.VisionDynamicAccuracyAnalyzerViewModel;
|
|
|
+
|
|
|
+namespace TeamAAS_VP.ViewModels.Home
|
|
|
+{
|
|
|
+ public class PickScrewAccuracyAnalyzerViewModel : BindableBase, IDialogAware
|
|
|
+ {
|
|
|
+ IRegionManager _regionManager;
|
|
|
+ IEventAggregator _eventAggregator;
|
|
|
+ IContainerProvider _container;
|
|
|
+ IDialogService _dialogService;
|
|
|
+ IRobotService _robotService;
|
|
|
+ ISystemDatabaseService _systemDatabaseService;
|
|
|
+ IConfigService _configService;
|
|
|
+ IPlcService _plcService;
|
|
|
+
|
|
|
+ TorqueService _torqueService;
|
|
|
+
|
|
|
+ //测试过程中控制取消的CTS
|
|
|
+ CancellationTokenSource _cts;
|
|
|
+ public PickScrewAccuracyAnalyzerViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container,
|
|
|
+ IDialogService dialogService, IRobotService robotService, ISystemDatabaseService systemDatabaseService,
|
|
|
+ IConfigService configService, TorqueService torqueService, IPlcService plcService)
|
|
|
+ {
|
|
|
+ _eventAggregator = ea;
|
|
|
+ _configService = configService;
|
|
|
+ _container = container;
|
|
|
+ _robotService = robotService;
|
|
|
+ _torqueService = torqueService;
|
|
|
+ _plcService = plcService;
|
|
|
+ management = _container.Resolve<Management>();
|
|
|
+ MessageQueue = new SnackbarMessageQueue(TimeSpan.FromSeconds(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 属性
|
|
|
+
|
|
|
+ private SnackbarMessageQueue _MessageQueue;
|
|
|
+ public SnackbarMessageQueue MessageQueue
|
|
|
+ {
|
|
|
+ get { return _MessageQueue; }
|
|
|
+ set { SetProperty(ref _MessageQueue, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Management _management;
|
|
|
+ public Management management
|
|
|
+ {
|
|
|
+ get { return _management; }
|
|
|
+ set { SetProperty(ref _management, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int _MoveSpeed = 100;
|
|
|
+ /// <summary>
|
|
|
+ /// 移动速度
|
|
|
+ /// </summary>
|
|
|
+ public int MoveSpeed
|
|
|
+ {
|
|
|
+ get { return _MoveSpeed; }
|
|
|
+ set { SetProperty(ref _MoveSpeed, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private double _CycleTime;
|
|
|
+ /// <summary>
|
|
|
+ /// 单次的时长
|
|
|
+ /// </summary>
|
|
|
+ public double CycleTime
|
|
|
+ {
|
|
|
+ get { return _CycleTime; }
|
|
|
+ set { SetProperty(ref _CycleTime, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int _RepeatCount = 10;
|
|
|
+ /// <summary>
|
|
|
+ /// 重复次数
|
|
|
+ /// </summary>
|
|
|
+ public int RepeatCount
|
|
|
+ {
|
|
|
+ get { return _RepeatCount; }
|
|
|
+ set { SetProperty(ref _RepeatCount, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int _CurrentProgress;
|
|
|
+ /// <summary>
|
|
|
+ /// 当前进度
|
|
|
+ /// </summary>
|
|
|
+ public int CurrentProgress
|
|
|
+ {
|
|
|
+ get { return _CurrentProgress; }
|
|
|
+ set { SetProperty(ref _CurrentProgress, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int _SuccessCount;
|
|
|
+ /// <summary>
|
|
|
+ /// 成功次数
|
|
|
+ /// </summary>
|
|
|
+ public int SuccessCount
|
|
|
+ {
|
|
|
+ get { return _SuccessCount; }
|
|
|
+ set { SetProperty(ref _SuccessCount, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int _FailCount;
|
|
|
+ /// <summary>
|
|
|
+ /// 失败次数
|
|
|
+ /// </summary>
|
|
|
+ public int FailCount
|
|
|
+ {
|
|
|
+ get { return _FailCount; }
|
|
|
+ set { SetProperty(ref _FailCount, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private double _SuccessRate;
|
|
|
+ /// <summary>
|
|
|
+ /// 成功率
|
|
|
+ /// </summary>
|
|
|
+ public double SuccessRate
|
|
|
+ {
|
|
|
+ get { return _SuccessRate; }
|
|
|
+ set { SetProperty(ref _SuccessRate, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private string _Message = "等待开始...";
|
|
|
+ public string Message
|
|
|
+ {
|
|
|
+ get { return _Message; }
|
|
|
+ set { SetProperty(ref _Message, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool _IsRunning;
|
|
|
+
|
|
|
+ public bool IsRunning
|
|
|
+ {
|
|
|
+ get { return _IsRunning; }
|
|
|
+ set { SetProperty(ref _IsRunning, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private IRobot _Robot;
|
|
|
+
|
|
|
+ public IRobot Robot
|
|
|
+ {
|
|
|
+ get { return _Robot; }
|
|
|
+ set { SetProperty(ref _Robot, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private ObservableCollection<PickDynamicTestResult> _TestResults;
|
|
|
+ /// <summary>
|
|
|
+ /// 测试结果列表
|
|
|
+ /// </summary>
|
|
|
+ public ObservableCollection<PickDynamicTestResult> TestResults
|
|
|
+ {
|
|
|
+ get { return _TestResults; }
|
|
|
+ set { SetProperty(ref _TestResults, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private RPoint _PointA = new RPoint();
|
|
|
+
|
|
|
+
|
|
|
+ private TorqueProduceModel _Points;
|
|
|
+
|
|
|
+ public TorqueProduceModel Points
|
|
|
+ {
|
|
|
+ get { return _Points; }
|
|
|
+ set { SetProperty(ref _Points, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 命令
|
|
|
+
|
|
|
+ private DelegateCommand _StopTestCommand;
|
|
|
+ public DelegateCommand StopTestCommand =>
|
|
|
+ _StopTestCommand ?? (_StopTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning));
|
|
|
+
|
|
|
+ //暂停测试命令
|
|
|
+ private DelegateCommand _PauseTestCommand;
|
|
|
+ public DelegateCommand PauseTestCommand =>
|
|
|
+ _PauseTestCommand ?? (_PauseTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning));
|
|
|
+
|
|
|
+ private DelegateCommand _LoadedCommand;
|
|
|
+ public DelegateCommand LoadedCommand =>
|
|
|
+ _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
|
|
|
+
|
|
|
+ private DelegateCommand _StartTestCommand;
|
|
|
+ public DelegateCommand StartTestCommand =>
|
|
|
+ _StartTestCommand ?? (_StartTestCommand = new DelegateCommand(ExecuteStartTestCommand).ObservesProperty(() => IsRunning));
|
|
|
+
|
|
|
+ private DelegateCommand _SingleTestCommand;
|
|
|
+ public DelegateCommand SingleTestCommand =>
|
|
|
+ _SingleTestCommand ?? (_SingleTestCommand = new DelegateCommand(ExecuteSingleTestCommand));
|
|
|
+
|
|
|
+ private DelegateCommand _ExportCSVCommand;
|
|
|
+ public DelegateCommand ExportCSVCommand =>
|
|
|
+ _ExportCSVCommand ?? (_ExportCSVCommand = new DelegateCommand(ExecuteExportCSVCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
|
|
|
+
|
|
|
+ private DelegateCommand _ClearDataCommand;
|
|
|
+ public DelegateCommand ClearDataCommand =>
|
|
|
+ _ClearDataCommand ?? (_ClearDataCommand = new DelegateCommand(ExecuteClearDataCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
|
|
|
+
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 保存配置
|
|
|
+ /// </summary>
|
|
|
+ private void SaveConfig()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var ConfigModel = new PickScrewAccuracyAnalyzerrConfigModel
|
|
|
+ {
|
|
|
+ RepeatCount = this.RepeatCount,
|
|
|
+ MoveSpeed = this.MoveSpeed
|
|
|
+ };
|
|
|
+ FileHelper.WriteJsonFile(ConfigModel, FilePath.PickScrewAccuracyAnalyzerrConfigurationPath);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.WriteLogError("保存视觉动态精度分析仪配置时出错", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ExecuteLoadedCommand()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var res = FileHelper.ReadJsonFile<PickScrewAccuracyAnalyzerrConfigModel>(FilePath.PickScrewAccuracyAnalyzerrConfigurationPath);
|
|
|
+ this.RepeatCount = res.RepeatCount;
|
|
|
+ this.MoveSpeed = res.MoveSpeed;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ MessageBox.Show(ex.Message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ExecuteSingleTestCommand()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private async void ExecuteStartTestCommand()
|
|
|
+ {
|
|
|
+ IsRunning = true;
|
|
|
+ _cts = new CancellationTokenSource();
|
|
|
+ CurrentProgress = 0;
|
|
|
+ SuccessCount = 0;
|
|
|
+ SuccessRate = 0;
|
|
|
+ FailCount = 0;
|
|
|
+ TestResults = new ObservableCollection<PickDynamicTestResult>();
|
|
|
+ Message = "测试进行中...";
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ PlcAddressConfig addressConfig = _configService.GetPlcAddresses();
|
|
|
+ OpcUaClientPLC plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
|
|
|
+ var result = System.Windows.MessageBox.Show("确定进行连续测试吗?", "提示", System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question);
|
|
|
+ if (result != System.Windows.MessageBoxResult.Yes)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Robot == null || !Robot.IsConnected)
|
|
|
+ {
|
|
|
+ SendTaskMessage("机器人未连接,无法示教!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //为机器人设置移动速度
|
|
|
+ await Robot.CalibParameAsync(new PickInfo(), MoveSpeed, 0, false, 0, 0);
|
|
|
+
|
|
|
+ while (CurrentProgress < RepeatCount)
|
|
|
+ {
|
|
|
+ DateTime startTime = DateTime.Now;
|
|
|
+ if (_cts.Token.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ Message = "测试已取消!";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bool isSuccess1 = await _torqueService.Throw_Screw_Async(Robot, plc, addressConfig, Points, MoveSpeed);
|
|
|
+ if (!isSuccess1)
|
|
|
+ {
|
|
|
+ SendTaskMessage("机器人移动到抛料点失败!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (_cts.Token.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ Message = "测试已取消!";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isSuccess2 = await _torqueService.Pick_Screw_Async(Robot, plc, addressConfig, Points);
|
|
|
+ if (isSuccess2)
|
|
|
+ {
|
|
|
+ SuccessCount++;
|
|
|
+ CycleTime = DateTime.Now.Subtract(startTime).TotalSeconds;
|
|
|
+ TestResults.Add(new PickDynamicTestResult()
|
|
|
+ {
|
|
|
+ Index = CurrentProgress + 1,
|
|
|
+ X_Position = Points.TorquePoints[1].X_Position,
|
|
|
+ Y_Position = Points.TorquePoints[1].Y_Position,
|
|
|
+ Z_Position = Points.TorquePoints[1].Z_Position_Start,
|
|
|
+ Timestamp = DateTime.Now,
|
|
|
+ CycleTime = this.CycleTime,
|
|
|
+ IsPickSuccess = isSuccess2
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ FailCount++;
|
|
|
+ CycleTime = DateTime.Now.Subtract(startTime).TotalSeconds;
|
|
|
+ TestResults.Add(new PickDynamicTestResult()
|
|
|
+ {
|
|
|
+ Index = CurrentProgress + 1,
|
|
|
+ X_Position = Points.TorquePoints[1].X_Position,
|
|
|
+ Y_Position = Points.TorquePoints[1].Y_Position,
|
|
|
+ Z_Position = Points.TorquePoints[1].Z_Position_Start,
|
|
|
+ Timestamp = DateTime.Now,
|
|
|
+ CycleTime = this.CycleTime,
|
|
|
+ IsPickSuccess = isSuccess2
|
|
|
+ });
|
|
|
+ }
|
|
|
+ CurrentProgress++;
|
|
|
+ SuccessRate = (double)SuccessCount / CurrentProgress * 100;
|
|
|
+ SendTaskMessage($"测试进行中... {CurrentProgress}/{RepeatCount}");
|
|
|
+ }
|
|
|
+ if (CurrentProgress >= RepeatCount)
|
|
|
+ {
|
|
|
+ Message = "测试完成!";
|
|
|
+ await _torqueService.Throw_Screw_Async(Robot, plc, addressConfig, Points, MoveSpeed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.WriteLogError("取料重复测试时出错!", ex);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ IsRunning = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SendTaskMessage(string msg)
|
|
|
+ {
|
|
|
+ App.Current.Dispatcher.Invoke(() =>
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg =msg, Duration = 1 });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ExecuteExportCSVCommand()
|
|
|
+ {
|
|
|
+ if (TestResults == null || TestResults.Count == 0)
|
|
|
+ {
|
|
|
+ SendTaskMessage("无测试数据,无法导出。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var dlg = new Microsoft.Win32.SaveFileDialog
|
|
|
+ {
|
|
|
+ DefaultExt = "csv",
|
|
|
+ Filter = "CSV 文件 (*.csv)|*.csv|所有文件 (*.*)|*.*",
|
|
|
+ FileName = "TestResults.csv",
|
|
|
+ Title = "保存测试结果为 CSV"
|
|
|
+ };
|
|
|
+
|
|
|
+ bool? dlgResult = dlg.ShowDialog();
|
|
|
+ if (dlgResult != true)
|
|
|
+ return;
|
|
|
+
|
|
|
+ string path = dlg.FileName;
|
|
|
+ if (File.Exists(path))
|
|
|
+ {
|
|
|
+ File.Delete(path);
|
|
|
+ }
|
|
|
+ using (StreamWriter sw = new StreamWriter(path, true))
|
|
|
+ {
|
|
|
+ //初始化文件,写入标题行
|
|
|
+ sw.WriteLine("序号,状态,位置X,位置Y,位置Z,循环时间,时间戳");
|
|
|
+ foreach (var item in TestResults)
|
|
|
+ {
|
|
|
+ sw.WriteLine($"{item.Index},{item.IsPickSuccess},{item.X_Position},{item.Y_Position},{item.Z_Position},{item.CycleTime},{item.Timestamp}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ MessageBox.Show("写入数据失败" + ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void ExecuteClearDataCommand()
|
|
|
+ {
|
|
|
+ TestResults.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 继承
|
|
|
+ public string Title { get; set; } = "动态取料测试";
|
|
|
+
|
|
|
+ public event Action<IDialogResult> RequestClose;
|
|
|
+
|
|
|
+ public bool CanCloseDialog()
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnDialogClosed()
|
|
|
+ {
|
|
|
+ SaveConfig();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnDialogOpened(IDialogParameters parameters)
|
|
|
+ {
|
|
|
+ if (parameters.ContainsKey("PickScrewPoint") && parameters.ContainsKey("Robot"))
|
|
|
+ {
|
|
|
+ Points = parameters.GetValue<TorqueProduceModel>("PickScrewPoint");
|
|
|
+ Robot = parameters.GetValue<IRobot>("Robot");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ }
|
|
|
+}
|