Przeglądaj źródła

优化相机软触发采集流程及异常处理

本次提交主要优化了 OptCamera.cs 的软触发采集流程,采用 TaskCompletionSource 异步等待回调并增加超时机制,提升了采集的可靠性和响应速度。增强了回调中的异常捕获与主流程的错误反馈。SetExposureTime 方法支持多种曝光时间节点及类型,提升兼容性。关闭设备时增加空引用判断,提升资源释放安全性。同时更新了版本号至 1.2.1.1。
孝锋 徐 7 miesięcy temu
rodzic
commit
03a0e9e7ce

+ 79 - 51
TeamAAS-VM/Core/Cameras/OptCamera.cs

@@ -1,5 +1,6 @@
 using Cognex.VisionPro;
 using Microsoft.Win32;
+using netDxf.Entities;
 using NPOI.POIFS.Crypt.Dsig;
 using NPOI.SS.Formula.Eval;
 using SciCamera.Net;
@@ -29,6 +30,7 @@ namespace TeamAAS_VP.Core.Cameras
         //private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1);
         // 用于保护状态变量(例如 IsGrabbing)的并发访问
         private readonly object _stateLock = new object();
+        private TaskCompletionSource<ICogImage> _tcs;
         #endregion
 
         #region 属性
@@ -352,12 +354,12 @@ namespace TeamAAS_VP.Core.Cameras
                 // ch:打开设备 | en:Open device
                 nReVal = mvCameraAcq.OpenDevice();
                 // ch:设置触发模式为off | en:Set trigger mode as off
-                nReVal = mvCameraAcq.SetEnumValueByStringEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerMode", "Off");
+                nReVal = mvCameraAcq.SetEnumValueByStringEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerMode", "On");
                 nReVal = mvCameraAcq.SetEnumValueByString("TriggerSource", "Software");
                 // ch:注册事件回调 | en:Register event callback
-                //nReVal = mvCameraAcq.RegisterPayloadCallBack(new SciCam.fnOnPayloadDelegate(ImageCallBack), IntPtr.Zero, true);
+                nReVal = mvCameraAcq.RegisterPayloadCallBack(new SciCam.fnOnPayloadDelegate(ImageCallBack), IntPtr.Zero, true);
                 // ch:设置采集策略 | en:Set Grab Strategy
-                nReVal = mvCameraAcq.SetGrabStrategy(SciCam.SciCamGrabStrategy.SciCam_GrabStrategy_Upcoming);
+                nReVal = mvCameraAcq.SetGrabStrategy(CurrentGrabStrategy);
                 if (nReVal != SciCam.SCI_CAMERA_OK)
                 {
                     Console.WriteLine("Register Event CallBack fail! nRet {0}", nReVal);
@@ -401,8 +403,8 @@ namespace TeamAAS_VP.Core.Cameras
             //_operationSemaphore.Wait();
             try
             {
-                mvCameraAcq.StopGrabbing();
-                mvCameraAcq.CloseDevice();
+                mvCameraAcq?.StopGrabbing();
+                mvCameraAcq?.CloseDevice();
             }
             finally
             {
@@ -432,42 +434,37 @@ namespace TeamAAS_VP.Core.Cameras
                             OpenDevice();
                         }
 
-                        //如果仅仅采集最后一帧,则清空缓存
-                        //if (lastImageOnly)
-                        //{
-                        //    //判断当前的模式是否为最新模式,如果不是则设置为最新模式
-                        //    if (CurrentGrabStrategy != SciCam.SciCamGrabStrategy.SciCam_GrabStrategy_Upcoming)
-                        //    {
-                        //        CurrentGrabStrategy = SciCam.SciCamGrabStrategy.SciCam_GrabStrategy_Upcoming;
-                        //        nReVal = mvCameraAcq.SetGrabStrategy(CurrentGrabStrategy);
-                        //    }
-                        //}
-                        //else
-                        //{
-                        //    //判断当前的模式是否为顺序模式,如果不是则设置为顺序模式
-                        //    if (CurrentGrabStrategy != SciCam.SciCamGrabStrategy.SciCam_GrabStrategy_Latest)
-                        //    {
-                        //        CurrentGrabStrategy = SciCam.SciCamGrabStrategy.SciCam_GrabStrategy_Latest;
-                        //        nReVal = mvCameraAcq.SetGrabStrategy(CurrentGrabStrategy);
-                        //    }
-                        //}
-                        //if (!mvCameraAcq.IsGrabbing())
-                        //{
-                        //    mvCameraAcq.StartGrabbing();
-                        //}
-                        //nReVal = mvCameraAcq.StartGrabbing();
-                        //mvCameraAcq.ClearPayloadBuffer();
+                        // 重置TaskCompletionSource
+                        _tcs?.TrySetCanceled();
+                        _tcs = new TaskCompletionSource<ICogImage>();
+
+                        // 注册取消令牌
+                        CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(2000); // 2秒超时
+                        cancellationTokenSource.Token.Register(() => _tcs.TrySetCanceled());
+
+                        // 触发图像采集
                         // ch:发送软触发命令 | en:Send Trigger Software command
-                        //nReVal = mvCameraAcq.SetCommandValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerSoftware");
-                        nReVal = mvCameraAcq.Grab(ref payload);
+                        nReVal = mvCameraAcq.SetCommandValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerSoftware");
                         if (nReVal == SciCam.SCI_CAMERA_OK)
                         {
-                            Image = GetConvertedInfo(payload);
-                            mvCameraAcq.FreePayload(payload);
-                            //nReVal = mvCameraAcq.StopGrabbing();
+                            // 等待图像接收事件
+                            Image = _tcs.Task.Result;
                             TotalTime = sw.Elapsed;
                             ErrorMessage = $"{i + 1}";
-                            return Image;
+                            if (Image != null)
+                            {
+                                return Image;
+                            }
+                            else
+                            {
+                                //nReVal = mvCameraAcq.FreePayload(payload);
+                                //nReVal = mvCameraAcq.StopGrabbing();
+                                //_operationSemaphore.Release();
+                                CloseDevice();
+                                OpenDevice();
+                                ErrorMessage = "图像采集失败!";
+                            }
+
                         }
                         else
                         {
@@ -503,21 +500,31 @@ namespace TeamAAS_VP.Core.Cameras
         // ch:采集回调接口 | en:Grab Callback interface     
         void ImageCallBack(IntPtr payload, IntPtr tag)
         {
-            if (payload == IntPtr.Zero) return;
-            uint nReVal = SciCam.SCI_CAMERA_OK;
-
-            SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE attribute = new SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE();
-            nReVal = SciCam.PayloadGetAttribute(payload, ref attribute);
-            if (nReVal != SciCam.SCI_CAMERA_OK || !attribute.isComplete)
+            try
             {
-                Console.WriteLine("Failed to get image attributes or frame is incomplete! nRet:{0}", nReVal);
+                if (payload == IntPtr.Zero) return;
+                uint nReVal = SciCam.SCI_CAMERA_OK;
+
+                SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE attribute = new SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE();
+                nReVal = SciCam.PayloadGetAttribute(payload, ref attribute);
+                if (nReVal != SciCam.SCI_CAMERA_OK || !attribute.isComplete)
+                {
+                    Console.WriteLine("Failed to get image attributes or frame is incomplete! nRet:{0}", nReVal);
+                    _tcs?.TrySetException(new Exception($"Failed to get image attributes or frame is incomplete! nRet: {nReVal}"));
+                }
+                else
+                {
+                    Image = GetConvertedInfo(payload);
+                    //ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
+                    //Console.WriteLine("Get One Frame: Width[{0}], Height[{1}], nFrameNum[{2}]",
+                    //attribute.imgAttr.width, attribute.imgAttr.height, attribute.frameID);
+                    // 收到图像时完成任务
+                    _tcs?.TrySetResult(Image);
+                }
             }
-            else
+            catch (Exception ex)
             {
-                Image = GetConvertedInfo(payload);
-                ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
-                //Console.WriteLine("Get One Frame: Width[{0}], Height[{1}], nFrameNum[{2}]",
-                //attribute.imgAttr.width, attribute.imgAttr.height, attribute.frameID);
+                _tcs?.TrySetException(new Exception($"相机采集错误: {ex.Message}"));
             }
         }
 
@@ -566,16 +573,37 @@ namespace TeamAAS_VP.Core.Cameras
         /// <returns></returns>
         public bool SetExposureTime(float ExposureTime)
         {
-            //_operationSemaphore.Wait();
             try
             {
                 if (!mvCameraAcq.IsDeviceOpen())
                     return false;
+                string[] nodeName = new string[]{
+                "ExposureTime",
+                "ExposureTimeAbs",
+                "ExposureTimeRaw"};
+
                 uint nReVal = SciCam.SCI_CAMERA_OK;
-                nReVal = mvCameraAcq.SetIntValue("ExposureTime", (int)ExposureTime);
+                for (int i = 0; i < nodeName.Count(); i++)
+                {
+                    nReVal = mvCameraAcq.SetIntValue(nodeName[i], (int)ExposureTime);
+
+                    if (nReVal != SciCam.SCI_CAMERA_OK)
+                    {
+                        nReVal = mvCameraAcq.SetFloatValue(nodeName[i], ExposureTime);
+                        if (nReVal == SciCam.SCI_CAMERA_OK)
+                        {
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+
                 if (nReVal != SciCam.SCI_CAMERA_OK)
                 {
-                    mvCameraAcq.SetFloatValue("ExposureTime", ExposureTime);
+                    return false;
                 }
                 return true;
             }

+ 2 - 2
TeamAAS-VM/Properties/AssemblyInfo.cs

@@ -51,5 +51,5 @@ using System.Windows;
 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
 //通过使用 "*",如下所示:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.2.1.0")]
-[assembly: AssemblyFileVersion("1.2.1.0")]
+[assembly: AssemblyVersion("1.2.1.1")]
+[assembly: AssemblyFileVersion("1.2.1.1")]