Browse Source

增加动态取料检测功能

KWD 7 months ago
parent
commit
50f02a25a7

+ 1 - 0
TeamAAS-VM/App.xaml.cs

@@ -214,6 +214,7 @@ namespace TeamAAS_VP
             containerRegistry.RegisterDialog<ChangeHeader>();
             containerRegistry.RegisterDialog<ChangeNozzle>();
             containerRegistry.RegisterDialog<PlcPointOffserParams>();
+            containerRegistry.RegisterDialog<PickScrewAccuracyAnalyzer>();
             //**************************************************************************************
 
             // 注册 SQLSugar 客户端(单例模式)

+ 4 - 2
TeamAAS-VM/Core/FilePath.cs

@@ -71,9 +71,11 @@ namespace TeamAAS_VP.Core
         /// 生产排班参数路径
         /// </summary>
 
-        public static readonly string WorkShiftParamPath = "..//Log//WorkShiftParam.cfg";
+        public static string WorkShiftParamPath = "..//Log//WorkShiftParam.cfg";
 
         // 电批配置路径
-        public static readonly string TorqueReaderConfigurationPath = "..//Config//TorqueReaderConfiguration.cfg";
+        public static string TorqueReaderConfigurationPath = "..//Config//TorqueReaderConfiguration.cfg";
+
+        public static string PickScrewAccuracyAnalyzerrConfigurationPath = "..//Config//PickScrewAccuracyAnalyzerrConfiguration.cfg";
     }
 }

+ 1 - 1
TeamAAS-VM/Core/Management.cs

@@ -1978,7 +1978,7 @@ namespace TeamAAS_VP.Core
                                 //plc启用的模式
                                 bool models = plc.ReadNode<bool>(addressConfig.Cam_code_mode.Address);
 
-                                if (models)
+                                if (models && state == 1)
                                 {
                                     //拍照读码
                                     SendTaskMessage(Lang.触发上相机锁附组装拍照, MessageLevel.Debug);

+ 74 - 0
TeamAAS-VM/Models/Torque/PickDynamicTestResult.cs

@@ -0,0 +1,74 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Models.Torque
+{
+    public class PickDynamicTestResult:BindableBase
+    {
+
+        private int _Index;
+        /// <summary>
+        /// 序号
+        /// </summary>
+        public int Index
+        {
+            get { return _Index; }
+            set { SetProperty(ref _Index, value); }
+        }
+
+        private DateTime _Timestamp;
+        /// <summary>
+        /// 时间戳
+        /// </summary>
+        public DateTime Timestamp
+        {
+            get { return _Timestamp; }
+            set { SetProperty(ref _Timestamp, value); }
+        }
+
+        private bool _IsPickSuccess;
+
+        public bool IsPickSuccess
+        {
+            get { return _IsPickSuccess; }
+            set { SetProperty(ref _IsPickSuccess, value); }
+        }
+
+
+        private float _X_Position;
+        public float X_Position
+        {
+            get { return _X_Position; }
+            set { SetProperty(ref _X_Position, value); }
+        }
+
+        private float _Y_Position;
+        public float Y_Position
+        {
+            get { return _Y_Position; }
+            set { SetProperty(ref _Y_Position, value); }
+        }
+
+
+        private float _Z_Position;
+        public float Z_Position
+        {
+            get { return _Z_Position; }
+            set { SetProperty(ref _Z_Position, value); }
+        }
+
+        private double _CycleTime;
+        /// <summary>
+        /// 单次节拍
+        /// </summary>
+        public double CycleTime
+        {
+            get { return _CycleTime; }
+            set { SetProperty(ref _CycleTime, value); }
+        }
+    }
+}

+ 32 - 0
TeamAAS-VM/Models/Torque/PickScrewAccuracyAnalyzerrConfigModel.cs

@@ -0,0 +1,32 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Models.Torque
+{
+    public class PickScrewAccuracyAnalyzerrConfigModel : BindableBase
+    {
+        private int _MoveSpeed = 100;
+        /// <summary>
+        /// 机器人移动速度
+        /// </summary>
+        public int MoveSpeed
+        {
+            get { return _MoveSpeed; }
+            set { SetProperty(ref _MoveSpeed, value); }
+        }
+        private int _RepeatCount = 10;
+        /// <summary>
+        /// 测试次数
+        /// </summary>
+        public int RepeatCount
+        {
+            get { return _RepeatCount; }
+            set { SetProperty(ref _RepeatCount, value); }
+        }
+    }
+
+}

+ 0 - 3
TeamAAS-VM/Models/Torque/PlcPoint_Torque.cs

@@ -54,9 +54,6 @@ namespace TeamAAS_VP.Models.Torque
             set { SetProperty(ref _Z_Position_Stop, value); }
         }
 
-
-
-
         public PlcPoint_Torque()
         {
             Number = 0;

+ 2 - 2
TeamAAS-VM/Services/TorqueService.cs

@@ -101,7 +101,7 @@ namespace TeamAAS_VP.Services
             management = _container.Resolve<Management>();
         }
 
-        public async Task<bool> Throw_Screw_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint)
+        public async Task<bool> Throw_Screw_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint,float speed = 100)
         {
             List<bool> result = new List<bool>();
             var point = new RPoint()
@@ -111,7 +111,7 @@ namespace TeamAAS_VP.Services
                 Z = PlcPoint.TorquePoints[0].Z_Position_Start,
             };
 
-            result.Add(await plc.WriteNodeAsync(addressConfig.Manu_ZAxis_Velocity.Address, (float)99.0));
+            result.Add(await plc.WriteNodeAsync(addressConfig.Manu_ZAxis_Velocity.Address, speed));
 
             float Z_Distance = -(PlcPoint.TorquePoints[0].Z_Position_Start - PlcPoint.TorquePoints[0].Z_Position_Stop);
 

+ 13 - 1
TeamAAS-VM/TeamAAS-VP.csproj

@@ -539,6 +539,8 @@
     <Compile Include="Models\HeadChangeRecord.cs" />
     <Compile Include="Models\NozzleChangeRecord.cs" />
     <Compile Include="Models\NumberStatistics.cs" />
+    <Compile Include="Models\Torque\PickDynamicTestResult.cs" />
+    <Compile Include="Models\Torque\PickScrewAccuracyAnalyzerrConfigModel.cs" />
     <Compile Include="Models\Torque\PlcPoint_Torque.cs" />
     <Compile Include="Models\PhotoCaptureRecord.cs" />
     <Compile Include="Models\ScrewFeederBatchRecord.cs" />
@@ -553,6 +555,7 @@
     </Compile>
     <Compile Include="Services\MesService.cs" />
     <Compile Include="Services\ShiftWatcherService.cs" />
+    <Compile Include="ViewModels\Home\PickScrewAccuracyAnalyzerViewModel.cs" />
     <Compile Include="ViewModels\Product\PlcPointOffserParamsViewModel.cs" />
     <Compile Include="ViewModels\Statistics\HeadChangeRecordQueryViewModel.cs" />
     <Compile Include="ViewModels\Statistics\NozzleChangeRecordQueryViewModel.cs" />
@@ -966,6 +969,9 @@
     <Compile Include="Views\Home\ChangeNozzle.xaml.cs">
       <DependentUpon>ChangeNozzle.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\Home\PickScrewAccuracyAnalyzer.xaml.cs">
+      <DependentUpon>PickScrewAccuracyAnalyzer.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\Home\ShowVisionRender.xaml.cs">
       <DependentUpon>ShowVisionRender.xaml</DependentUpon>
     </Compile>
@@ -1318,6 +1324,10 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\Home\PickScrewAccuracyAnalyzer.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\Home\ShowVisionRender.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -1580,7 +1590,9 @@
       <LastGenOutput>Lang.Designer.cs</LastGenOutput>
       <SubType>Designer</SubType>
     </EmbeddedResource>
-    <EmbeddedResource Include="Resources\Languages\Lang.zh-TW.resx" />
+    <EmbeddedResource Include="Resources\Languages\Lang.zh-TW.resx">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
     <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>

+ 451 - 0
TeamAAS-VM/ViewModels/Home/PickScrewAccuracyAnalyzerViewModel.cs

@@ -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
+
+    }
+}

+ 32 - 7
TeamAAS-VM/ViewModels/Home/TorqueCheckViewModel.cs

@@ -44,6 +44,8 @@ namespace TeamAAS_VP.ViewModels.Home
         IRobotService _robotService;
         IPlcService _plcService;
         TorqueService _torqueService;
+        IDialogService _dialogService;
+
         float Value { get; set; } = 0;
 
         #region 属性
@@ -168,7 +170,11 @@ namespace TeamAAS_VP.ViewModels.Home
         public ObservableCollection<PlcPoint_Torque> Points
         {
             get { return _Points; }
-            set { SetProperty(ref _Points, value); }
+            set
+            {
+                SetProperty(ref _Points, value);
+                AllProductParameter.TorquePoints = Points;
+            }
         }
 
         private TorqueProduceModel _AllProductParameter = new TorqueProduceModel();
@@ -191,7 +197,7 @@ namespace TeamAAS_VP.ViewModels.Home
                 SetProperty(ref _selectedPointInDataGrid, value);
                 // 可以同步到 SelectPoint 属性
                 SelectedPoint = value;
-                AllProductParameter.TorquePoints = _Points;
+                AllProductParameter.TorquePoints = Points;
             }
         }
 
@@ -246,12 +252,16 @@ namespace TeamAAS_VP.ViewModels.Home
         public DelegateCommand SavePointsCommand =>
             _SavePointsCommand ?? (_SavePointsCommand = new DelegateCommand(ExecuteSavePointsCommand));
 
+        private DelegateCommand _PickScrewTestCommand;
+        public DelegateCommand PickScrewTestCommand =>
+            _PickScrewTestCommand ?? (_PickScrewTestCommand = new DelegateCommand(ExecutePickScrewTestCommand));
+
         #endregion
 
         #region 方法
 
         public TorqueCheckViewModel(IEventAggregator ea, IConfigService configService, TorqueService torqueService,
-            IContainerProvider container, IRobotService robotService, IPlcService plcService)
+            IContainerProvider container, IRobotService robotService, IPlcService plcService, IDialogService dialogService)
         {
             _eventAggregator = ea;
             _configService = configService;
@@ -259,12 +269,9 @@ namespace TeamAAS_VP.ViewModels.Home
             _robotService = robotService;
             _plcService = plcService;
             _torqueService = torqueService;
+            _dialogService = dialogService;
             management = _container.Resolve<Management>();
         }
-        bool CanExecuteDeletePointCommand()
-        {
-            return SelectedPointInDataGrid != null;
-        }
 
         void ExecuteCancelCommand()
         {
@@ -604,6 +611,24 @@ namespace TeamAAS_VP.ViewModels.Home
             }
             return false;
         }
+
+        private void ExecutePickScrewTestCommand()
+        {
+            var param = new DialogParameters();
+            param.Add("PickScrewPoint", AllProductParameter);
+            param.Add("Robot", Robot);
+            _dialogService.ShowDialog("PickScrewAccuracyAnalyzer", param, rst =>
+            {
+                //对话框关闭之后的回调函数,可以在这解析结果。
+                ButtonResult result1 = rst.Result;
+
+                if (result1 == ButtonResult.OK)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 1 });
+                }
+            });
+        }
+
         #endregion
 
         public string Title { get; set; } = "扭力点检";

+ 471 - 0
TeamAAS-VM/Views/Home/PickScrewAccuracyAnalyzer.xaml

@@ -0,0 +1,471 @@
+<UserControl x:Class="TeamAAS_VP.Views.Home.PickScrewAccuracyAnalyzer"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:sys="clr-namespace:System;assembly=mscorlib"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Product"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:VisionDynamicAccuracyAnalyzerViewModel}"
+             d:Height="1100"
+             d:Width="1000"
+             MinHeight="500"
+             MinWidth="500"
+             d:Background="White"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}">
+    <b:Interaction.Triggers>
+        <b:EventTrigger EventName="Loaded">
+            <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
+        </b:EventTrigger>
+    </b:Interaction.Triggers>
+    <prism:Dialog.WindowStyle>
+        <Style TargetType="Window">
+            <Setter Property="prism:Dialog.WindowStartupLocation"
+                    Value="CenterScreen" />
+            <Setter Property="AllowDrop"
+                    Value="True" />
+            <Setter Property="ShowInTaskbar"
+                    Value="True" />
+            <Setter Property="MinHeight"
+                    Value="500" />
+            <Setter Property="MinWidth"
+                    Value="500" />
+            <Setter Property="WindowState"
+                    Value="Normal" />
+            <Setter Property="Topmost"
+                    Value="False" />
+        </Style>
+    </prism:Dialog.WindowStyle>
+
+    <UserControl.Resources>
+        <!-- 复用静态测试的样式 -->
+        <Style TargetType="Button"
+               BasedOn="{StaticResource MaterialDesignFlatDarkBgButton}">
+            <Setter Property="Padding"
+                    Value="10 5" />
+            <Setter Property="Margin"
+                    Value="5" />
+            <Setter Property="FontSize"
+                    Value="14" />
+            <Setter Property="BorderThickness"
+                    Value="0" />
+        </Style>
+
+        <Style TargetType="TextBlock">
+            <Setter Property="VerticalAlignment"
+                    Value="Center" />
+            <Setter Property="Margin"
+                    Value="5" />
+        </Style>
+
+        <Style TargetType="TextBox"
+               BasedOn="{StaticResource MaterialDesignTextBox}">
+            <Setter Property="Margin"
+                    Value="5" />
+            <Setter Property="VerticalContentAlignment"
+                    Value="Center" />
+        </Style>
+
+        <Style x:Key="DataGridStyle"
+               TargetType="DataGrid"
+               BasedOn="{StaticResource MaterialDesignDataGrid}">
+            <Setter Property="Margin"
+                    Value="5" />
+            <Setter Property="AutoGenerateColumns"
+                    Value="False" />
+            <Setter Property="CanUserAddRows"
+                    Value="False" />
+            <Setter Property="CanUserDeleteRows"
+                    Value="False" />
+            <Setter Property="IsReadOnly"
+                    Value="True" />
+            <Setter Property="AlternatingRowBackground"
+                    Value="#F5F5F5" />
+        </Style>
+
+        <Style x:Key="TitleStyle"
+               TargetType="TextBlock">
+            <Setter Property="FontSize"
+                    Value="16" />
+            <Setter Property="FontWeight"
+                    Value="Bold" />
+            <Setter Property="Margin"
+                    Value="0 10 0 5" />
+            <Setter Property="Foreground"
+                    Value="#2C3E50" />
+        </Style>
+    </UserControl.Resources>
+    <Grid>
+        <ScrollViewer>
+            <Border Grid.Column="0"
+                    BorderBrush="#BDC3C7"
+                    BorderThickness="0 0 1 0">
+                <Grid>
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="*"
+                                       MinHeight="150" />
+                        <RowDefinition Height="Auto" />
+                    </Grid.RowDefinitions>
+
+                    <!-- 机器人位置 -->
+                    <Border Grid.Row="0"
+                            Background="#ECF0F1"
+                            Padding="10">
+                        <StackPanel>
+                            <TextBlock Style="{StaticResource TitleStyle}"
+                                       Text="机器人位置" />
+
+                            <Grid Margin="0 10 0 0">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                </Grid.RowDefinitions>
+
+                                <Grid Grid.Row="0"
+                                      Margin="0 0 0 10">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="Auto" />
+                                        <ColumnDefinition Width="*" />
+                                        <ColumnDefinition Width="Auto" />
+                                    </Grid.ColumnDefinitions>
+
+                                    <TextBlock Text="取料坐标:"
+                                               Grid.Column="0"
+                                               VerticalAlignment="Center" />
+                                    <TextBox Grid.Column="1"
+                                             d:Text="X:0.000 Y:0.000 Z:0.000"
+                                             ToolTip="机器人A点位置坐标"
+                                             IsReadOnly="True"
+                                             Background="#F8F9FA">
+                                        <TextBox.Text>
+                                            <MultiBinding StringFormat="X:{0:f3} Y:{1:f3} Z:{2:f3}">
+                                                <Binding Path="Points.TorquePoints[1].X_Position" />
+                                                <Binding Path="Points.TorquePoints[1].Y_Position" />
+                                                <Binding Path="Points.TorquePoints[1].Z_Position_Start" />
+                                            </MultiBinding>
+                                        </TextBox.Text>
+                                    </TextBox>
+                                    <!--<Button Grid.Column="2"
+                                            Content="示教"
+                                            Command="{Binding TeachPointACommand}"
+                                            Background="#3498DB"
+                                            Foreground="White"
+                                            Width="60"
+                                            Margin="5,0,0,0" />-->
+                                </Grid>
+
+                                <Grid Grid.Row="1"
+                                      Margin="0 0 0 10">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="Auto" />
+                                        <ColumnDefinition Width="*" />
+                                        <ColumnDefinition Width="Auto" />
+                                    </Grid.ColumnDefinitions>
+
+                                    <TextBlock Text="抛料坐标:"
+                                               Grid.Column="0"
+                                               VerticalAlignment="Center" />
+                                    <TextBox Grid.Column="1"
+                                             d:Text="X:100.000 Y:50.000 Z:0.000"
+                                             ToolTip="机器人B点拍照位置坐标"
+                                             IsReadOnly="True"
+                                             Background="#F8F9FA">
+                                        <TextBox.Text>
+                                            <MultiBinding StringFormat="X:{0:f3} Y:{1:f3} Z:{2:f3}">
+                                                <Binding Path="Points.TorquePoints[0].X_Position" />
+                                                <Binding Path="Points.TorquePoints[0].Y_Position" />
+                                                <Binding Path="Points.TorquePoints[0].Z_Position_Start" />
+                                            </MultiBinding>
+                                        </TextBox.Text>
+                                    </TextBox>
+                                    <!--<Button Grid.Column="2"
+                                            Content="示教"
+                                            Command="{Binding TeachPointBCommand}"
+                                            Background="#3498DB"
+                                            Foreground="White"
+                                            Width="60"
+                                            Margin="5,0,0,0" />-->
+                                </Grid>
+                            </Grid>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 测试参数设置 -->
+                    <Border Grid.Row="1"
+                            Background="#F8F9FA"
+                            Padding="10">
+                        <StackPanel>
+                            <TextBlock Style="{StaticResource TitleStyle}"
+                                       Text="测试参数设置" />
+
+                            <Grid Margin="0 10 0 0">
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition Width="*" />
+                                    <ColumnDefinition Width="*" />
+                                </Grid.ColumnDefinitions>
+
+                                <!-- 重复次数 -->
+                                <StackPanel Grid.Column="0">
+                                    <TextBlock Text="重复次数:" />
+                                    <mah:NumericUpDown Value="{Binding RepeatCount, Mode=TwoWay}"
+                                                       Minimum="1"
+                                                       Maximum="1000"
+                                                       d:Value="50"
+                                                       TextAlignment="Center"
+                                                       HorizontalContentAlignment="Center"
+                                                       HorizontalAlignment="Stretch"
+                                                       IsEnabled="{Binding IsRunning, Converter={StaticResource InvertBooleanConverter}}" />
+                                </StackPanel>
+
+                                <!-- 移动速度 -->
+                                <StackPanel Grid.Column="1"
+                                            Margin="10,0,0,0">
+                                    <TextBlock Text="移动速度(%):" />
+                                    <mah:NumericUpDown Value="{Binding MoveSpeed, Mode=TwoWay}"
+                                                       Minimum="1"
+                                                       Maximum="100"
+                                                       d:Value="50"
+                                                       TextAlignment="Center"
+                                                       HorizontalContentAlignment="Center"
+                                                       HorizontalAlignment="Stretch"
+                                                       IsEnabled="{Binding IsRunning, Converter={StaticResource InvertBooleanConverter}}" />
+                                </StackPanel>
+                            </Grid>
+
+
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 测试控制区域 -->
+                    <Border Grid.Row="2"
+                            Background="#ECF0F1"
+                            Padding="10">
+                        <StackPanel>
+                            <TextBlock Style="{StaticResource TitleStyle}"
+                                       Text="测试控制" />
+
+                            <WrapPanel HorizontalAlignment="Center"
+                                       Margin="0 10 0 0">
+
+                                <!--<Button Content="单次测试"
+                                        Background="#3498DB"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Height="35"
+                                        FontWeight="Bold"
+                                        Command="{Binding SingleTestCommand}"
+                                        IsEnabled="{Binding IsRunning, Converter={StaticResource InvertBooleanConverter}}" />-->
+
+                                <Button Content="连续测试"
+                                        Background="#27AE60"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Height="35"
+                                        FontWeight="Bold"
+                                        Command="{Binding StartTestCommand}" />
+
+                                <Button Content="停止"
+                                        Background="#E74C3C"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Height="35"
+                                        Command="{Binding StopTestCommand}" />
+
+                                <Button Content="暂停"
+                                        Background="#F39C12"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Height="35"
+                                        Command="{Binding PauseTestCommand}" />
+                            </WrapPanel>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 进度显示 -->
+                    <Border Grid.Row="3"
+                            Background="White"
+                            Padding="10">
+                        <StackPanel>
+                            <TextBlock Style="{StaticResource TitleStyle}"
+                                       Text="测试进度" />
+
+                            <Grid Margin="0 10 0 0">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                </Grid.RowDefinitions>
+
+                                <ProgressBar Grid.Row="0"
+                                             Height="25"
+                                             Margin="5"
+                                             Minimum="0"
+                                             Maximum="{Binding RepeatCount}"
+                                             Value="{Binding CurrentProgress}"
+                                             IsEnabled="False"
+                                             d:Maximum="100"
+                                             d:Value="50" />
+
+                                <TextBlock Grid.Row="1"
+                                           HorizontalAlignment="Center"
+                                           FontSize="12"
+                                           Foreground="#7F8C8D"
+                                           d:Text="等待开始..."
+                                           Text="{Binding Message}" />
+                            </Grid>
+
+                            <!-- 实时统计信息 -->
+                            <WrapPanel Margin="0 15 0 0"
+                                       HorizontalAlignment="Center">
+                                <Border Background="#3498DB"
+                                        Padding="10 5"
+                                        Margin="5"
+                                        CornerRadius="3">
+                                    <StackPanel>
+                                        <TextBlock Text="当前循环"
+                                                   Foreground="White"
+                                                   FontSize="11" />
+                                        <TextBlock Text="{Binding CurrentProgress}"
+                                                   d:Text="1"
+                                                   Foreground="White"
+                                                   FontSize="16"
+                                                   FontWeight="Bold"
+                                                   HorizontalAlignment="Center" />
+                                    </StackPanel>
+                                </Border>
+
+                                <Border Background="#2ECC71"
+                                        Padding="10 5"
+                                        Margin="5"
+                                        CornerRadius="3">
+                                    <StackPanel>
+                                        <TextBlock Text="成功率"
+                                                   Foreground="White"
+                                                   FontSize="11" />
+                                        <TextBlock Text="{Binding SuccessRate, StringFormat={}{0:F1}%}"
+                                                   d:Text="100%"
+                                                   Foreground="White"
+                                                   FontSize="16"
+                                                   FontWeight="Bold"
+                                                   HorizontalAlignment="Center" />
+                                    </StackPanel>
+                                </Border>
+
+                                <Border Background="#9B59B6"
+                                        Padding="10 5"
+                                        Margin="5"
+                                        CornerRadius="3">
+                                    <StackPanel>
+                                        <TextBlock Text="往返时间"
+                                                   Foreground="White"
+                                                   FontSize="11" />
+                                        <TextBlock Text="{Binding CycleTime, StringFormat={}{0:F2}s}"
+                                                   d:Text="2.34s"
+                                                   Foreground="White"
+                                                   FontSize="16"
+                                                   FontWeight="Bold"
+                                                   HorizontalAlignment="Center" />
+                                    </StackPanel>
+                                </Border>
+                            </WrapPanel>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 测试结果列表 -->
+                    <Border Grid.Row="4"
+                            Background="White"
+                            Padding="10">
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="*" />
+                            </Grid.RowDefinitions>
+
+                            <StackPanel Grid.Row="0"
+                                        Orientation="Horizontal">
+                                <TextBlock Style="{StaticResource TitleStyle}"
+                                           Text="测试结果列表" />
+                                <TextBlock Margin="10,0,0,0"
+                                           VerticalAlignment="Center"
+                                           Foreground="#7F8C8D"
+                                           Text="(显示最近20次结果)" />
+                            </StackPanel>
+
+                            <DataGrid x:Name="dgResults"
+                                      Grid.Row="1"
+                                      Style="{StaticResource DataGridStyle}"
+                                      MaxHeight="250"
+                                      AutoGenerateColumns="False"
+                                      CanUserAddRows="False"
+                                      IsReadOnly="True"
+                                      ItemsSource="{Binding TestResults}">
+                                <DataGrid.Columns>
+                                    <DataGridTextColumn Header="序号"
+                                                        Binding="{Binding Index}"
+                                                        MinWidth="50" />
+                                    <DataGridTextColumn Header="状态"
+                                                        Binding="{Binding IsPickSuccess}"
+                                                        MinWidth="60" />
+                                    <DataGridTextColumn Header="位置X"
+                                                        Binding="{Binding X_Position, StringFormat={}{0:F3}}"
+                                                        MinWidth="70" />
+                                    <DataGridTextColumn Header="位置Y"
+                                                        Binding="{Binding Y_Position, StringFormat={}{0:F3}}"
+                                                        MinWidth="70" />
+                                    <DataGridTextColumn Header="位置Z"
+                                                        Binding="{Binding Z_Position, StringFormat={}{0:F3}}"
+                                                        MinWidth="70" />
+                                    <DataGridTextColumn Header="循环时间"
+                                                        Binding="{Binding CycleTime, StringFormat={}{0:F2}s}"
+                                                        MinWidth="80" />
+                                    <DataGridTextColumn Header="时间戳"
+                                                        Binding="{Binding Timestamp}"
+                                                        MinWidth="120" />
+                                </DataGrid.Columns>
+                            </DataGrid>
+                        </Grid>
+                    </Border>
+
+                    <!-- 导出和精度分析 -->
+                    <Border Grid.Row="5"
+                            Background="#ECF0F1"
+                            Padding="10">
+                        <StackPanel>
+                            <!-- 导出按钮 -->
+                            <WrapPanel HorizontalAlignment="Right">
+                                <Button Content="导出CSV"
+                                        Background="#3498DB"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Command="{Binding ExportCSVCommand}" />
+
+                                <Button Content="清空数据"
+                                        Background="#95A5A6"
+                                        Foreground="White"
+                                        MinWidth="100"
+                                        Command="{Binding ClearDataCommand}" />
+                            </WrapPanel>
+
+                        </StackPanel>
+                    </Border>
+                </Grid>
+            </Border>
+        </ScrollViewer>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Home/PickScrewAccuracyAnalyzer.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Home
+{
+    /// <summary>
+    /// PickScrewAccuracyAnalyzer.xaml 的交互逻辑
+    /// </summary>
+    public partial class PickScrewAccuracyAnalyzer : UserControl
+    {
+        public PickScrewAccuracyAnalyzer()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 4 - 4
TeamAAS-VM/Views/Home/TorqueCheck.xaml

@@ -99,12 +99,12 @@
                                 Margin="5,2"
                                 MinWidth="80"
                                 materialDesign:ButtonAssist.CornerRadius="5"
-                                Command="{Binding AddPointCommand}" />
-                        <Button Content="{lex:Loc 删除点}"
+                                Command="{Binding AddPointCommand}" />-->
+                        <Button Content="取料测试"
                                 Margin="5,2"
-                                MinWidth="80"
+                                MinWidth="100"
                                 materialDesign:ButtonAssist.CornerRadius="5"
-                                Command="{Binding DeletePointCommand}" />-->
+                                Command="{Binding PickScrewTestCommand}" />
                         <Button Content="{lex:Loc 保存}"
                                 Margin="20"
                                 MinWidth="100"

+ 2 - 2
TeamAAS-VM/Views/SettingView.xaml

@@ -2493,7 +2493,7 @@
                             </Grid>
                         </GroupBox>
 
-                        <GroupBox Header="电批配置"  Width="300">
+                        <GroupBox Header="扭力测量仪配置"  Width="300">
                             <Grid Margin="10">
                                 <Grid.ColumnDefinitions>
                                     <ColumnDefinition Width="auto" />
@@ -2560,7 +2560,7 @@
                                         <materialDesign:PackIcon Kind="ContentSaveCheck"
                                          Margin="0,0,6,0" />
                                         <TextBlock VerticalAlignment="Center"
-                           Text="保存电批配置" />
+                           Text="保存扭力测量仪配置" />
                                     </StackPanel>
                                 </Button>
                             </Grid>