yaoxiaohan 7 months ago
parent
commit
ca03f333b1

+ 115 - 22
TeamAAS-VM/Core/Management.cs

@@ -21,6 +21,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Drawing;
 using System.Drawing;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
@@ -196,7 +197,7 @@ namespace TeamAAS_VP.Core
 
 
         public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
         public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
             IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
             IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
-            ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService, 
+            ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService,
             IMesService mesService)
             IMesService mesService)
         {
         {
             _regionManager = regionManager;
             _regionManager = regionManager;
@@ -352,7 +353,7 @@ namespace TeamAAS_VP.Core
 
 
                 try
                 try
                 {
                 {
-                   // Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
+                    // Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
                     _cameraService.CreateCamera(item.Id, item);
                     _cameraService.CreateCamera(item.Id, item);
                     var camera = _cameraService.GetCamera(item.Id);
                     var camera = _cameraService.GetCamera(item.Id);
                     Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
                     Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
@@ -999,6 +1000,7 @@ namespace TeamAAS_VP.Core
                 addressConfig.In_FixedCameracheckExe.Address,
                 addressConfig.In_FixedCameracheckExe.Address,
                 addressConfig.In_RequestPosition.Address,
                 addressConfig.In_RequestPosition.Address,
                 addressConfig.In_ScrewTeachExe.Address,
                 addressConfig.In_ScrewTeachExe.Address,
+                addressConfig.In_QrCodePhotoRequest.Address,
                 addressConfig.In_PickINC.Address,
                 addressConfig.In_PickINC.Address,
             };
             };
             for (int i = 0; i < 10; i++)
             for (int i = 0; i < 10; i++)
@@ -1090,6 +1092,13 @@ namespace TeamAAS_VP.Core
                     await item.WriteToPlcAddress(addressConfig.Out_IndependentCamer, plc);
                     await item.WriteToPlcAddress(addressConfig.Out_IndependentCamer, plc);
                 }
                 }
             }
             }
+            if (current.QrCodePoints != null && current.QrCodePoints.Count > 0)
+            {
+                foreach (var item in current.QrCodePoints)
+                {
+                    await item.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
+                }
+            }
         }
         }
 
 
         public async Task WriteParameterToPlcAsync()
         public async Task WriteParameterToPlcAsync()
@@ -1142,8 +1151,10 @@ namespace TeamAAS_VP.Core
         /// 零件SN
         /// 零件SN
         /// </summary>
         /// </summary>
         string PartSN = "";
         string PartSN = "";
-
-
+        /// <summary>
+        /// 复检结果
+        /// </summary>
+        string gapString = "";
         /// <summary>
         /// <summary>
         /// 二次定位相机的工具坐标
         /// 二次定位相机的工具坐标
         /// </summary>
         /// </summary>
@@ -1160,10 +1171,11 @@ namespace TeamAAS_VP.Core
         bool _LastFixedCameraPutExe = false;
         bool _LastFixedCameraPutExe = false;
         bool _LastFixedCameracheckExe = false;
         bool _LastFixedCameracheckExe = false;
         Int16[] _LastWorkStart = new Int16[7];
         Int16[] _LastWorkStart = new Int16[7];
+        Int16 _LastQrCodePhotoRequest = 0;
         Int16[] _LastWorkDone = new Int16[7];
         Int16[] _LastWorkDone = new Int16[7];
         Int16 _LastRequestPosition = 0;
         Int16 _LastRequestPosition = 0;
         Int16 _LastPickINC = 0;
         Int16 _LastPickINC = 0;
-        Int16[] _LastMesCheck=new Int16[10];
+        Int16[] _LastMesCheck = new Int16[10];
         DateTime[] _LastMesCheckTime = new DateTime[10];
         DateTime[] _LastMesCheckTime = new DateTime[10];
 
 
         /// <summary>
         /// <summary>
@@ -1687,7 +1699,7 @@ namespace TeamAAS_VP.Core
                                 }
                                 }
                                 else
                                 else
                                 {
                                 {
-                                    
+
                                     await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
                                     await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
                                     return;
                                     return;
                                 }
                                 }
@@ -1960,16 +1972,16 @@ namespace TeamAAS_VP.Core
                             }
                             }
                             if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
                             if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
                             {
                             {
-                                
-                                Vector<double> p1=Vector<double>.Build.Dense(new double[] { visionResults[1].X, visionResults[1].Y });
-                                Vector<double> p2=Vector<double>.Build.Dense(new double[] { visionResults[2].X, visionResults[2].Y });
-                                Vector<double> p3=Vector<double>.Build.Dense(new double[] { visionResults[3].X, visionResults[3].Y });
+
+                                Vector<double> p1 = Vector<double>.Build.Dense(new double[] { visionResults[1].X, visionResults[1].Y });
+                                Vector<double> p2 = Vector<double>.Build.Dense(new double[] { visionResults[2].X, visionResults[2].Y });
+                                Vector<double> p3 = Vector<double>.Build.Dense(new double[] { visionResults[3].X, visionResults[3].Y });
                                 Vector<double> p4 = Vector<double>.Build.Dense(new double[] { visionResults[0].X, visionResults[0].Y });
                                 Vector<double> p4 = Vector<double>.Build.Dense(new double[] { visionResults[0].X, visionResults[0].Y });
 
 
                                 var center = RectangleCenterCalculator.CalculateByPCAWithKnownOrder(new List<Vector<double>> { p1, p2, p3, p4 });
                                 var center = RectangleCenterCalculator.CalculateByPCAWithKnownOrder(new List<Vector<double>> { p1, p2, p3, p4 });
                                 UpCameraPutResults[0].X = (float)center.Center[0];
                                 UpCameraPutResults[0].X = (float)center.Center[0];
                                 UpCameraPutResults[0].Y = (float)center.Center[1];
                                 UpCameraPutResults[0].Y = (float)center.Center[1];
-                                UpCameraPutResults[0].Z= (float)center.MajorAxisAngle;
+                                UpCameraPutResults[0].Z = (float)center.MajorAxisAngle;
                                 SendTaskMessage($"产品拍照结果:X={UpCameraPutResults[0].X},Y={UpCameraPutResults[0].Y},Angle={UpCameraPutResults[0].Z}", MessageLevel.Info);
                                 SendTaskMessage($"产品拍照结果:X={UpCameraPutResults[0].X},Y={UpCameraPutResults[0].Y},Angle={UpCameraPutResults[0].Z}", MessageLevel.Info);
                             }
                             }
                             else
                             else
@@ -2034,12 +2046,12 @@ namespace TeamAAS_VP.Core
                             var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3CheckProcedureId);
                             var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3CheckProcedureId);
                             var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4CheckProcedureId);
                             var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4CheckProcedureId);
 
 
-                            // 执行视觉任务
+                            // 执行视觉任务(复检结果gap)
                             var _cts = new CancellationTokenSource();
                             var _cts = new CancellationTokenSource();
-                            var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, null, _cts.Token, 1, null);
-                            var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, null, _cts.Token, 2, null);
-                            var task3 = _remoteCommandService.ExecutePhotoGetSinglePoint(process3, null, null, _cts.Token, 3, null);
-                            var task4 = _remoteCommandService.ExecutePhotoGetSinglePoint(process4, null, null, _cts.Token, 4, null);
+                            var task1 = _remoteCommandService.ExecutePhotoGetDistance(process1, null, null, _cts.Token, 1, null);
+                            var task2 = _remoteCommandService.ExecutePhotoGetDistance(process2, null, null, _cts.Token, 2, null);
+                            var task3 = _remoteCommandService.ExecutePhotoGetDistance(process3, null, null, _cts.Token, 3, null);
+                            var task4 = _remoteCommandService.ExecutePhotoGetDistance(process4, null, null, _cts.Token, 4, null);
 
 
                             var visionResults = await Task.WhenAll(task1, task2, task3, task4);
                             var visionResults = await Task.WhenAll(task1, task2, task3, task4);
                             if (isDryMode)
                             if (isDryMode)
@@ -2050,12 +2062,14 @@ namespace TeamAAS_VP.Core
                             if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
                             if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
                             {
                             {
                                 SendTaskMessage($"固定相机检测OK", MessageLevel.Debug);
                                 SendTaskMessage($"固定相机检测OK", MessageLevel.Debug);
+                                gapString = $"1-{visionResults[0].distance},2-{visionResults[1].distance},3-{visionResults[2].distance},4-{visionResults[3].distance}";
                                 await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
                                 await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
                                 return;
                                 return;
                             }
                             }
                             else
                             else
                             {
                             {
                                 SendTaskMessage($"固定相机检测NG", MessageLevel.Error);
                                 SendTaskMessage($"固定相机检测NG", MessageLevel.Error);
+                                gapString = $"1-0,2-0,3-0,4-0";
                                 await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
                                 await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
                                 return;
                                 return;
                             }
                             }
@@ -2110,9 +2124,9 @@ namespace TeamAAS_VP.Core
                             ToolCoord toolCoord = new ToolCoord();
                             ToolCoord toolCoord = new ToolCoord();
                             toolCoord.ComputeTool(currentPosition.X, currentPosition.Y, currentPosition.U, UpCameraPutResults[1].X, UpCameraPutResults[1].Y);
                             toolCoord.ComputeTool(currentPosition.X, currentPosition.Y, currentPosition.U, UpCameraPutResults[1].X, UpCameraPutResults[1].Y);
 
 
-                            
+
                             //计算放料角度
                             //计算放料角度
-                            double angle= currentPosition.U - UpCameraPutResults[1].Z + UpCameraPutResults[0].Z;
+                            double angle = currentPosition.U - UpCameraPutResults[1].Z + UpCameraPutResults[0].Z;
 
 
                             //将产品的中心点坐标转换为Tool0下的坐标
                             //将产品的中心点坐标转换为Tool0下的坐标
                             var point = currentProduct.ScrewPoints[0].Clone();
                             var point = currentProduct.ScrewPoints[0].Clone();
@@ -2155,6 +2169,73 @@ namespace TeamAAS_VP.Core
 
 
                     }
                     }
                 }
                 }
+                // PLC请求二维码拍照
+                else if (addressConfig.In_QrCodePhotoRequest.Address.Contains(tuple.nodeId))
+                {
+                    if (tuple.value is Int16 state)
+                    {
+                        if (_LastQrCodePhotoRequest != state)
+                        {
+                            _LastQrCodePhotoRequest = state;
+                        }
+                        else
+                        {
+                            return;
+                        }
+                        if (state == 1)
+                        {
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_QrCodeCamera_ScanNum.Address);
+                            //SendTaskMessage(string.Format("扫码编号", cameraIndex), MessageLevel.Info);
+
+                            Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
+                            //视觉流程ID
+                            var qrCodeProcess = _productService.GetCurrentProductProcedureModelById(qrCodeProcedureId);
+                            if (qrCodeProcess == null)
+                            {
+                                SendTaskMessage($"未找到二维码视觉流程,流程ID: {qrCodeProcedureId}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
+                                return;
+                            }
+
+                            SendTaskMessage($"开始执行二维码扫码视觉流程", MessageLevel.Debug);
+                            var _cts = new CancellationTokenSource();
+
+                            await _remoteCommandService.SetLightBeforePhoto(qrCodeProcess);
+                            var qrCodeResult = _remoteCommandService.ExecutePhoto(qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
+
+                            if (qrCodeResult && outputCollection.Contains("QR"))
+                            {
+                                PartSN = outputCollection["QR"].Value as string;
+                                if (!string.IsNullOrEmpty(PartSN))
+                                {
+                                    SendTaskMessage($"二维码扫码成功:{PartSN}", MessageLevel.Info);
+                                    await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
+                                }
+                                else
+                                {
+                                    PartSN = "";
+                                    SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
+                                    await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
+                                    return;
+                                }
+                            }
+                            else
+                            {
+                                PartSN = "";
+                                SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
+                                return;
+                            }
+                        }
+                        else
+                        {
+                            SendTaskMessage("二维码拍照点位发送信号已关闭", MessageLevel.Alarm);
+                            await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)0);
+                        }
+                    }
+                   
+                }
                 else
                 else
                 {
                 {
                     // 过站检查
                     // 过站检查
@@ -2172,7 +2253,10 @@ namespace TeamAAS_VP.Core
                                 {
                                 {
                                     return;
                                     return;
                                 }
                                 }
-                                var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
+                                //var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
+                                var code = "CN0NJTYVLXU0061W0001";
+                                string comp = "110RNYV4123456789012345";
+                                //询问mes
                                 if (state == 1)
                                 if (state == 1)
                                 {
                                 {
                                     //这里缺少从MES获取产品配方的内容,需要补充
                                     //这里缺少从MES获取产品配方的内容,需要补充
@@ -2181,7 +2265,7 @@ namespace TeamAAS_VP.Core
 
 
                                     LogHelper.WriteLogMes($"【mes开始QUERY】");
                                     LogHelper.WriteLogMes($"【mes开始QUERY】");
                                     SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
                                     SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
-                                    (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "",2);
+                                    (bool isSuccess, string response) = await _mesService.StationGetAsync(code, comp, 2);
                                     if (i == 0)
                                     if (i == 0)
                                     {
                                     {
                                         SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
                                         SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
@@ -2230,7 +2314,8 @@ namespace TeamAAS_VP.Core
                                     }
                                     }
 
 
                                     //读取产品结果
                                     //读取产品结果
-                                    Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address,i));
+                                    Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
+                                    resultIndex = 1;
                                     //读取压力值
                                     //读取压力值
                                     float pressure = plc.ReadNode<float>(string.Format(addressConfig.In_PressureValue.Address, i));
                                     float pressure = plc.ReadNode<float>(string.Format(addressConfig.In_PressureValue.Address, i));
                                     AssemblyRecord assemblyRecord = new AssemblyRecord();
                                     AssemblyRecord assemblyRecord = new AssemblyRecord();
@@ -2278,10 +2363,18 @@ namespace TeamAAS_VP.Core
                                     }
                                     }
 
 
                                     await _systemDatabaseService.RecordAssemblyAsync(assemblyRecord);
                                     await _systemDatabaseService.RecordAssemblyAsync(assemblyRecord);
+                                    var pressureParam = FileHelper.ReadJsonFile<List<PressureModel>>(FilePath.PressureParamterConfigPath);
+                                    var p1 = pressureParam[0];//组装压力
+                                    var p2 = pressureParam[1];//保压压力
 
 
                                     LogHelper.WriteLogMes($"【mes开始ADD】");
                                     LogHelper.WriteLogMes($"【mes开始ADD】");
                                     SendTaskMessage($"mes开始ADD", MessageLevel.Info);
                                     SendTaskMessage($"mes开始ADD", MessageLevel.Info);
-                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(code,"", resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
+                                    string gap = ""; string press = ""; string presstime = ""; string assypress = "";
+                                    gap = gapString;
+                                    press = p2.PressureNum.ToString();
+                                    presstime = p2.PressureTime.ToString();
+                                    assypress = assemblyRecord.AssemblyPressure.ToString();
+                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(code, comp, gap, press, presstime, assypress, resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
                                     if (isSuccess)
                                     if (isSuccess)
                                     {
                                     {
                                         LogHelper.WriteLogMes($"上传mes成功");
                                         LogHelper.WriteLogMes($"上传mes成功");

+ 2 - 2
TeamAAS-VM/Interfaces/IMesService.cs

@@ -63,7 +63,7 @@ namespace TeamAAS_VP.Interfaces
         /// - 若 <paramref name="start_time"/> 晚于 <paramref name="stop_time"/>,实现应记录并视情况返回失败或抛出异常。
         /// - 若 <paramref name="start_time"/> 晚于 <paramref name="stop_time"/>,实现应记录并视情况返回失败或抛出异常。
         /// - 实现应尊重 <paramref name="cancellationToken"/>,并在取消时尽早中止请求。
         /// - 实现应尊重 <paramref name="cancellationToken"/>,并在取消时尽早中止请求。
         /// </remarks>
         /// </remarks>
-        Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
+        Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string gap, string press, string presstime, string assypress, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
 
 
         /// <summary>
         /// <summary>
         /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息,并使用指定的超时时间(秒)。
         /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息,并使用指定的超时时间(秒)。
@@ -82,6 +82,6 @@ namespace TeamAAS_VP.Interfaces
         /// - 此重载用于在不传入 <see cref="CancellationToken"/> 的场景中指定超时时间。
         /// - 此重载用于在不传入 <see cref="CancellationToken"/> 的场景中指定超时时间。
         /// - 实现应确保对时间参数与布尔参数进行适当的 URL 编码或格式化。
         /// - 实现应确保对时间参数与布尔参数进行适当的 URL 编码或格式化。
         /// </remarks>
         /// </remarks>
-        Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, bool isSuccess, DateTime start_time, DateTime stop_time, double timeoutInSeconds);
+        Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string gap, string press, string presstime, string assypress, bool isSuccess, DateTime start_time, DateTime stop_time, double timeoutInSeconds);
     }
     }
 }
 }

+ 14 - 0
TeamAAS-VM/Interfaces/IRemoteCommandService.cs

@@ -241,6 +241,15 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         /// <returns></returns>
         bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection);
         bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection);
 
 
+        /// <summary>
+        /// 执行拍照二维码流程运行
+        /// </summary>
+        /// <param name="procedure"></param>
+        /// <param name="outputCollection"></param>
+        /// <returns></returns>
+        bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection);
+
+
         /// <summary>
         /// <summary>
         /// 执行相机拍照获取单个点位结果
         /// 执行相机拍照获取单个点位结果
         /// </summary>
         /// </summary>
@@ -344,5 +353,10 @@ namespace TeamAAS_VP.Interfaces
         /// <param name="procedure">流程模型</param>
         /// <param name="procedure">流程模型</param>
         /// <returns></returns>
         /// <returns></returns>
         Task TurnOffLightAfterPhoto(ProcedureModel procedure);
         Task TurnOffLightAfterPhoto(ProcedureModel procedure);
+
+        /// <summary>
+        /// 复检结果
+        /// </summary>
+        Task<(bool IsSucceed, string distance)> ExecutePhotoGetDistance(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken, int positionIndex, string remark);
     }
     }
 }
 }

+ 76 - 0
TeamAAS-VM/Models/PLC/PlcAddressConfig.cs

@@ -28,6 +28,26 @@ namespace TeamAAS_VP.Models.PLC
             set { SetProperty(ref _WorkMode, value); }
             set { SetProperty(ref _WorkMode, value); }
         }
         }
 
 
+        private PlcAddress _QrCodePhotoResault = new PlcAddress();
+        /// <summary>
+        /// pc发送二维码拍照点位成功后 =1 失败=2 未执行=0
+        /// </summary>
+        public PlcAddress Out_QrCodePhotoResault
+        {
+            get { return _QrCodePhotoResault; }
+            set { SetProperty(ref _QrCodePhotoResault, value); }
+        }
+
+        private PlcPointAddress _QrCodeCamera = new PlcPointAddress();
+        /// <summary>
+        /// 二维码拍照点位参数
+        /// </summary>
+        public PlcPointAddress Out_QrCodeCamera
+        {
+            get { return _QrCodeCamera; }
+            set { SetProperty(ref _QrCodeCamera, value); }
+        }
+
         private PlcAddress _PickPointNum = new PlcAddress();
         private PlcAddress _PickPointNum = new PlcAddress();
         /// <summary>
         /// <summary>
         /// 取料位置 =0 不需要取料 =1 需要取料
         /// 取料位置 =0 不需要取料 =1 需要取料
@@ -330,6 +350,27 @@ namespace TeamAAS_VP.Models.PLC
         #endregion
         #endregion
 
 
         #region 从PLC读取的地址
         #region 从PLC读取的地址
+
+        private PlcAddress _In_QrCodePhotoRequest = new PlcAddress();
+        /// <summary>
+        /// 二维码拍照请求
+        /// </summary>
+        public PlcAddress In_QrCodePhotoRequest
+        {
+            get { return _In_QrCodePhotoRequest; }
+            set { SetProperty(ref _In_QrCodePhotoRequest, value); }
+        }
+
+        private PlcAddress _In_QrCodeCamera_ScanNum = new PlcAddress();
+        /// <summary>
+        /// 二维码拍照请求
+        /// </summary>
+        public PlcAddress In_QrCodeCamera_ScanNum
+        {
+            get { return _In_QrCodeCamera_ScanNum; }
+            set { SetProperty(ref _In_QrCodeCamera_ScanNum, value); }
+        }
+
         private PlcAddress _In_Code = new PlcAddress();
         private PlcAddress _In_Code = new PlcAddress();
         /// <summary>
         /// <summary>
         /// 产品编码
         /// 产品编码
@@ -667,6 +708,41 @@ namespace TeamAAS_VP.Models.PLC
                 return p;
                 return p;
             }
             }
 
 
+            // Out_QrCodeCamera(二维码拍照点位)初始化并赋地址
+            Out_QrCodeCamera = EnsurePoint(Out_QrCodeCamera);
+            Out_QrCodeCamera.Description = "二维码拍照点位参数";
+            Out_QrCodeCamera.X_Position.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].X_Position";
+            Out_QrCodeCamera.X_Velocity.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].X_Velocity";
+            Out_QrCodeCamera.Y_Position.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Y_Position";
+            Out_QrCodeCamera.Y_Velocity.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Y_Velocity";
+            Out_QrCodeCamera.Z_Position_Start.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Z_Position_Start";
+            Out_QrCodeCamera.Z_Velocity_Start.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Z_Velocity_Start";
+            Out_QrCodeCamera.Z_Position_Stop.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Z_Position_Stop";
+            Out_QrCodeCamera.Z_Velocity_Stop.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Z_Velocity_Stop";
+            Out_QrCodeCamera.U_Position.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].U_Position";
+            Out_QrCodeCamera.U_Velocity.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].U_Velocity";
+            Out_QrCodeCamera.R_Position.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].R_Position";
+            Out_QrCodeCamera.R_Velocity.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].R_Velocity";
+            Out_QrCodeCamera.Torque.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Torque";
+            Out_QrCodeCamera.Feeder.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].Feeder";
+            Out_QrCodeCamera.ScrewProNum.Address = "ns=4;s=DB_Communication|FromPC.Point_Camera_Scan[{0}].ScrewProNum";
+
+            In_QrCodePhotoRequest = Ensure(In_QrCodePhotoRequest);
+            In_QrCodePhotoRequest.Address = "ns=4;s=DB_Communication|ToPC.Camera_ScanExe";
+            In_QrCodePhotoRequest.DataType = "int16";
+            In_QrCodePhotoRequest.Description = "二维码拍照请求";
+
+            In_QrCodeCamera_ScanNum = Ensure(In_QrCodeCamera_ScanNum);
+            In_QrCodeCamera_ScanNum.Address = "ns=4;s=DB_Communication|Camera_ScanNum";
+            In_QrCodeCamera_ScanNum.DataType = "int16";
+            In_QrCodeCamera_ScanNum.Description = "二维码拍照编号";
+
+            Out_QrCodePhotoResault = Ensure(Out_QrCodePhotoResault);
+            Out_QrCodePhotoResault.Address = "ns=4;s=DB_Communication|FromPC.Camera_ScanStatus";
+            Out_QrCodePhotoResault.DataType = "int16";
+            Out_QrCodePhotoResault.Description = "二维码拍照结果";
+
+
             // 2. 按 JSON 提供的数据设置默认值(以当前属性名为准)
             // 2. 按 JSON 提供的数据设置默认值(以当前属性名为准)
             Out_WorkMode = Ensure(Out_WorkMode);
             Out_WorkMode = Ensure(Out_WorkMode);
             Out_WorkMode.Address = "ns=4;s=DB_Communication|FromPC.WorkMode";
             Out_WorkMode.Address = "ns=4;s=DB_Communication|FromPC.WorkMode";

+ 22 - 1
TeamAAS-VM/Models/Product/ProductModel.cs

@@ -166,6 +166,15 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _FixedUpCamera2ProcedureId, value); }
             set { SetProperty(ref _FixedUpCamera2ProcedureId, value); }
         }
         }
 
 
+
+        // 二维码扫码流程ID
+        private Guid _QrCodeProcedureId;
+        public Guid QrCodeProcedureId
+        {
+            get { return _QrCodeProcedureId; }
+            set { SetProperty(ref _QrCodeProcedureId, value); }
+        }
+
         /// <summary>
         /// <summary>
         /// 固定向上的相机模板角度
         /// 固定向上的相机模板角度
         /// </summary>
         /// </summary>
@@ -406,6 +415,16 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _SecPosCameraPoints, value); }
             set { SetProperty(ref _SecPosCameraPoints, value); }
         }
         }
 
 
+        private ObservableCollection<PlcPoint> _QrCodePoints = new ObservableCollection<PlcPoint>();
+        /// <summary>
+        /// 二维码拍照点位参数集合
+        /// </summary>
+        public ObservableCollection<PlcPoint> QrCodePoints
+        {
+            get { return _QrCodePoints; }
+            set { SetProperty(ref _QrCodePoints, value); }
+        }
+
         private ObservableCollection<PlcPoint> _ScrewCameraPoints = new ObservableCollection<PlcPoint>();
         private ObservableCollection<PlcPoint> _ScrewCameraPoints = new ObservableCollection<PlcPoint>();
         /// <summary>
         /// <summary>
         /// 锁附拍照点位参数集合
         /// 锁附拍照点位参数集合
@@ -603,7 +622,9 @@ namespace TeamAAS_VP.Models
                 RemovePoints = this.RemovePoints,
                 RemovePoints = this.RemovePoints,
                 PressurePlacePoints = this.PressurePlacePoints,
                 PressurePlacePoints = this.PressurePlacePoints,
                 IsLoad = this.IsLoad,
                 IsLoad = this.IsLoad,
-                IsCreate = this.IsCreate
+                IsCreate = this.IsCreate,
+                QrCodePoints = this.QrCodePoints,
+
             };
             };
         }
         }
     }
     }

+ 7 - 5
TeamAAS-VM/Services/MesService.cs

@@ -99,11 +99,11 @@ namespace TeamAAS_VP.Services
             string url = "";
             string url = "";
             if (device.F == "PTL")
             if (device.F == "PTL")
             {
             {
-                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&comp={device.comp}:{comp}&p=unit_process_check,model";
+                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&comp={device.comp}:{comp}&p=unit_process_check,message,model";
             }
             }
             else
             else
             {
             {
-                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&p=unit_process_check,model";
+                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&p=unit_process_check,message,model";
             }
             }
 
 
             LogHelper.WriteLogMes($"【询问URL】{url}");
             LogHelper.WriteLogMes($"【询问URL】{url}");
@@ -179,7 +179,7 @@ namespace TeamAAS_VP.Services
         /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
         /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
         /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
         /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
         /// </remarks>
         /// </remarks>
-        public async Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default)
+        public async Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp,string gap,string press,string presstime,string assypress, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default)
         {
         {
             // 如果已经释放,则抛出异常,防止在已释放资源上继续操作。
             // 如果已经释放,则抛出异常,防止在已释放资源上继续操作。
             if (_disposed) throw new ObjectDisposedException(nameof(MesService));
             if (_disposed) throw new ObjectDisposedException(nameof(MesService));
@@ -204,11 +204,13 @@ namespace TeamAAS_VP.Services
             if (device.F == "PTL")
             if (device.F == "PTL")
             {
             {
                 url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PTL&comp={device.comp}:{comp}" +
                 url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PTL&comp={device.comp}:{comp}" +
+                    $"&gap={gap}&pressure={press}&pressure_time={presstime}&assy_pressure={assypress}" +
                     $"&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
                     $"&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
             }
             }
             else
             else
             {
             {
                 url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PQC" +
                 url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PQC" +
+                    $"&gap={gap}&pressure={press}&pressure_time={presstime}&assy_pressure={assypress}" +
                     $"&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
                     $"&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
             }
             }
             LogHelper.WriteLogMes($"【上传URL】{url}");
             LogHelper.WriteLogMes($"【上传URL】{url}");
@@ -258,11 +260,11 @@ namespace TeamAAS_VP.Services
         /// <param name="stop_time">结束时间。</param>
         /// <param name="stop_time">结束时间。</param>
         /// <param name="timeoutInSeconds">请求超时,单位为秒。</param>
         /// <param name="timeoutInSeconds">请求超时,单位为秒。</param>
         /// <returns>与 <see cref="SubmitGetAsync(string, bool, DateTime, DateTime, CancellationToken)"/> 相同的返回语义。</returns>
         /// <returns>与 <see cref="SubmitGetAsync(string, bool, DateTime, DateTime, CancellationToken)"/> 相同的返回语义。</returns>
-        public async Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, bool isSuccess, DateTime start_time, DateTime stop_time, double timeoutInSeconds)
+        public async Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string gap, string press, string presstime, string assypress, bool isSuccess, DateTime start_time, DateTime stop_time, double timeoutInSeconds)
         {
         {
             using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
             using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
             {
             {
-                return await SubmitGetAsync(sn, comp, isSuccess, start_time, stop_time, cts.Token);
+                return await SubmitGetAsync(sn, comp, gap, press, presstime, assypress, isSuccess, start_time, stop_time, cts.Token);
             }
             }
         }
         }
 
 

+ 156 - 0
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -1563,6 +1563,105 @@ namespace TeamAAS_VP.Services
             }
             }
         }
         }
 
 
+        /// <summary>
+        /// 执行拍照二维码流程运行
+        /// </summary>
+        /// <param name="procedure"></param>
+        /// <param name="outputCollection"></param>
+        /// <returns></returns>
+        public bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection)
+        {
+            try
+            {
+                SetLightBeforePhoto(procedure);
+                // 1. 采集图像
+                var camera = _cameraService.GetCamera(procedure.CameraId);
+                bool succed = camera.SetExposureTime(procedure.ExposureTime);
+                if (!succed)
+                {
+                    SendTaskMessage("相机曝光设置失败", MessageLevel.Error);
+                }
+                succed = camera.SetGain(procedure.Gain);
+                if (!succed)
+                {
+                    SendTaskMessage("相机增益设置失败", MessageLevel.Error);
+                }
+                DateTime nowtime = DateTime.Now;
+                LogHelper.WriteLogInfo("开始采集图像");
+                var image = camera.Grab();
+                if (image == null)
+                {
+
+                    SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
+                    outputCollection = null;
+                    return false;
+                }
+                procedure.ToolBlock.Inputs["InputImage"].Value = image;
+                LogHelper.WriteLogInfo(string.Format("采集图像完成用时0ms", (DateTime.Now - nowtime).Milliseconds));
+
+                // 3. 运行视觉工具
+                LogHelper.WriteLogInfo("开始运行视觉工具");
+                procedure.ToolBlock.Run();      //运行ToolBlock
+
+                if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
+                {
+                    SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
+                    outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                    DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
+                    ICogRecord record = null;
+                    foreach (CogToolBlockTerminal item in outputCollection)
+                    {
+                        if (item.Value is ICogRecord)
+                            record = item.Value as ICogRecord;
+                    }
+                    _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
+                    {
+                        Id = procedure.Id,
+                        Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
+                        Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
+                        Record = record,
+                        Result = (bool)(outputCollection["Found"].Value),
+                        IsShow = true,
+                        IsSaveImage = procedure.IsSaveImage,
+                        SaveImageModel = procedure.SaveImageModel,
+                        SaveImagePathModel = procedure.SaveImagePathModel,
+                        SavePath = procedure.SavePath,
+                        IsCompress = procedure.IsCompress,
+                        ProceductName = procedure.Name
+                    });
+                    SendTaskMessage($"{procedure.CameraName},{procedure.CameraId}", MessageLevel.Info);
+                    return true;
+                }
+                else
+                {
+                    SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
+                    SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
+                    outputCollection = null;
+                    _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
+                    {
+                        Id = procedure.Id,
+                        Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
+                        Graphic = new CogGraphicCollection(),
+                        Result = false,
+                        IsShow = true,
+                        IsSaveImage = procedure.IsSaveImage,
+                        SaveImageModel = procedure.SaveImageModel,
+                        SaveImagePathModel = procedure.SaveImagePathModel,
+                        SavePath = procedure.SavePath,
+                        ProceductName = procedure.Name,
+                    });
+                    return false;
+                }
+            }
+            catch (Exception ex)
+            {
+                SendTaskMessage(ex.Message, MessageLevel.Error);
+                LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错", ex);
+                outputCollection = null;
+                return false;
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs、图像和图形集合。
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs、图像和图形集合。
         /// </summary>
         /// </summary>
@@ -1760,6 +1859,63 @@ namespace TeamAAS_VP.Services
             }
             }
         }
         }
 
 
+        /// <summary>
+        /// 获取复检结果
+        /// </summary>
+        /// <param name="procedure"></param>
+        /// <param name="InputTerminal"></param>
+        /// <param name="robotCoord"></param>
+        /// <param name="cancellationToken"></param>
+        /// <param name="positionIndex"></param>
+        /// <param name="remark"></param>
+        /// <returns></returns>
+        public async Task<(bool IsSucceed, string distance)> ExecutePhotoGetDistance(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken, int positionIndex, string remark)
+        {
+            DateTime nowtime = DateTime.Now;
+            await SetLightBeforePhoto(procedure);
+            try
+            {
+                //拍照失败时,需要多次拍照
+                for (int i = 0; i < procedure.FeederFailLimit; i++)
+                {
+                    SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
+
+                    // 1. 执行相机拍照并运行视觉工具
+                    bool visionSucceed = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
+                    if (!visionSucceed)
+                    {
+                        SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
+                        continue;
+                    }
+
+                    if (!outputCollection.Contains("Found"))
+                    {
+                        SendTaskMessage(Lang.未找到视觉输出结果, MessageLevel.Error);
+                        await RecordPhotoCaptureAsync(procedure, robotCoord, false, new double[] { 0, 0, 0 }, new double[] { 0, 0, 0 }, string.Empty, positionIndex, remark);
+                        return (false, "");
+                    }
+
+                    LogHelper.WriteLogInfo("开始获取视觉输出结果");
+                    string dis = (string)(outputCollection["Gap"].Value);
+                    return (true, dis);
+                }
+                SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
+                await RecordPhotoCaptureAsync(procedure, robotCoord, false, new double[] { 0, 0, 0 }, new double[] { 0, 0, 0 }, string.Empty, positionIndex, remark);
+                return (false, "");
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("执行相机取图并获取单点位时出错!", ex);
+                await RecordPhotoCaptureAsync(procedure, robotCoord, false, new double[] { 0, 0, 0 }, new double[] { 0, 0, 0 }, string.Empty, positionIndex, remark);
+                return (false, "");
+            }
+            finally
+            {
+                await TurnOffLightAfterPhoto(procedure);
+
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// 记录拍照结果数据至数据库
         /// 记录拍照结果数据至数据库
         /// </summary>
         /// </summary>

+ 7 - 0
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -352,6 +352,7 @@ namespace TeamAAS_VP.ViewModels.Product
             public List<PlcPoint> CheckCameraPoints { get; set; }
             public List<PlcPoint> CheckCameraPoints { get; set; }
             public List<PlcPoint> IndependentCamerPoints { get; set; }
             public List<PlcPoint> IndependentCamerPoints { get; set; }
             public List<PlcPoint> RemovePoints { get; set; }
             public List<PlcPoint> RemovePoints { get; set; }
+            public List<PlcPoint> QrCodePoints { get; set; }
             public List<PlcPoint> PressurePlacePoints { get; set; }
             public List<PlcPoint> PressurePlacePoints { get; set; }
         }
         }
         #endregion
         #endregion
@@ -957,6 +958,9 @@ namespace TeamAAS_VP.ViewModels.Product
                 case 8:
                 case 8:
                     Points = SelectProduct.PressurePlacePoints;
                     Points = SelectProduct.PressurePlacePoints;
                     break;
                     break;
+                case 9:
+                    Points = SelectProduct.QrCodePoints;
+                    break;
                 default:
                 default:
                     break;
                     break;
             }
             }
@@ -2104,6 +2108,7 @@ namespace TeamAAS_VP.ViewModels.Product
                     SecPosCameraPoints = SelectProduct.SecPosCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     SecPosCameraPoints = SelectProduct.SecPosCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     ScrewCameraPoints = SelectProduct.ScrewCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     ScrewCameraPoints = SelectProduct.ScrewCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     ScrewCameraLocalPos1 = SelectProduct.ScrewCameraLocalPos1?.Clone() ?? new PlcPoint(),
                     ScrewCameraLocalPos1 = SelectProduct.ScrewCameraLocalPos1?.Clone() ?? new PlcPoint(),
+                    QrCodePoints = SelectProduct.QrCodePoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     ScrewCameraLocalPos2 = SelectProduct.ScrewCameraLocalPos2?.Clone() ?? new PlcPoint(),
                     ScrewCameraLocalPos2 = SelectProduct.ScrewCameraLocalPos2?.Clone() ?? new PlcPoint(),
                     ScrewPoints = SelectProduct.ScrewPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     ScrewPoints = SelectProduct.ScrewPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     CheckCameraPoints = SelectProduct.CheckCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
                     CheckCameraPoints = SelectProduct.CheckCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
@@ -2173,6 +2178,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 SelectProduct.PickPoints = new ObservableCollection<PlcPoint>(import.PickPoints ?? new List<PlcPoint>());
                 SelectProduct.PickPoints = new ObservableCollection<PlcPoint>(import.PickPoints ?? new List<PlcPoint>());
                 SelectProduct.SecPosCameraPoints = new ObservableCollection<PlcPoint>(import.SecPosCameraPoints ?? new List<PlcPoint>());
                 SelectProduct.SecPosCameraPoints = new ObservableCollection<PlcPoint>(import.SecPosCameraPoints ?? new List<PlcPoint>());
                 SelectProduct.ScrewCameraPoints = new ObservableCollection<PlcPoint>(import.ScrewCameraPoints ?? new List<PlcPoint>());
                 SelectProduct.ScrewCameraPoints = new ObservableCollection<PlcPoint>(import.ScrewCameraPoints ?? new List<PlcPoint>());
+                SelectProduct.QrCodePoints = new ObservableCollection<PlcPoint>(import.QrCodePoints ?? new List<PlcPoint>());
                 SelectProduct.ScrewCameraLocalPos1 = import.ScrewCameraLocalPos1 ?? new PlcPoint();
                 SelectProduct.ScrewCameraLocalPos1 = import.ScrewCameraLocalPos1 ?? new PlcPoint();
                 SelectProduct.ScrewCameraLocalPos2 = import.ScrewCameraLocalPos2 ?? new PlcPoint();
                 SelectProduct.ScrewCameraLocalPos2 = import.ScrewCameraLocalPos2 ?? new PlcPoint();
                 SelectProduct.ScrewPoints = new ObservableCollection<PlcPoint>(import.ScrewPoints ?? new List<PlcPoint>());
                 SelectProduct.ScrewPoints = new ObservableCollection<PlcPoint>(import.ScrewPoints ?? new List<PlcPoint>());
@@ -2195,6 +2201,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 renumber(SelectProduct.IndependentCamerPoints);
                 renumber(SelectProduct.IndependentCamerPoints);
                 renumber(SelectProduct.RemovePoints);
                 renumber(SelectProduct.RemovePoints);
                 renumber(SelectProduct.PressurePlacePoints);
                 renumber(SelectProduct.PressurePlacePoints);
+                renumber(SelectProduct.QrCodePoints);
 
 
                 // 根据当前 SelectedIndex 切换 Points 绑定到对应集合
                 // 根据当前 SelectedIndex 切换 Points 绑定到对应集合
                 ExecuteSelectionChangedCommand();
                 ExecuteSelectionChangedCommand();

+ 1 - 0
TeamAAS-VM/ViewModels/Product/ProductHomeViewModel.cs

@@ -208,6 +208,7 @@ namespace TeamAAS_VP.ViewModels.Product
                         RemovePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         RemovePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         PressurePlacePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         PressurePlacePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         IndependentCamerPoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         IndependentCamerPoints = new ObservableCollection<Models.PLC.PlcPoint>(),
+                        QrCodePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                     };
                     };
 
 
                     var cameras = _configService.GetAllCameras();
                     var cameras = _configService.GetAllCameras();

+ 23 - 1
TeamAAS-VM/ViewModels/Product/ProductParamsViewModel.cs

@@ -102,6 +102,23 @@ namespace TeamAAS_VP.ViewModels.Product
             }
             }
         }
         }
 
 
+        private ProcedureModel _QrCodePhotoProcedure;
+        /// <summary>
+        /// 移动向下扫码拍照流程ID
+        /// </summary>
+        public ProcedureModel QrCodePhotoProcedure
+        {
+            get { return _QrCodePhotoProcedure; }
+            set
+            {
+                SetProperty(ref _QrCodePhotoProcedure, value);
+                if (value != null)
+                {
+                    SelectProduct.QrCodeProcedureId = value.Id;
+                }
+            }
+        }
+
         private ProcedureModel _FixedDownCamera1Procedure;
         private ProcedureModel _FixedDownCamera1Procedure;
         /// <summary>
         /// <summary>
         /// 固定向下相机1取料流程ID
         /// 固定向下相机1取料流程ID
@@ -408,6 +425,8 @@ namespace TeamAAS_VP.ViewModels.Product
             }
             }
         }
         }
 
 
+
+
         #endregion
         #endregion
 
 
         #region 命令
         #region 命令
@@ -574,7 +593,10 @@ namespace TeamAAS_VP.ViewModels.Product
             {
             {
                 SelectProduct.IndependentCamer4CheckProcedureId = Guid.Empty;
                 SelectProduct.IndependentCamer4CheckProcedureId = Guid.Empty;
             }
             }
-
+            if (SelectProduct.QrCodeProcedureId != Guid.Empty)
+            {
+                QrCodePhotoProcedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.QrCodeProcedureId);
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 12 - 0
TeamAAS-VM/Views/Product/PlcPointParams.xaml

@@ -329,6 +329,18 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="压力组装点位" />
                                 <TextBlock Text="压力组装点位" />
                             </ListBoxItem>
                             </ListBoxItem>
+                            <ListBoxItem>
+                                <ListBoxItem.Style>
+                                    <Style TargetType="ListBoxItem"
+                                           BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
+                                        <Setter Property="materialDesign:NavigationBarAssist.SelectedIcon"
+                                                Value="Circle" />
+                                        <Setter Property="materialDesign:NavigationBarAssist.UnselectedIcon"
+                                                Value="CircleOutline" />
+                                    </Style>
+                                </ListBoxItem.Style>
+                                <TextBlock Text="二维码拍照点位" />
+                            </ListBoxItem>
                         </ListBox>
                         </ListBox>
                         <!--点位列表操作按钮面板-->
                         <!--点位列表操作按钮面板-->
                         <StackPanel DockPanel.Dock="Bottom"
                         <StackPanel DockPanel.Dock="Bottom"

+ 24 - 0
TeamAAS-VM/Views/Product/ProductParams.xaml

@@ -135,6 +135,7 @@
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
+                        <RowDefinition Height="auto" />
                     </Grid.RowDefinitions>
                     </Grid.RowDefinitions>
                     <Grid.ColumnDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="auto" />
                         <ColumnDefinition Width="auto" />
@@ -708,6 +709,29 @@
                             </DataTemplate>
                             </DataTemplate>
                         </ComboBox.ItemTemplate>
                         </ComboBox.ItemTemplate>
                     </ComboBox>
                     </ComboBox>
+                    <!--相机扫码拍照流程-->
+                    <TextBlock Grid.Row="21"
+                               Grid.Column="0"
+                               Text="相机扫码拍照流程ID" />
+                    <ComboBox Grid.Row="21"
+                              Grid.Column="1"
+                              ItemsSource="{Binding ProcedureModels}"
+                              SelectedItem="{Binding QrCodePhotoProcedure}"
+                              materialDesign:TextFieldAssist.HasClearButton="True"
+                              materialDesign:HintAssist.Hint="{lex:Loc 选择需要配置的流程}">
+                        <ComboBox.ItemTemplate>
+                            <DataTemplate>
+                                <StackPanel Orientation="Horizontal">
+                                    <materialDesign:PackIcon Kind="VideoOutline" />
+                                    <TextBlock Text="{Binding CameraName}"
+                                               Margin="6,0" />
+                                    <materialDesign:PackIcon Kind="ProgressWrench" />
+                                    <TextBlock Text="{Binding Name}"
+                                               Margin="6,0" />
+                                </StackPanel>
+                            </DataTemplate>
+                        </ComboBox.ItemTemplate>
+                    </ComboBox>
                 </Grid>
                 </Grid>
             </Grid>
             </Grid>