yaoxiaohan 7 tháng trước cách đây
mục cha
commit
ca03f333b1

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

@@ -21,6 +21,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Drawing;
 using System.IO;
 using System.Linq;
@@ -196,7 +197,7 @@ namespace TeamAAS_VP.Core
 
         public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
             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)
         {
             _regionManager = regionManager;
@@ -352,7 +353,7 @@ namespace TeamAAS_VP.Core
 
                 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);
                     var camera = _cameraService.GetCamera(item.Id);
                     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_RequestPosition.Address,
                 addressConfig.In_ScrewTeachExe.Address,
+                addressConfig.In_QrCodePhotoRequest.Address,
                 addressConfig.In_PickINC.Address,
             };
             for (int i = 0; i < 10; i++)
@@ -1090,6 +1092,13 @@ namespace TeamAAS_VP.Core
                     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()
@@ -1142,8 +1151,10 @@ namespace TeamAAS_VP.Core
         /// 零件SN
         /// </summary>
         string PartSN = "";
-
-
+        /// <summary>
+        /// 复检结果
+        /// </summary>
+        string gapString = "";
         /// <summary>
         /// 二次定位相机的工具坐标
         /// </summary>
@@ -1160,10 +1171,11 @@ namespace TeamAAS_VP.Core
         bool _LastFixedCameraPutExe = false;
         bool _LastFixedCameracheckExe = false;
         Int16[] _LastWorkStart = new Int16[7];
+        Int16 _LastQrCodePhotoRequest = 0;
         Int16[] _LastWorkDone = new Int16[7];
         Int16 _LastRequestPosition = 0;
         Int16 _LastPickINC = 0;
-        Int16[] _LastMesCheck=new Int16[10];
+        Int16[] _LastMesCheck = new Int16[10];
         DateTime[] _LastMesCheckTime = new DateTime[10];
 
         /// <summary>
@@ -1687,7 +1699,7 @@ namespace TeamAAS_VP.Core
                                 }
                                 else
                                 {
-                                    
+
                                     await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
                                     return;
                                 }
@@ -1960,16 +1972,16 @@ namespace TeamAAS_VP.Core
                             }
                             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 });
 
                                 var center = RectangleCenterCalculator.CalculateByPCAWithKnownOrder(new List<Vector<double>> { p1, p2, p3, p4 });
                                 UpCameraPutResults[0].X = (float)center.Center[0];
                                 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);
                             }
                             else
@@ -2034,12 +2046,12 @@ namespace TeamAAS_VP.Core
                             var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3CheckProcedureId);
                             var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4CheckProcedureId);
 
-                            // 执行视觉任务
+                            // 执行视觉任务(复检结果gap)
                             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);
                             if (isDryMode)
@@ -2050,12 +2062,14 @@ namespace TeamAAS_VP.Core
                             if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
                             {
                                 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);
                                 return;
                             }
                             else
                             {
                                 SendTaskMessage($"固定相机检测NG", MessageLevel.Error);
+                                gapString = $"1-0,2-0,3-0,4-0";
                                 await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
                                 return;
                             }
@@ -2110,9 +2124,9 @@ namespace TeamAAS_VP.Core
                             ToolCoord toolCoord = new ToolCoord();
                             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下的坐标
                             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
                 {
                     // 过站检查
@@ -2172,7 +2253,10 @@ namespace TeamAAS_VP.Core
                                 {
                                     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)
                                 {
                                     //这里缺少从MES获取产品配方的内容,需要补充
@@ -2181,7 +2265,7 @@ namespace TeamAAS_VP.Core
 
                                     LogHelper.WriteLogMes($"【mes开始QUERY】");
                                     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)
                                     {
                                         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));
                                     AssemblyRecord assemblyRecord = new AssemblyRecord();
@@ -2278,10 +2363,18 @@ namespace TeamAAS_VP.Core
                                     }
 
                                     await _systemDatabaseService.RecordAssemblyAsync(assemblyRecord);
+                                    var pressureParam = FileHelper.ReadJsonFile<List<PressureModel>>(FilePath.PressureParamterConfigPath);
+                                    var p1 = pressureParam[0];//组装压力
+                                    var p2 = pressureParam[1];//保压压力
 
                                     LogHelper.WriteLogMes($"【mes开始ADD】");
                                     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)
                                     {
                                         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="cancellationToken"/>,并在取消时尽早中止请求。
         /// </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>
         /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息,并使用指定的超时时间(秒)。
@@ -82,6 +82,6 @@ namespace TeamAAS_VP.Interfaces
         /// - 此重载用于在不传入 <see cref="CancellationToken"/> 的场景中指定超时时间。
         /// - 实现应确保对时间参数与布尔参数进行适当的 URL 编码或格式化。
         /// </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>
         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>
@@ -344,5 +353,10 @@ namespace TeamAAS_VP.Interfaces
         /// <param name="procedure">流程模型</param>
         /// <returns></returns>
         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); }
         }
 
+        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();
         /// <summary>
         /// 取料位置 =0 不需要取料 =1 需要取料
@@ -330,6 +350,27 @@ namespace TeamAAS_VP.Models.PLC
         #endregion
 
         #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();
         /// <summary>
         /// 产品编码
@@ -667,6 +708,41 @@ namespace TeamAAS_VP.Models.PLC
                 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 提供的数据设置默认值(以当前属性名为准)
             Out_WorkMode = Ensure(Out_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); }
         }
 
+
+        // 二维码扫码流程ID
+        private Guid _QrCodeProcedureId;
+        public Guid QrCodeProcedureId
+        {
+            get { return _QrCodeProcedureId; }
+            set { SetProperty(ref _QrCodeProcedureId, value); }
+        }
+
         /// <summary>
         /// 固定向上的相机模板角度
         /// </summary>
@@ -406,6 +415,16 @@ namespace TeamAAS_VP.Models
             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>();
         /// <summary>
         /// 锁附拍照点位参数集合
@@ -603,7 +622,9 @@ namespace TeamAAS_VP.Models
                 RemovePoints = this.RemovePoints,
                 PressurePlacePoints = this.PressurePlacePoints,
                 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 = "";
             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
             {
-                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}");
@@ -179,7 +179,7 @@ namespace TeamAAS_VP.Services
         /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
         /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
         /// </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));
@@ -204,11 +204,13 @@ namespace TeamAAS_VP.Services
             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}" +
+                    $"&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")}";
             }
             else
             {
                 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")}";
             }
             LogHelper.WriteLogMes($"【上传URL】{url}");
@@ -258,11 +260,11 @@ namespace TeamAAS_VP.Services
         /// <param name="stop_time">结束时间。</param>
         /// <param name="timeoutInSeconds">请求超时,单位为秒。</param>
         /// <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)))
             {
-                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>
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs、图像和图形集合。
         /// </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>

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

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

@@ -208,6 +208,7 @@ namespace TeamAAS_VP.ViewModels.Product
                         RemovePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         PressurePlacePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                         IndependentCamerPoints = new ObservableCollection<Models.PLC.PlcPoint>(),
+                        QrCodePoints = new ObservableCollection<Models.PLC.PlcPoint>(),
                     };
 
                     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;
         /// <summary>
         /// 固定向下相机1取料流程ID
@@ -408,6 +425,8 @@ namespace TeamAAS_VP.ViewModels.Product
             }
         }
 
+
+
         #endregion
 
         #region 命令
@@ -574,7 +593,10 @@ namespace TeamAAS_VP.ViewModels.Product
             {
                 SelectProduct.IndependentCamer4CheckProcedureId = Guid.Empty;
             }
-
+            if (SelectProduct.QrCodeProcedureId != Guid.Empty)
+            {
+                QrCodePhotoProcedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.QrCodeProcedureId);
+            }
         }
 
         /// <summary>

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

@@ -329,6 +329,18 @@
                                 </ListBoxItem.Style>
                                 <TextBlock Text="压力组装点位" />
                             </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>
                         <!--点位列表操作按钮面板-->
                         <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" />
                     </Grid.RowDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="auto" />
@@ -708,6 +709,29 @@
                             </DataTemplate>
                         </ComboBox.ItemTemplate>
                     </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>