ソースを参照

多相机视觉流程配置与调用链路优化

实现产品参数界面多相机视觉流程的灵活配置,产品模型与服务层新增流程ID属性与查找方法,管理层支持按配置动态调用视觉流程,远程命令服务支持单点视觉任务执行。为多相机协作与流程切换奠定基础。
孝锋 徐 8 ヶ月 前
コミット
953befdf01

+ 117 - 8
TeamAAS-VM/Core/Management.cs

@@ -18,6 +18,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
+using System.Drawing;
 using System.IO;
 using System.Linq;
 using System.Net.Sockets;
@@ -299,7 +300,7 @@ namespace TeamAAS_VP.Core
             }
             catch (Exception ex)
             {
-                LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错",ex);
+                LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错", ex);
             }
             if (sb.Length == 0)
             {
@@ -905,16 +906,16 @@ namespace TeamAAS_VP.Core
             var addressConfig = _configService.GetPlcAddresses();
             var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
             if (plc == null || !plc.IsConnected) return;
-            var current= _productService.GetCurrentProduct();
+            var current = _productService.GetCurrentProduct();
             if (current == null) return;
-            if (current.PickCameraPoints!=null && current.PickCameraPoints.Count>0)
+            if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
             {
                 foreach (var item in current.PickCameraPoints)
                 {
-                    await item.WriteToPlcAddress(addressConfig.Out_PickCamera,plc);
+                    await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
                 }
             }
-            
+
             if (current.PickPoints != null && current.PickPoints.Count > 0)
             {
                 foreach (var item in current.PickPoints)
@@ -953,6 +954,9 @@ namespace TeamAAS_VP.Core
             }
         }
 
+        PointF[] DowmCameraResults= new PointF[10];
+        PointF[] UpCameraPutResults = new PointF[10];
+
         /// <summary>
         /// PLC命令触发时
         /// </summary>
@@ -964,6 +968,8 @@ namespace TeamAAS_VP.Core
                 var addressConfig = _configService.GetPlcAddresses();
                 var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
                 if (plc == null || !plc.IsConnected) return;
+                // 获取当前产品
+                var currentProduct = _productService.GetCurrentProduct();
 
                 // 触发下相机拍照
                 if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
@@ -973,6 +979,33 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发下相机拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_DowmCameraNum.Address);
+
+                            // 获取流程
+                            var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
+                            if (process == null)
+                            {
+                                SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
+                                return;
+                            }
+
+                            // 执行视觉任务
+                            var _cts = new CancellationTokenSource();
+                            var visionResult = _remoteCommandService.ExecutePhotoGetSinglePoint(process, null,null, _cts.Token);
+                            if (visionResult.IsSucceed)
+                            {
+                                DowmCameraResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
+                                await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
+                            }
+                            else
+                            {
+                                await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
+                            }
+
+                            //_remoteCommandService.ExecuteNormalVisionTaskAsync()
+
                             await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
                         }
                         else
@@ -990,6 +1023,10 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发上相机取料拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPickNum.Address);
+
+
                             await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
                         }
                         else
@@ -1007,7 +1044,43 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发上相机锁附/组装拍照...", MessageLevel.Debug);
-                            await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
+                            //相机的编号
+                            Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_UpCameraPutNum.Address);
+
+                            // 获取流程
+                            var process = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCameraLockPhotoProcedureId);
+                            if (process == null)
+                            {
+                                SendTaskMessage($"未找到上相机锁附/组装拍照对应的视觉流程,流程ID:{currentProduct.MoveDownCameraLockPhotoProcedureId}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
+                                return;
+                            }
+
+                            // 获取机器人当前坐标
+                            var robot = _robotService.GetAllRobots().FirstOrDefault();
+                            if (robot == null)
+                            {
+                                SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
+                                return;
+
+                            }
+                            var currentPosition = robot.GetRobotPos();
+
+                            // 执行视觉任务
+                            var _cts = new CancellationTokenSource();
+                            var visionResult = _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X , currentPosition.Y, currentPosition.U}, _cts.Token);
+                            if (visionResult.IsSucceed)
+                            {
+                                UpCameraPutResults[cameraIndex]=new PointF((float)visionResult.X, (float)visionResult.Y);
+
+                                
+                                await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
+                            }
+                            else
+                            {
+                                await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
+                            }
                         }
                         else
                         {
@@ -1024,6 +1097,11 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发上相机检测拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.Out_UPCameracheckNum.Address);
+
+
+
                             await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
                         }
                         else
@@ -1041,6 +1119,11 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发固定相机取料拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPickNum.Address);
+
+
+
                             await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
                         }
                         else
@@ -1058,6 +1141,10 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发固定相机锁附/组装拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPutNum.Address);
+
+
                             await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)1);
                         }
                         else
@@ -1075,6 +1162,10 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
+                            //相机的编号
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
+
+
                             await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
                         }
                         else
@@ -1092,7 +1183,9 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"收到开始锁付信号...", MessageLevel.Debug);
-                            // 这里保留扩展点:可在此添加写 PLC 或启动工作流程的代码
+                            //位置编号
+                            //Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
+
                         }
                         else
                         {
@@ -1109,7 +1202,9 @@ namespace TeamAAS_VP.Core
                         if (state)
                         {
                             SendTaskMessage($"收到停止锁付信号...", MessageLevel.Debug);
-                            // 停止动作的处理点
+                            //位置编号
+                            //Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
+                            
                         }
                         else
                         {
@@ -1125,6 +1220,20 @@ namespace TeamAAS_VP.Core
                         if (state == 1)
                         {
                             SendTaskMessage($"收到多相机坐标合并请求,开始合并...", MessageLevel.Debug);
+                            //是拍一个锁一个还是拍两个点锁所有
+                            var systemConfig = _configService.GetSystemConfiguration();
+                            //拍1打1 
+                            if (systemConfig.WorkMode == 1)
+                            {
+                                currentProduct.ScrewPoints[0].X_Position = UpCameraPutResults[1].X;
+                                currentProduct.ScrewPoints[0].Y_Position = UpCameraPutResults[1].Y;
+                                await currentProduct.ScrewPoints[0].WriteToPlcAddress(addressConfig.Out_Screw, plc);
+                            }
+                            //拍1打所有
+                            else if (systemConfig.WorkMode == 2)
+                            {
+
+                            }
                             await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
                         }
                         else

+ 8 - 0
TeamAAS-VM/Interfaces/IProductService.cs

@@ -392,5 +392,13 @@ namespace TeamAAS_VP.Interfaces
         /// <param name="prcname"></param>
         /// <returns></returns>
         Task<bool> LoadProcedureVisionToolsAsync(Guid productid, Guid cameraid, string prcname);
+
+        /// <summary>
+        /// 获取当前产品的指定视觉流程ID的视觉流程对象
+        /// </summary>
+        /// <param name="procedureId"></param>
+        /// <returns></returns>
+        ProcedureModel GetCurrentProductProcedureModelById(Guid procedureId);
+
     }
 }

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

@@ -240,6 +240,16 @@ 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="InputTerminal"></param>
+        /// <param name="robotCoord"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        (bool IsSucceed, double X, double Y, double U) ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken);
+
         /// <summary>
         /// 获取需要输出项
         /// </summary>

+ 40 - 0
TeamAAS-VM/Models/Product/ProductModel.cs

@@ -146,6 +146,46 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _IsUserUpCamera, value); }
         }
 
+        private Guid _FixedUpCamera1ProcedureId;
+        /// <summary>
+        /// 固定向上相机1视觉流程ID
+        /// </summary>
+        public Guid FixedUpCamera1ProcedureId
+        {
+            get { return _FixedUpCamera1ProcedureId; }
+            set { SetProperty(ref _FixedUpCamera1ProcedureId, value); }
+        }
+
+        private Guid _FixedUpCamera2ProcedureId;
+        /// <summary>
+        /// 固定向上相机2视觉流程ID
+        /// </summary>
+        public Guid FixedUpCamera2ProcedureId
+        {
+            get { return _FixedUpCamera2ProcedureId; }
+            set { SetProperty(ref _FixedUpCamera2ProcedureId, value); }
+        }
+
+        private Guid _FixedDownCameraProcedureId;
+        /// <summary>
+        /// 固定向下相机取料流程ID
+        /// </summary>
+        public Guid FixedDownCameraProcedureId
+        {
+            get { return _FixedDownCameraProcedureId; }
+            set { SetProperty(ref _FixedDownCameraProcedureId, value); }
+        }
+
+        private Guid _MoveDownCameraLockPhotoProcedureId;
+        /// <summary>
+        /// 移动向下相机锁付拍照流程ID
+        /// </summary>
+        public Guid MoveDownCameraLockPhotoProcedureId
+        {
+            get { return _MoveDownCameraLockPhotoProcedureId; }
+            set { SetProperty(ref _MoveDownCameraLockPhotoProcedureId, value); }
+        }
+
         private ObservableCollection<ProductGlobalParam> _GlobalParamListCollection;
         /// <summary>
         /// 产品全局参数集合

+ 20 - 0
TeamAAS-VM/Services/ProductService.cs

@@ -1051,6 +1051,26 @@ namespace TeamAAS_VP.Services
             });
         }
 
+        /// <summary>
+        /// 获取当前产品的指定视觉流程ID的视觉流程对象
+        /// </summary>
+        /// <param name="procedureId"></param>
+        /// <returns></returns>
+        public ProcedureModel GetCurrentProductProcedureModelById(Guid procedureId)
+        {
+            var currentProduct = GetCurrentProduct();
+            if (currentProduct == null) return null;
+            foreach (var cameraProcedure in currentProduct.CameraProcedures)
+            {
+                var procedure = cameraProcedure.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
+                if (procedure != null)
+                {
+                    return procedure;
+                }
+            }
+            return null;
+        }
+
 
         /// <summary>
         /// 递归删除指定目录及其所有子目录和文件。

+ 66 - 2
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -2,12 +2,15 @@ using Cognex.VisionPro;
 using Cognex.VisionPro.ToolBlock;
 using MathNet.Numerics.LinearAlgebra;
 using Microsoft.CodeAnalysis.Scripting;
+using NPOI.SS.Formula.Functions;
 using Org.BouncyCastle.Tls;
 using Prism.Events;
 using Prism.Ioc;
 using Prism.Regions;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.IO;
 using System.Linq;
 using System.Reflection;
@@ -27,8 +30,6 @@ using TeamAAS_VP.Models.Calibration;
 using TeamAAS_VP.Models.Feeder;
 using TeamAAS_VP.Models.Product;
 using TeamAAS_VP.Resources.Languages;
-using System.ComponentModel;
-using System.Collections.Concurrent;
 
 namespace TeamAAS_VP.Services
 {
@@ -1549,6 +1550,69 @@ namespace TeamAAS_VP.Services
             }
         }
 
+        /// <summary>
+        /// 执行相机拍照获取单个点位结果
+        /// </summary>
+        /// <param name="procedure"></param>
+        /// <param name="InputTerminal"></param>
+        /// <param name="robotCoord"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public (bool IsSucceed ,double X,double Y,double U) ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken)
+        {
+            DateTime nowtime = DateTime.Now;
+            //拍照失败时,需要多次拍照
+            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);
+                    return (false,0,0,0);
+                }
+
+                // 2. 获取视觉输出结果
+                bool Found = (bool)(outputCollection["Found"].Value);
+                if (!Found)
+                {
+                    SendTaskMessage(Lang.拍照NG, MessageLevel.Debug);
+                    continue;
+                }
+
+                SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
+
+                // 3. 获取视觉输出结果
+                LogHelper.WriteLogInfo("开始获取视觉输出结果");
+                //获取相机校准
+                var calib = _calibrationService.GetCalibration(procedure.CalibrationId);
+                string points = (string)(outputCollection["Points"].Value);
+                string[] strpoints = points.Split(';');
+                //先将pos按照逗号进行分隔,拿到数组
+                var posParts = strpoints[0].Split(',');
+                double _pixel_x = double.Parse(posParts[0]);
+                double _pixel_y = double.Parse(posParts[1]);
+                double _pixel_u = double.Parse(posParts[2]);
+                //转换点位-像素转换成机器人绝对坐标
+                var calibResult = _calibrationService.ConvertPixelToPosition((_pixel_x, _pixel_y, _pixel_u), robotCoord, calib, RobotBrand.XYZ_Platform);
+                if (!calibResult.IsSucceed)
+                {
+                    return (false, 0, 0, 0);
+                }
+                return (true, calibResult.X, calibResult.Y, calibResult.U);
+            }
+            SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
+            return (false, 0, 0, 0);
+        }
+
         /// <summary>
         /// 从 ToolBlock 的输出集合中根据 Procedure 配置提取需要发送的输出项并做必要的坐标转换。
         /// 返回元组:是否成功、错误信息(失败时)和名称->(是否点位, 值) 的字典。

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

@@ -56,6 +56,82 @@ namespace TeamAAS_VP.ViewModels.Product
             get { return _management; }
             set { SetProperty(ref _management, value); }
         }
+
+        private ObservableCollection<ProcedureModel> _ProcedureModels;
+
+        /// <summary>
+        /// 流程集合
+        /// </summary>
+        public ObservableCollection<ProcedureModel> ProcedureModels
+        {
+            get { return _ProcedureModels; }
+            set { SetProperty(ref _ProcedureModels, value); }
+        }
+
+        private ProcedureModel _FixedUpCamera1Procedure;
+        /// <summary>
+        /// 固定向上相机1视觉流程
+        /// </summary>
+        public ProcedureModel FixedUpCamera1Procedure
+        {
+            get { return _FixedUpCamera1Procedure; }
+            set
+            {
+                SetProperty(ref _FixedUpCamera1Procedure, value);
+                if (value != null)
+                {
+                    SelectProduct.FixedUpCamera1ProcedureId = value.Id;
+                }
+            }
+        }
+
+        private ProcedureModel _FixedUpCamera2Procedure;
+        /// <summary>
+        /// 固定向上相机2视觉流程
+        /// </summary>
+        public ProcedureModel FixedUpCamera2Procedure
+        {
+            get { return _FixedUpCamera2Procedure; }
+            set
+            {
+                SetProperty(ref _FixedUpCamera2Procedure, value); 
+                if (value != null)
+                {
+                    SelectProduct.FixedUpCamera2ProcedureId = value.Id;
+                }
+            }
+        }
+
+        private ProcedureModel _FixedDownCameraProcedure;
+        /// <summary>
+        /// 固定向下相机取料流程ID
+        /// </summary>
+        public ProcedureModel FixedDownCameraProcedure
+        {
+            get { return _FixedDownCameraProcedure; }
+            set { SetProperty(ref _FixedDownCameraProcedure, value);
+                if (value != null)
+                {
+                    SelectProduct.FixedDownCameraProcedureId = value.Id;
+                }
+            }
+        }
+
+        private ProcedureModel _MoveDownCameraLockPhotoProcedure;
+        /// <summary>
+        /// 移动向下相机锁付拍照流程ID
+        /// </summary>
+        public ProcedureModel MoveDownCameraLockPhotoProcedure
+        {
+            get { return _MoveDownCameraLockPhotoProcedure; }
+            set { SetProperty(ref _MoveDownCameraLockPhotoProcedure, value);
+                if (value != null)
+                {
+                    SelectProduct.MoveDownCameraLockPhotoProcedureId = value.Id;
+                }
+            }
+        }
+
         #endregion
 
         #region 命令
@@ -112,7 +188,7 @@ namespace TeamAAS_VP.ViewModels.Product
                 var task = DialogHost.Show(waiting, "RootDialog", null, null, null);
                 await _productService.UpdateProductAsync(SelectProduct);
                 var current = _productService.GetCurrentProduct();
-                if (current!=null && current.IsLoad)
+                if (current != null && current.IsLoad)
                 {
                     await management.WritePositionToPlcAsync();
                 }
@@ -173,6 +249,30 @@ namespace TeamAAS_VP.ViewModels.Product
             try
             {
                 SelectProduct = navigationContext.Parameters.GetValue<ProductModel>("SelectProduct");
+                ProcedureModels = new ObservableCollection<ProcedureModel>();
+                foreach (var item in SelectProduct.CameraProcedures)
+                {
+                    foreach (var item1 in item.ProcedureModels)
+                    {
+                        ProcedureModels.Add(item1);
+                    }
+                }
+                if (SelectProduct.FixedUpCamera1ProcedureId!=Guid.Empty)
+                {
+                    FixedUpCamera1Procedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.FixedUpCamera1ProcedureId);
+                }
+                if (SelectProduct.FixedUpCamera2ProcedureId != Guid.Empty)
+                {
+                    FixedUpCamera2Procedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.FixedUpCamera2ProcedureId);
+                }
+                if (SelectProduct.FixedDownCameraProcedureId != Guid.Empty)
+                {
+                    FixedDownCameraProcedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.FixedDownCameraProcedureId);
+                }
+                if (SelectProduct.MoveDownCameraLockPhotoProcedureId != Guid.Empty)
+                {
+                    MoveDownCameraLockPhotoProcedure = ProcedureModels.FirstOrDefault(p => p.Id == SelectProduct.MoveDownCameraLockPhotoProcedureId);
+                }
             }
             catch (Exception ex)
             {

+ 123 - 6
TeamAAS-VM/Views/Product/ProductParams.xaml

@@ -180,7 +180,7 @@
                                               Minimum="1"
                                               StringFormat="{}{0:N0} %"
                                               Value="{Binding SelectProduct.Speed,Mode=TwoWay}" />
-                    <!--PTP加减速度-->
+                    <!--PTP加减速度--><!--
                     <TextBlock Grid.Row="1"
                                Grid.Column="0"
                                Text="{lex:Loc PTP加减速度,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}" />
@@ -192,7 +192,7 @@
                                               StringFormat="{}{0:N0} %"
                                               Value="{Binding SelectProduct.Accel,Mode=TwoWay}" />
 
-                    <!--CP速度-->
+                    --><!--CP速度--><!--
                     <TextBlock Grid.Row="2"
                                Grid.Column="0"
                                Text="{lex:Loc CP速度,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}" />
@@ -203,7 +203,7 @@
                                               Minimum="1"
                                               StringFormat="{}{0:N0} mm/s"
                                               Value="{Binding SelectProduct.Speeds,Mode=TwoWay}" />
-                    <!--CP加减速度-->
+                    --><!--CP加减速度--><!--
                     <TextBlock Grid.Row="3"
                                Grid.Column="0"
                                Text="{lex:Loc CP加减速度,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}" />
@@ -215,7 +215,7 @@
                                               StringFormat="{}{0:N0} mm/s²"
                                               Value="{Binding SelectProduct.Accels,Mode=TwoWay}" />
 
-                    <!--功率-->
+                    --><!--功率--><!--
                     <TextBlock Grid.Row="4"
                                Grid.Column="0"
                                Text="{lex:Loc 功率,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}" />
@@ -224,14 +224,131 @@
                               Content="{lex:Loc 高功率}"
                               IsChecked="{Binding SelectProduct.Power}" />
 
-                    <!--二次相机功能-->
+                    --><!--二次相机功能--><!--
                     <TextBlock Grid.Row="5"
                                Grid.Column="0"
                                Text="{lex:Loc 视觉引导模式,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}" />
                     <CheckBox Grid.Row="5"
                               Grid.Column="1"
                               Content="{lex:Loc 启用二次定位相机}"
-                              IsChecked="{Binding SelectProduct.IsUserUpCamera}" />
+                              IsChecked="{Binding SelectProduct.IsUserUpCamera}" />-->
+                    <!--固定向上相机1视觉流程-->
+                    <TextBlock Grid.Row="1"
+                               Grid.Column="0"
+                               Text="固定向上相机1视觉流程ID: " />
+                    <ComboBox Grid.Row="1"
+                              Grid.Column="1"
+                              ItemsSource="{Binding ProcedureModels}"
+                              SelectedItem="{Binding FixedUpCamera1Procedure}"
+                              materialDesign:TextFieldAssist.HasClearButton="True"
+                              materialDesign:HintAssist.Hint="{lex:Loc 选择需要配置的流程}">
+                        <b:Interaction.Triggers>
+                            <b:EventTrigger EventName="PreviewMouseDown">
+                                <b:CallMethodAction  TargetObject="{Binding}"
+                                                     MethodName="ComboBox_MouseDown"></b:CallMethodAction>
+                            </b:EventTrigger>
+                        </b:Interaction.Triggers>
+                        <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>
+                    <!--固定向上相机2视觉流程-->
+                    <TextBlock Grid.Row="2"
+                               Grid.Column="0"
+                               Text="固定向上相机2视觉流程ID: " />
+                    <ComboBox Grid.Row="2"
+                              Grid.Column="1"
+                              ItemsSource="{Binding ProcedureModels}"
+                              SelectedItem="{Binding FixedUpCamera2Procedure}"
+                              materialDesign:TextFieldAssist.HasClearButton="True"
+                              materialDesign:HintAssist.Hint="{lex:Loc 选择需要配置的流程}">
+                        <b:Interaction.Triggers>
+                            <b:EventTrigger EventName="PreviewMouseDown">
+                                <b:CallMethodAction  TargetObject="{Binding}"
+                                                     MethodName="ComboBox_MouseDown"></b:CallMethodAction>
+                            </b:EventTrigger>
+                        </b:Interaction.Triggers>
+                        <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>
+                    <!--固定向下相机取料流程-->
+                    <TextBlock Grid.Row="3"
+                               Grid.Column="0"
+                               Text="固定向下相机取料流程ID: " />
+                    <ComboBox Grid.Row="3"
+                              Grid.Column="1"
+                              ItemsSource="{Binding ProcedureModels}"
+                              SelectedItem="{Binding FixedDownCameraProcedure}"
+                              materialDesign:TextFieldAssist.HasClearButton="True"
+                              materialDesign:HintAssist.Hint="{lex:Loc 选择需要配置的流程}">
+                        <b:Interaction.Triggers>
+                            <b:EventTrigger EventName="PreviewMouseDown">
+                                <b:CallMethodAction  TargetObject="{Binding}"
+                                                     MethodName="ComboBox_MouseDown"></b:CallMethodAction>
+                            </b:EventTrigger>
+                        </b:Interaction.Triggers>
+                        <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>
+                    <!--移动向下相机锁付拍照流程-->
+                    <TextBlock Grid.Row="4"
+                               Grid.Column="0"
+                               Text="移动向下相机锁付拍照流程ID: " />
+                    <ComboBox Grid.Row="4"
+                              Grid.Column="1"
+                              ItemsSource="{Binding ProcedureModels}"
+                              SelectedItem="{Binding MoveDownCameraLockPhotoProcedure}"
+                              materialDesign:TextFieldAssist.HasClearButton="True"
+                              materialDesign:HintAssist.Hint="{lex:Loc 选择需要配置的流程}">
+                        <b:Interaction.Triggers>
+                            <b:EventTrigger EventName="PreviewMouseDown">
+                                <b:CallMethodAction  TargetObject="{Binding}"
+                                                     MethodName="ComboBox_MouseDown"></b:CallMethodAction>
+                            </b:EventTrigger>
+                        </b:Interaction.Triggers>
+                        <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>