Ver código fonte

增加翻转相机拍照,增加mes二次查询

zly 4 meses atrás
pai
commit
ff641f662b

+ 221 - 100
TeamAAS-VM/Core/Management.cs

@@ -1,4 +1,5 @@
 using Cognex.VisionPro;
+using Cognex.VisionPro.ToolBlock;
 using CSScripting;
 using NPOI.OpenXmlFormats.Dml.Diagram;
 using NPOI.SS.Formula.Eval;
@@ -1503,6 +1504,7 @@ namespace TeamAAS_VP.Core
         bool _LastFixedCameracheckExe = false;
         public bool _LastAutoRunning = false;
         public bool _LastManualMode = false;
+        bool _LastFzCameracheckExe = false;
         bool _LastClearMode = false;
         Int16 _LastWorkStart = 0;
         Int16 _LastWorkDone = 0;
@@ -2477,7 +2479,118 @@ namespace TeamAAS_VP.Core
                     }
                 }
 
-                //翻转相机检测拍照
+                // 翻转相机检测拍照
+                else if (addressConfig.In_FzCameraPixExe.Address.Contains(tuple.nodeId))
+                {
+                    if (tuple.value is bool state)
+                    {
+                        if (_LastFzCameracheckExe != state)
+                        {
+                            _LastFzCameracheckExe = state;
+                        }
+                        else
+                        {
+                            return;
+                        }
+                        if (state)
+                        {
+                            SendTaskMessage("触发翻转相机拍照", MessageLevel.Debug);
+                            var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 1));
+
+                            //这里缺少从MES获取产品配方的内容,需要补充
+                            _LastMesCheckTime[5] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
+                            var stationConfig2 = _configService.GetDeviceInfo(0);
+                            LogHelper.WriteLogMes($"【mes开始QUERY】");
+                            SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
+                            (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
+                            if (isSuccess)
+                            {
+                                string ProductMainSN_Temp = "";
+                                LogHelper.WriteLogMes($"询问mes成功");
+                                SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+                                string[] item = response.Split('\n');
+                                //获取过度件sn
+                                string snItem = item.FirstOrDefault(f => f.Contains("sn="));
+                                if (snItem != null)
+                                {
+                                    ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
+                                    SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
+                                }
+
+                                LogHelper.WriteLogMes($"询问mes成功");
+                                SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+
+                                //20260214,螺丝机特别版
+                                (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
+                                if (isSuccess2)
+                                {
+                                    LogHelper.WriteLogMes($"询问mes成功");
+                                    SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
+
+                                    string[] items = response2.Split('\n');
+                                    //获取产品主sn和wo用于后续上传数据使用
+                                    string snItem2 = items.FirstOrDefault(f => f.Contains("sn="));
+                                    if (snItem2 != null)
+                                    {
+                                        var codesn = snItem2.Replace("sn=", "").Trim();
+
+                                        SendTaskMessage($"产品主sn:{codesn}", MessageLevel.Info);
+                                    }
+
+                                    LogHelper.WriteLogMes($"第二次询问mes成功");
+                                    SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
+
+                                }
+                                else
+                                {
+                                    LogHelper.WriteLogMes($"第二次询问mes失败");
+                                    SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
+                                    await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
+                                    return;
+                                }
+                            }
+                            else
+                            {
+                                LogHelper.WriteLogMes($"询问mes失败");
+                                SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
+                                await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
+                                return;
+                            }
+
+                            Guid FzCameraProcedureId = currentProduct.FzCameraProcedureId;
+
+                            var FzCameraProcess = _productService.GetCurrentProductProcedureModelById(FzCameraProcedureId);
+                            if (FzCameraProcess == null)
+                            {
+                                SendTaskMessage($"未找到翻转相机视觉流程,流程ID: {FzCameraProcedureId}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
+                                return;
+                            }
+                            SendTaskMessage($"开始执行翻转相机视觉流程", MessageLevel.Debug);
+                            var _cts = new CancellationTokenSource();
+
+                            await _remoteCommandService.SetLightBeforePhoto(FzCameraProcess);
+                            var FzCameraResult = _remoteCommandService.ExecutePhoto(FzCameraProcess, out CogToolBlockTerminalCollection outputCollection);
+
+                            if (FzCameraResult)
+                            {
+                                SendTaskMessage("翻转相机拍照成功", MessageLevel.Debug);
+                                await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)1);
+
+                            }
+                            else
+                            {
+                                SendTaskMessage("翻转相机拍照失败", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
+                            }
+                        }
+                        else
+                        {
+                            SendTaskMessage($"触发翻转相机检测拍照信号已关闭", MessageLevel.Alarm);
+                            await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)0);
+                        }
+                    }
+                }
 
                 //切换成自动运行模式
                 else if (addressConfig.AutoRunning.Address.Contains(tuple.nodeId))
@@ -2576,7 +2689,14 @@ namespace TeamAAS_VP.Core
                                     code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
                                 }
                                 var homeview = _container.Resolve<HomeViewModel>();
-
+                                if (i == 0)
+                                {
+                                    SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
+                                }
+                                else
+                                {
+                                    SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
+                                }
                                 //过站检查
                                 if (state == 1)
                                 {
@@ -2591,121 +2711,122 @@ namespace TeamAAS_VP.Core
                                     LogHelper.WriteLogMes($"【mes开始QUERY】");
                                     SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
                                     ShowMes_Query = false;
-                                    (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
-
-
-                                    if (i == 0)
-                                    {
-                                        SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
-                                    }
-                                    else
-                                    {
-                                        SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
-                                    }
+                                    (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
                                     if (isSuccess)
                                     {
-
-                                        string[] item = response.Split('\n');
-                                        //获取产品主sn和wo用于后续上传数据使用
-                                        string snItem = item.FirstOrDefault(f => f.Contains("sn="));
-                                        if (snItem != null)
-                                        {
-                                            ProductMainSN = snItem.Replace("sn=", "").Trim();
-                                            if (i == 0)
-                                            {
-                                                _productService.CurrentProductCode = ProductMainSN;
-                                            }
-                                            SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
-                                        }
-                                        string woItem = item.FirstOrDefault(f => f.Contains("wo="));
-                                        if (woItem != null)
-                                        {
-                                            wo = woItem.Replace("wo=", "").Trim();
-                                            SendTaskMessage($"工单信息:{wo}", MessageLevel.Info);
-                                        }
-                                        string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
-                                        if (modelItem != null)
-                                        {
-                                            model_num = modelItem.Replace("model_num=", "").Trim();
-                                            SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
-                                        }
-                                        string colorItem = item.FirstOrDefault(f => f.Contains("color="));
-                                        if (colorItem != null)
-                                        {
-                                            color = colorItem.Replace("color=", "").Trim();
-                                            SendTaskMessage($"color:{color}", MessageLevel.Info);
-                                        }
-                                        string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
-                                        if (ppidItem != null)
-                                        {
-                                            ppid = ppidItem.Replace("ppid=", "").Trim();
-                                            SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
-                                        }
-                                        string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
-                                        if (stageItem != null)
-                                        {
-                                            stage = stageItem.Replace("stage=", "").Trim();
-                                            SendTaskMessage($"stage:{stage}", MessageLevel.Info);
-                                        }
-                                        string kbsnitem = item.FirstOrDefault(f => f.Contains("KB="));
-                                        if (kbsnitem != null)
+                                        string ProductMainSN_Temp = "";
+                                        LogHelper.WriteLogMes($"询问mes成功");
+                                        SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+                                        string[] item2 = response.Split('\n');
+                                        //获取过度件sn
+                                        string snItem2 = item2.FirstOrDefault(f => f.Contains("sn="));
+                                        if (snItem2 != null)
                                         {
-                                            kb_sn = kbsnitem.Replace("KB=", "").Trim();
-                                            SendTaskMessage($"KB:{kb_sn}", MessageLevel.Info);
+                                            ProductMainSN_Temp = snItem2.Replace("sn=", "").Trim();
+                                            SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
                                         }
-                                        ShowMes_Query = true;
-                                        //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
 
+                                        LogHelper.WriteLogMes($"询问mes成功");
+                                        SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
 
-                                        if (stationConfig2.EnableMES)
+                                        (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
+                                        if (isSuccess)
                                         {
-                                            //切换产品
-                                            if (i == 0)//i=0时才会切换产品
+
+                                            string[] item = response.Split('\n');
+                                            //获取产品主sn和wo用于后续上传数据使用
+                                            string snItem = item.FirstOrDefault(f => f.Contains("sn="));
+                                            if (snItem != null)
+                                            {
+                                                ProductMainSN = snItem.Replace("sn=", "").Trim();
+                                                if (i == 0)
+                                                {
+                                                    _productService.CurrentProductCode = ProductMainSN;
+                                                }
+                                                SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
+                                            }
+                                            string woItem = item.FirstOrDefault(f => f.Contains("wo="));
+                                            if (woItem != null)
+                                            {
+                                                wo = woItem.Replace("wo=", "").Trim();
+                                                SendTaskMessage($"工单信息:{wo}", MessageLevel.Info);
+                                            }
+                                            string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
+                                            if (modelItem != null)
+                                            {
+                                                model_num = modelItem.Replace("model_num=", "").Trim();
+                                                SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
+                                            }
+                                            string colorItem = item.FirstOrDefault(f => f.Contains("color="));
+                                            if (colorItem != null)
+                                            {
+                                                color = colorItem.Replace("color=", "").Trim();
+                                                SendTaskMessage($"color:{color}", MessageLevel.Info);
+                                            }
+                                            string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
+                                            if (ppidItem != null)
+                                            {
+                                                ppid = ppidItem.Replace("ppid=", "").Trim();
+                                                SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
+                                            }
+                                            string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
+                                            if (stageItem != null)
                                             {
-                                                var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
-                                                if (!string.IsNullOrEmpty(q))
+                                                stage = stageItem.Replace("stage=", "").Trim();
+                                                SendTaskMessage($"stage:{stage}", MessageLevel.Info);
+                                            }
+                                            string kbsnitem = item.FirstOrDefault(f => f.Contains("KB="));
+                                            if (kbsnitem != null)
+                                            {
+                                                kb_sn = kbsnitem.Replace("KB=", "").Trim();
+                                                SendTaskMessage($"KB:{kb_sn}", MessageLevel.Info);
+                                            }
+                                            ShowMes_Query = true;
+
+                                            if (stationConfig2.EnableMES)
+                                            {
+                                                //切换产品
+                                                if (i == 0)//i=0时才会切换产品
                                                 {
-                                                    ProductWithMes productWithMes = new ProductWithMes();
-                                                    ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
-                                                    Guid productId = Guid.Empty;
-                                                    foreach (var itt in ProductList)
+                                                    var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
+                                                    if (!string.IsNullOrEmpty(q))
                                                     {
-                                                        if (itt.Name == q)
+                                                        ProductWithMes productWithMes = new ProductWithMes();
+                                                        ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
+                                                        Guid productId = Guid.Empty;
+                                                        foreach (var itt in ProductList)
+                                                        {
+                                                            if (itt.Name == q)
+                                                            {
+                                                                productId = itt.ID;
+                                                                break;
+                                                            }
+                                                        }
+                                                        //if(kb_sn==)
+                                                        if (currentProduct.ID != productId || productWithMes.ProductKBSN != kb_sn)
                                                         {
-                                                            productId = itt.ID;
-                                                            break;
+                                                            //切换产品
+                                                            _productService.LoadProduct(productId);
+                                                            _productService.SetCurrentProduct(productId);
+                                                            await WritePositionToPlcAsync();
+                                                            SendTaskMessage($"切换产品成功", MessageLevel.Debug);
                                                         }
                                                     }
-                                                    //if(kb_sn==)
-                                                    if (currentProduct.ID != productId || productWithMes.ProductKBSN != kb_sn)
-                                                    {
-                                                        //切换产品
-                                                        _productService.LoadProduct(productId);
-                                                        _productService.SetCurrentProduct(productId);
-                                                        await WritePositionToPlcAsync();
-                                                        SendTaskMessage($"切换产品成功", MessageLevel.Debug);
-                                                    }
                                                 }
                                             }
+                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
+                                            LogHelper.WriteLogMes($"【mes结束QUERY】");
+                                            SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
+                                           // return;
                                         }
-                                        
-                                        await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
-
-                                        LogHelper.WriteLogMes($"【mes结束QUERY】");
-                                        SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
-                                        return;
-                                    }
-                                    else
-                                    {
-                                        //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-
-                                        await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+                                        else
+                                        {
+                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
 
-                                        LogHelper.WriteLogMes($"询问mes失败");
-                                        SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
-                                    }
-                                    LogHelper.WriteLogMes($"【mes结束QUERY】");
-                                    SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
+                                            LogHelper.WriteLogMes($"询问mes失败");
+                                            SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
+                                        }
+                                    }                                   
                                 }
                                 // 上传本站数据
                                 else if (state == 2)

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

@@ -241,6 +241,14 @@ 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>

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

@@ -188,6 +188,16 @@ namespace TeamAAS_VP.Models.PLC
             set { SetProperty(ref _FixedCameracheckStatus, value); }
         }
 
+        private PlcAddress _FzCameraPickStatus = new PlcAddress();
+        /// <summary>
+        /// 固定相机取料拍照结果 =1 拍照OK =2 拍照NG =3 取图拍照OK
+        /// </summary>
+        public PlcAddress Out_FzCameraPickStatus
+        {
+            get { return _FzCameraPickStatus; }
+            set { SetProperty(ref _FzCameraPickStatus, value); }
+        }
+
         private PlcAddress _Out_CameraDone = new PlcAddress();
         /// <summary>
         /// 相机坐标拟合完成
@@ -535,6 +545,17 @@ namespace TeamAAS_VP.Models.PLC
             get { return _In_WorkDone; }
             set { SetProperty(ref _In_WorkDone, value); }
         }
+
+        private PlcAddress _In_FzCameraPixExe = new PlcAddress();
+        /// <summary>
+        /// 翻转相机触发拍照
+        /// </summary>
+        public PlcAddress In_FzCameraPixExe
+        {
+            get { return _In_FzCameraPixExe; }
+            set { SetProperty(ref _In_FzCameraPixExe, value); }
+        }
+
         #endregion
 
         public PlcAddressConfig()
@@ -651,6 +672,11 @@ namespace TeamAAS_VP.Models.PLC
             Out_FixedCameracheckStatus.DataType = "int16";
             Out_FixedCameracheckStatus.Description = "固定相机检测拍照结果 =1 拍照OK =2 拍照NG =3 取图拍照OK";
 
+            Out_FzCameraPickStatus = Ensure(Out_FzCameraPickStatus);
+            Out_FzCameraPickStatus.Address = "ns=4;s=DB_Communication|FromPC.FzCameraPickStatus";
+            Out_FzCameraPickStatus.DataType = "int16";
+            Out_FzCameraPickStatus.Description = "翻转相机取料拍照结果 =1 拍照OK =2 拍照NG =3 取图拍照OK";
+
             Out_CameraDone = Ensure(Out_CameraDone);
             Out_CameraDone.Address = "ns=4;s=DB_Communication|FromPC.CameraDone";
             Out_CameraDone.DataType = "int16";
@@ -840,6 +866,11 @@ namespace TeamAAS_VP.Models.PLC
             In_WorkDone.DataType = "int16";
             In_WorkDone.Description = "锁附/组装结束 =1OK =2NG";
 
+            In_FzCameraPixExe = Ensure(In_FzCameraPixExe);
+            In_FzCameraPixExe.Address = "ns=4;s=DB_Communication|ToPC.In_FzCameraPixExe";
+            In_FzCameraPixExe.DataType = "bool";
+            In_FzCameraPixExe.Description = "翻转相机检测拍照触发";
+
             // 说明:若项目中 PlcAddress 的实际属性名或类型与此不同(例如使用枚举、不同字段名),
             // 请根据实际类型调整赋值。本方法主要提供合理的默认字符串地址、数据类型及描述,便于后续从配置覆盖。
         }

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

@@ -1462,6 +1462,152 @@ 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;
+                    }
+
+                    bool Found = (bool)(outputCollection["Found"].Value);
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => 1);
+                        template.RegisterVariable("Result", () => Found ? "OK" : "NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
+
+                    _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
+                    {
+                        Id = procedure.Id,
+                        DisplayName = procedure.DisplayName,
+                        //Image = (ICogImage)procedure.ToolBlock.Outputs["OriImage"].Value,
+                        //Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
+                        Image = image,
+                        Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
+                        Record = record,
+                        Result = Found,
+                        IsShow = true,
+                        IsSaveImage = procedure.IsSaveImage,
+                        SaveImageModel = procedure.SaveImageModel,
+                        SaveImagePathModel = procedure.SaveImagePathModel,
+                        SavePath = procedure.SavePath,
+                        IsCompress = procedure.IsCompress,
+                        ProceductName = procedure.Name,
+                        ImageFileName = imgName,
+                        Is3DModel = true
+                    });
+                    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;
+
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => 1);
+                        template.RegisterVariable("Result", () => "NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
+                    _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
+                    {
+                        Id = procedure.Id,
+                        DisplayName = procedure.DisplayName,
+                        //Image = (ICogImage)procedure.ToolBlock.Outputs["OriImage"].Value,
+                        //Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
+                        Image = image,
+                        Graphic = new CogGraphicCollection(),
+                        Result = false,
+                        IsShow = true,
+                        IsSaveImage = procedure.IsSaveImage,
+                        SaveImageModel = procedure.SaveImageModel,
+                        SaveImagePathModel = procedure.SaveImagePathModel,
+                        SavePath = procedure.SavePath,
+                        ProceductName = procedure.Name,
+                        ImageFileName = imgName,
+                        Is3DModel = true
+                    });
+                    return false;
+                }
+            }
+            catch (Exception ex)
+            {
+                SendTaskMessage(ex.Message, MessageLevel.Error);
+                LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错", ex);
+                outputCollection = null;
+                return false;
+            }
+        }
+
         /// <summary>
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
         /// 该方法会发布 RenderUpdateNotification 以更新 UI。