12 KiB
12 KiB
CNC 执行机制说明
概述
CncExecutionService 是 CNC 程序的核心执行引擎,负责按节点顺序执行整个检测程序。它协调运动控制、图像采集、流水线处理和结果归档等子系统,实现自动化多位置检测流程。
类定义
| 类 | 文件 | 职责 |
|---|---|---|
CncExecutionService |
Services/Cnc/CncExecutionService.cs |
CNC 程序执行引擎 |
ICncExecutionService |
Services/Cnc/ICncExecutionService.cs |
执行服务接口 |
CncEditorViewModel |
ViewModels/Cnc/CncEditorViewModel.cs |
调用执行服务的 ViewModel |
依赖注入
CncExecutionService 通过构造函数注入以下服务:
| 依赖 | 接口 | 用途 |
|---|---|---|
| 检测结果存储 | IInspectionResultStore |
归档检测运行记录和节点结果 |
| 日志 | ILoggerService |
结构化日志记录 |
| 主视口 | IMainViewportService |
获取实时图像、推送结果图像 |
| 应用状态 | IAppStateService |
获取探测器帧数据 |
| 流水线执行 | IPipelineExecutionService |
执行图像处理流水线 |
| 图像处理 | IImageProcessingService |
获取算子定义和参数 |
| 事件聚合器 | IEventAggregator |
订阅探测器断连事件 |
| 图像持久化 | IImagePersistenceService |
保存采集图像到磁盘 |
| 运动控制 | IMotionControlService(可选) |
控制各轴移动到目标位置 |
| 运动系统 | IMotionSystem(可选) |
查询轴状态(是否到位) |
| 射线源 | IRaySourceService(可选) |
射线源控制 |
执行流程
入口方法
Task ExecuteAsync(CncProgram program, IProgress<CncNodeExecutionProgress> progress, CancellationToken cancellationToken)
执行阶段
┌─────────────────────────────────────────────────────────────┐
│ 1. 初始化阶段 │
│ - 创建 LinkedCancellationTokenSource(支持探测器断连取消) │
│ - 获取初始源图像 │
│ - 调用 _store.BeginRunAsync() 创建检测运行记录 │
├─────────────────────────────────────────────────────────────┤
│ 2. 多位置执行循环(SavePositionNode) │
│ 对每个 SavePositionNode 按顺序执行: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 0: 运动到目标位置 (MoveToPositionAsync) │ │
│ │ Step 1: 图像采集(探测器实时帧 或 手动图像文件) │ │
│ │ Step 2: 图像保存(如果 SaveImage=true) │ │
│ │ Step 3: 流水线执行(如果下一节点是 InspectionModule) │ │
│ │ Step 4: 报告节点执行状态 │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 3. 批次结果汇总 │
│ - 构建 BatchCaptureResult │
│ - 调用 _imagePersistenceService.WriteSummaryAsync() │
├─────────────────────────────────────────────────────────────┤
│ 4. 非位置节点执行 │
│ 按 Index 顺序处理剩余节点: │
│ - ReferencePointNode: 记录参考点参数 │
│ - SaveNodeNode / SaveNodeWithImageNode: 记录设备状态 │
│ - WaitDelayNode: 延时等待(带进度报告) │
│ - PauseDialogNode: 弹出暂停对话框 │
│ - InspectionModuleNode: 执行图像处理流水线 │
│ - CompleteProgramNode: 标记程序完成,退出循环 │
├─────────────────────────────────────────────────────────────┤
│ 5. 完成阶段 │
│ - 调用 _store.CompleteRunAsync() 标记运行结束 │
│ - 清理 CancellationTokenSource │
│ - 通知 MainViewportService CNC 执行结束 │
└─────────────────────────────────────────────────────────────┘
核心方法说明
ExecuteAsync — 主执行入口
| 参数 | 类型 | 说明 |
|---|---|---|
program |
CncProgram |
待执行的 CNC 程序(含所有节点) |
progress |
IProgress<CncNodeExecutionProgress> |
进度回调(通知 UI 更新节点状态) |
cancellationToken |
CancellationToken |
外部取消令牌(用户点击停止) |
关键行为:
- 使用
LinkedCancellationTokenSource将外部取消和探测器断连事件合并 - 每个节点执行前检查取消状态
- 失败节点不中断整体执行(容错设计),仅标记为 Failed 并继续
MoveToPositionAsync — 运动控制
private Task<MotionResult> MoveToPositionAsync(MotionState target, CancellationToken ct)
- 将
MotionState中的微米(μm)坐标转换为毫米(mm)后发送给运动控制服务 - 依次移动:StageX → StageY → SourceZ → DetectorZ → DetectorSwing → StageRotation → FixtureRotation
- 任一轴移动失败立即返回错误
- 运动服务不可用时返回成功(优雅降级)
WaitForAxesSettledAsync — 等待轴到位
private async Task<bool> WaitForAxesSettledAsync(CancellationToken ct)
- 每 50ms 轮询所有线性轴和旋转轴的状态
- 所有轴
Status == Idle时返回true - 超时 30 秒返回
false(不中断执行,继续后续步骤)
TryGetSourceImage — 图像获取
private BitmapSource TryGetSourceImage()
图像源优先级:
MainViewportService.LatestManualImage(用户手动加载的图像)MainViewportService.CurrentDisplayImage(当前显示的实时图像)AppStateService.LatestDetectorFrame(原始探测器帧,Gray16 → BitmapSource)
ExecuteInspectionNodeAsync — 检测模块执行
private async Task<BitmapSource> ExecuteInspectionNodeAsync(
Guid runId, InspectionModuleNode inspectionNode, BitmapSource sourceImage, CancellationToken ct)
执行步骤:
- 创建
InspectionNodeResult记录 - 序列化 Pipeline 定义为 JSON 快照
- 保存输入图像为资产
- 调用
BuildPipelineNodeViewModels()构建流水线 ViewModel - 调用
_pipelineExecutionService.ExecutePipelineAsync()执行流水线 - 推送结果图像到主视口
- 推送检测叠加层数据(轮廓、标注)
- 合成背景图 + 叠加层,保存结果截图
- 调用
_store.AppendNodeResultAsync()归档节点结果
BuildPipelineNodeViewModels — 构建流水线 ViewModel
private IEnumerable<PipelineNodeViewModel> BuildPipelineNodeViewModels(PipelineModel pipeline)
- 将
PipelineModel.Nodes(数据模型)转换为PipelineNodeViewModel(执行模型) - 加载每个算子的参数定义和保存值
- 处理 JSON 参数值的类型转换(
JsonElement→int/double/bool/string)
ExecuteWaitDelayWithProgressAsync — 延时等待
private static async Task ExecuteWaitDelayWithProgressAsync(
WaitDelayNode waitNode, IProgress<CncNodeExecutionProgress> progress, CancellationToken ct)
- 每 50ms 报告一次进度百分比
- 支持取消(抛出
OperationCanceledException)
取消机制
| 取消源 | 触发方式 | 处理 |
|---|---|---|
| 用户点击停止 | CancellationToken 从 ViewModel 传入 |
各节点执行前检查 |
| 探测器断连 | DetectorDisconnectedEvent → _executionCts.Cancel() |
通过 LinkedCTS 传播 |
| 运动失败 | MoveToPositionAsync 返回失败 |
标记节点 Failed,继续下一个 |
进度报告
通过 IProgress<CncNodeExecutionProgress> 回调通知 UI:
public record CncNodeExecutionProgress(
Guid NodeId,
NodeExecutionState State,
double? ProgressPercent = null,
BitmapSource ResultImage = null,
int? PositionIndex = null,
int? TotalPositions = null);
ViewModel 收到回调后更新 CncNodeViewModel.ExecutionState,触发树形节点的颜色变化。
结果归档
| 方法 | 时机 | 存储内容 |
|---|---|---|
_store.BeginRunAsync() |
执行开始 | 运行记录 + 源图像 |
_store.AppendNodeResultAsync() |
每个检测模块执行后 | 节点结果 + Pipeline 快照 + 输入/输出图像 |
_store.CompleteRunAsync() |
执行结束 | 标记运行完成/失败 |
_imagePersistenceService.WriteSummaryAsync() |
多位置循环结束 | 批次结果 JSON 摘要 |
容错设计
- 图像采集失败:标记节点 Failed,跳过该位置,继续下一个
- 图像保存失败:标记节点 Failed,但仍继续执行流水线
- 流水线执行异常:捕获异常,标记 Failed,不中断整体执行
- 运动服务不可用:返回成功(优雅降级,适用于仿真模式)
- 探测器断连:通过事件取消整个执行
调用关系图
CncEditorViewModel
│
├── RunCncCommand → ExecuteRunAsync()
│ │
│ └── CncExecutionService.ExecuteAsync()
│ │
│ ├── IInspectionResultStore.BeginRunAsync()
│ │
│ ├── [循环] SavePositionNode
│ │ ├── MoveToPositionAsync() → IMotionControlService
│ │ ├── WaitForAxesSettledAsync() → IMotionSystem
│ │ ├── TryGetSourceImage() → IMainViewportService / IAppStateService
│ │ ├── IImagePersistenceService.SaveImageAsync()
│ │ └── ExecuteInspectionNodeAsync()
│ │ ├── BuildPipelineNodeViewModels()
│ │ ├── IPipelineExecutionService.ExecutePipelineAsync()
│ │ ├── IMainViewportService.SetCncResultImage()
│ │ ├── IMainViewportService.PushDetectionOverlay()
│ │ └── IInspectionResultStore.AppendNodeResultAsync()
│ │
│ ├── [循环] 非位置节点
│ │ ├── WaitDelayNode → ExecuteWaitDelayWithProgressAsync()
│ │ ├── PauseDialogNode → MessageBox
│ │ ├── InspectionModuleNode → ExecuteInspectionNodeAsync()
│ │ └── CompleteProgramNode → 退出
│ │
│ ├── IImagePersistenceService.WriteSummaryAsync()
│ └── IInspectionResultStore.CompleteRunAsync()
│
└── StopCncCommand → CancellationTokenSource.Cancel()