|
@@ -18,6 +18,7 @@ using System;
|
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Concurrent;
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
+using System.Diagnostics;
|
|
|
using System.Drawing;
|
|
using System.Drawing;
|
|
|
using System.IO;
|
|
using System.IO;
|
|
|
using System.IO.Compression;
|
|
using System.IO.Compression;
|
|
@@ -67,6 +68,11 @@ namespace TeamAAS_VP.Core
|
|
|
IMesService _mesService;
|
|
IMesService _mesService;
|
|
|
|
|
|
|
|
Timer yieldtimer;
|
|
Timer yieldtimer;
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 消息队列——替代 SendTaskMessage 中的 Dispatcher.BeginInvoke,消除 UI 线程阻塞
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private readonly ConcurrentQueue<MessageStruct> _messageQueue = new ConcurrentQueue<MessageStruct>();
|
|
|
|
|
+ private Timer _messageFlushTimer;
|
|
|
private DateTime StartTime = DateTime.Now;
|
|
private DateTime StartTime = DateTime.Now;
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// 产品主sn
|
|
/// 产品主sn
|
|
@@ -302,6 +308,7 @@ namespace TeamAAS_VP.Core
|
|
|
_plcService = plcService;
|
|
_plcService = plcService;
|
|
|
_calibrationService = calibrationService;
|
|
_calibrationService = calibrationService;
|
|
|
yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
|
|
yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
|
|
|
|
|
+ _messageFlushTimer = new Timer(_ => FlushMessageQueue(), null, 200, 200);
|
|
|
Renders = new ObservableCollection<ShowRender>();
|
|
Renders = new ObservableCollection<ShowRender>();
|
|
|
_configService = configService;
|
|
_configService = configService;
|
|
|
_productService = productService;
|
|
_productService = productService;
|
|
@@ -1513,10 +1520,20 @@ namespace TeamAAS_VP.Core
|
|
|
private readonly object _stateLock = new object();
|
|
private readonly object _stateLock = new object();
|
|
|
// private SharedSpeedFileHelper _speedFileHelper = new SharedSpeedFileHelper();
|
|
// private SharedSpeedFileHelper _speedFileHelper = new SharedSpeedFileHelper();
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// PLC命令触发时S
|
|
|
|
|
|
|
+ /// PLC命令触发时 - 同步入口,立即释放OPC UA回调线程,实际逻辑异步执行
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
/// <param name="tuple"></param>
|
|
/// <param name="tuple"></param>
|
|
|
- private async void PlcCommandTrigger((string key, string nodeId, object value) tuple)
|
|
|
|
|
|
|
+ private void PlcCommandTrigger((string key, string nodeId, object value) tuple)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 立即释放OPC UA回调线程,避免阻塞Session导致后续WriteNodeAsync无法派发
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] Trigger queued key={tuple.key}, node={tuple.nodeId}, value={tuple.value}, thread={Thread.CurrentThread.ManagedThreadId}, time={DateTime.Now:HH:mm:ss.fff}");
|
|
|
|
|
+ _ = Task.Run(() => PlcCommandTriggerAsync(tuple));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// PLC命令触发时的异步处理逻辑
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private async Task PlcCommandTriggerAsync((string key, string nodeId, object value) tuple)
|
|
|
{
|
|
{
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
@@ -1662,6 +1679,8 @@ namespace TeamAAS_VP.Core
|
|
|
}
|
|
}
|
|
|
catch { }
|
|
catch { }
|
|
|
var sysConfig = _configService.GetSystemConfiguration();
|
|
var sysConfig = _configService.GetSystemConfiguration();
|
|
|
|
|
+ string fixedCameraTraceId = $"FC-{cameraIndex}-{DateTime.Now:HHmmss.fff}";
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} fixed camera trigger start, node={tuple.nodeId}, value={tuple.value}, procCount={procIds.Count}, PhotosUse={sysConfig.PhotosUse}, cameraIndex={cameraIndex}, PhotoCountStop={currentProduct.PhotoCountStop}, thread={Thread.CurrentThread.ManagedThreadId}");
|
|
|
|
|
|
|
|
#region 扫码枪扫码
|
|
#region 扫码枪扫码
|
|
|
if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse2 == true)
|
|
if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse2 == true)
|
|
@@ -2510,30 +2529,45 @@ namespace TeamAAS_VP.Core
|
|
|
{
|
|
{
|
|
|
LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
|
|
LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
|
|
|
}
|
|
}
|
|
|
- if (sysConfig.TurnOnAllLightUse == false)
|
|
|
|
|
- {
|
|
|
|
|
- await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // [DEBUG] 光源控制已临时屏蔽
|
|
|
|
|
+ // if (sysConfig.TurnOnAllLightUse == false)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
if (sysConfig.PhotosUse == true)
|
|
if (sysConfig.PhotosUse == true)
|
|
|
{
|
|
{
|
|
|
bool Is3dPhoto = Is3D(prcId);
|
|
bool Is3dPhoto = Is3D(prcId);
|
|
|
|
|
+ var grabWatch = Stopwatch.StartNew();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} GrabImageEx start, cameraIndex={cameraIndex}, procedureId={prcId}, is3D={Is3dPhoto}, thread={Thread.CurrentThread.ManagedThreadId}");
|
|
|
var tt = await GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig);
|
|
var tt = await GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig);
|
|
|
|
|
+ grabWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} GrabImageEx done, cameraIndex={cameraIndex}, procedureId={prcId}, success={tt.IsSucceed}, elapsedMs={grabWatch.ElapsedMilliseconds}, msg={tt.Message}");
|
|
|
if (tt.IsSucceed == false)
|
|
if (tt.IsSucceed == false)
|
|
|
{
|
|
{
|
|
|
SendTaskMessage($"图像采集失败!{cameraIndex}: {prcId}", MessageLevel.Alarm);
|
|
SendTaskMessage($"图像采集失败!{cameraIndex}: {prcId}", MessageLevel.Alarm);
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} return before status write because GrabImageEx failed, cameraIndex={cameraIndex}, procedureId={prcId}");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+ var executeWatch = Stopwatch.StartNew();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} ExecuteProcedureAsync start, cameraIndex={cameraIndex}, procedureId={prcId}, imageCount={(tt.imges == null ? 0 : tt.imges.Length)}");
|
|
|
await ExecuteProcedureAsync(cameraIndex, prcId, tt.imges, Is3dPhoto, currentProduct);
|
|
await ExecuteProcedureAsync(cameraIndex, prcId, tt.imges, Is3dPhoto, currentProduct);
|
|
|
|
|
+ executeWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} ExecuteProcedureAsync done, cameraIndex={cameraIndex}, procedureId={prcId}, elapsedMs={executeWatch.ElapsedMilliseconds}");
|
|
|
if (targetPoint.AiVision == 1)
|
|
if (targetPoint.AiVision == 1)
|
|
|
{
|
|
{
|
|
|
var targetPoint2 = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == targetPoint.AiVision);
|
|
var targetPoint2 = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == targetPoint.AiVision);
|
|
|
|
|
+ var aiExecuteWatch = Stopwatch.StartNew();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} AiVision ExecuteProcedureAsync start, aiPoint={targetPoint.AiVision}, procedureId={targetPoint2?.CameraProcedureId1}");
|
|
|
await ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId1, tt.imges, Is3dPhoto, currentProduct);
|
|
await ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId1, tt.imges, Is3dPhoto, currentProduct);
|
|
|
|
|
+ aiExecuteWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} AiVision ExecuteProcedureAsync done, aiPoint={targetPoint.AiVision}, elapsedMs={aiExecuteWatch.ElapsedMilliseconds}");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
bool Is3dPhoto = Is3D(prcId);
|
|
bool Is3dPhoto = Is3D(prcId);
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} enqueue GrabImageEx task, cameraIndex={cameraIndex}, procedureId={prcId}, is3D={Is3dPhoto}");
|
|
|
_ImageTaskList.Add(GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig));
|
|
_ImageTaskList.Add(GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig));
|
|
|
if (targetPoint.AiVision == 1)
|
|
if (targetPoint.AiVision == 1)
|
|
|
{
|
|
{
|
|
@@ -2541,24 +2575,33 @@ namespace TeamAAS_VP.Core
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (sysConfig.TurnOnAllLightUse == false)
|
|
|
|
|
- {
|
|
|
|
|
- await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // [DEBUG] 光源控制已临时屏蔽
|
|
|
|
|
+ // if (sysConfig.TurnOnAllLightUse == false)
|
|
|
|
|
+ // {
|
|
|
|
|
+ // await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure);
|
|
|
|
|
+ // }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (cameraIndex != currentProduct.PhotoCountStop)
|
|
if (cameraIndex != currentProduct.PhotoCountStop)
|
|
|
{
|
|
{
|
|
|
//直接放行,执行下一个检测点
|
|
//直接放行,执行下一个检测点
|
|
|
- await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
|
|
|
|
|
|
|
+ var statusWriteWatch = Stopwatch.StartNew();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} status write start, node={addressConfig.Out_FixedCameraPickStatus.Address}, value=1, beforeImageTaskCount={_ImageTaskList.Count}, thread={Thread.CurrentThread.ManagedThreadId}");
|
|
|
|
|
+ bool statusWriteResult = await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
|
|
|
|
|
+ statusWriteWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} status write done, node={addressConfig.Out_FixedCameraPickStatus.Address}, value=1, result={statusWriteResult}, elapsedMs={statusWriteWatch.ElapsedMilliseconds}");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (_ImageTaskList.Count > 0)//如果2D取图有队列
|
|
if (_ImageTaskList.Count > 0)//如果2D取图有队列
|
|
|
{
|
|
{
|
|
|
//并发
|
|
//并发
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} image task batch start, taskCount={_ImageTaskList.Count}");
|
|
|
_ = Task.Run(async () =>
|
|
_ = Task.Run(async () =>
|
|
|
{
|
|
{
|
|
|
|
|
+ var imageBatchWatch = Stopwatch.StartNew();
|
|
|
var ImageTaskResults = await Task.WhenAll(_ImageTaskList);
|
|
var ImageTaskResults = await Task.WhenAll(_ImageTaskList);
|
|
|
|
|
+ imageBatchWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} image task batch done, taskCount={ImageTaskResults.Length}, elapsedMs={imageBatchWatch.ElapsedMilliseconds}");
|
|
|
foreach (var item in ImageTaskResults)
|
|
foreach (var item in ImageTaskResults)
|
|
|
{
|
|
{
|
|
|
if (item.IsSucceed)
|
|
if (item.IsSucceed)
|
|
@@ -4213,9 +4256,21 @@ namespace TeamAAS_VP.Core
|
|
|
|
|
|
|
|
private void SendTaskMessage(string msg, MessageLevel level)
|
|
private void SendTaskMessage(string msg, MessageLevel level)
|
|
|
{
|
|
{
|
|
|
- _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
|
|
|
|
|
+ _messageQueue.Enqueue(new Models.MessageStruct() { Message = msg, level = level });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 定时将消息队列批量推送到 UI 线程,200ms 一次,单次 BeginInvoke
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private void FlushMessageQueue()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (_messageQueue.IsEmpty) return;
|
|
|
|
|
+ App.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
|
{
|
|
{
|
|
|
- _eventAggregator.GetEvent<TaskMessageNotification>().Publish(new Models.MessageStruct() { Message = msg, level = level });
|
|
|
|
|
|
|
+ while (_messageQueue.TryDequeue(out var item))
|
|
|
|
|
+ {
|
|
|
|
|
+ _eventAggregator.GetEvent<TaskMessageNotification>().Publish(item);
|
|
|
|
|
+ }
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
public bool concurrenty = true;
|
|
public bool concurrenty = true;
|
|
@@ -5839,6 +5894,7 @@ namespace TeamAAS_VP.Core
|
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|
|
|
private async Task<(bool IsSucceed, ICogImage[] imges, string Message, int pointIndex, Guid procedureId)> GrabImageEx(int pointIndex, Guid procedureId, bool Is3dPhoto, ProductModel currentProduct, SystemConfiguration sysConfig)
|
|
private async Task<(bool IsSucceed, ICogImage[] imges, string Message, int pointIndex, Guid procedureId)> GrabImageEx(int pointIndex, Guid procedureId, bool Is3dPhoto, ProductModel currentProduct, SystemConfiguration sysConfig)
|
|
|
{
|
|
{
|
|
|
|
|
+ var grabExWatch = Stopwatch.StartNew();
|
|
|
// 获取当前产品
|
|
// 获取当前产品
|
|
|
//var currentProduct = _productService.GetCurrentProduct();
|
|
//var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null)
|
|
if (currentProduct == null)
|
|
@@ -5855,6 +5911,7 @@ namespace TeamAAS_VP.Core
|
|
|
|
|
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
|
|
+ var procFindWatch = Stopwatch.StartNew();
|
|
|
ProcedureModel selectedProcedure = null;
|
|
ProcedureModel selectedProcedure = null;
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
@@ -5870,6 +5927,8 @@ namespace TeamAAS_VP.Core
|
|
|
{
|
|
{
|
|
|
LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
|
|
LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
|
|
|
}
|
|
}
|
|
|
|
|
+ procFindWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] GrabImageEx procFind done, pointIndex={pointIndex}, procId={procedureId}, is3D={Is3dPhoto}, elapsedMs={procFindWatch.ElapsedMilliseconds}, thread={Thread.CurrentThread.ManagedThreadId}");
|
|
|
|
|
|
|
|
if (selectedProcedure == null)
|
|
if (selectedProcedure == null)
|
|
|
{
|
|
{
|
|
@@ -5883,10 +5942,19 @@ namespace TeamAAS_VP.Core
|
|
|
//var sysConfig = _configService.GetSystemConfiguration();
|
|
//var sysConfig = _configService.GetSystemConfiguration();
|
|
|
if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
|
|
if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
|
|
|
{
|
|
{
|
|
|
|
|
+ var lightWatch = Stopwatch.StartNew();
|
|
|
await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
|
|
await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
|
|
|
|
|
+ lightWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] GrabImageEx SetLightBeforePhoto done, pointIndex={pointIndex}, elapsedMs={lightWatch.ElapsedMilliseconds}");
|
|
|
}
|
|
}
|
|
|
//1. 执行拍照
|
|
//1. 执行拍照
|
|
|
|
|
+ var grabAsyncWatch = Stopwatch.StartNew();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] GrabImageEx ExecuteGrabImageAsync start, pointIndex={pointIndex}, procedureId={procedureId}, is3D={Is3dPhoto}, cameraId={selectedProcedure.CameraId}, photoCount={selectedProcedure.PhotoCount}, thread={Thread.CurrentThread.ManagedThreadId}");
|
|
|
var res = await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure, Is3dPhoto, sysConfig);
|
|
var res = await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure, Is3dPhoto, sysConfig);
|
|
|
|
|
+ grabAsyncWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] GrabImageEx ExecuteGrabImageAsync done, pointIndex={pointIndex}, procedureId={procedureId}, success={res.IsSucceed}, elapsedMs={grabAsyncWatch.ElapsedMilliseconds}, msg={res.Msg}");
|
|
|
|
|
+ grabExWatch.Stop();
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[PLC-TRACE] GrabImageEx total done, pointIndex={pointIndex}, procedureId={procedureId}, totalElapsedMs={grabExWatch.ElapsedMilliseconds}");
|
|
|
return (res.IsSucceed, res.Image, res.Msg, pointIndex, procedureId);
|
|
return (res.IsSucceed, res.Image, res.Msg, pointIndex, procedureId);
|
|
|
}
|
|
}
|
|
|
catch (Exception ex)
|
|
catch (Exception ex)
|