跳到主要内容

事件与动作

Vision Studio 采用事件驱动模型,视觉程序在执行过程中触发事件,绑定的事件处理器自动执行相应动作。事件机制实现了视觉程序与 PLC 逻辑的松耦合联动。

事件模型

┌────────────────────────────────────────────┐
│ 视觉程序执行流程 │
│ │
│ 触发信号 ──→ 采集 ──→ 预处理 ──→ 推理 ──→ 输出 │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ OnTrigger OnFrame OnInference │
│ Completed │
│ │
│ 异常 ──→ OnFault │
│ 超时 ──→ OnTimeout │
└────────────────────────────────────────────┘

事件列表

OnTrigger (触发事件)

当视觉程序被触发时触发,发生在采集开始之前。

触发时机:收到触发信号(软件、硬件、PLC 变量或定时)的瞬间

事件参数

参数类型说明
trigger_sourceSTRING触发源("PLC"/"HARDWARE"/"SOFTWARE"/"TIMER")
trigger_timestampLWORD触发时间戳
trigger_countDWORD触发累计次数
last_result_statusDWORD上次执行状态

示例用途

  • 重置累计计数器
  • 记录触发时间
  • 检查上次执行状态,决定是否继续

OnFrame (帧事件)

当相机采集到一帧图像时触发,发生在图像预处理之前。

触发时机:图像采集完成,图像数据就绪

事件参数

参数类型说明
imageImage采集到的原始图像
acquisition_time_msREAL采集耗时
exposure_timeREAL实际曝光时间 (µs)
gainREAL实际增益 (dB)

示例用途

  • 检查图像质量(亮度、对比度)
  • 动态调整曝光参数
  • 保存原始图像用于追溯

OnInferenceCompleted (推理完成事件)

当推理完成并得到结果时触发。

触发时机:模型推理完成,结果已生成

事件参数

参数类型说明
resultDetectionResult检测结果
inference_time_msREAL推理耗时
model_nameSTRING模型名称
input_sizeSTRING输入尺寸(如 "640x640")

示例用途

  • 根据结果执行条件分支
  • 触发二次确认流程
  • 记录推理性能指标

OnFault (故障事件)

当视觉程序执行过程中发生故障时触发。

触发时机:相机断开、模型加载失败、推理异常等

事件参数

参数类型说明
error_codeDWORD错误码
error_messageSTRING错误描述
fault_sourceSTRING故障来源("CAMERA"/"MODEL"/"INFERENCE"/"SYSTEM")
recoverableBOOL是否可自动恢复

故障事件不触发 OnTimeout:OnFault 覆盖超时以外的所有异常

示例用途

  • 切换备用相机
  • 记录故障日志
  • 通知 PLC 进入安全状态

OnTimeout (超时事件)

当视觉程序执行超过配置的超时时间时触发。

触发时机:采集或推理超过 timeout_ms 配置值

事件参数

参数类型说明
timeout_msDWORD配置的超时值
elapsed_msDWORD实际已耗时
stageSTRING超时阶段("ACQUISITION"/"INFERENCE")

OnTimeout 与 OnFault 互斥:超时场景只触发 OnTimeout,不触发 OnFault

示例用途

  • 输出默认结果值
  • 记录超时到诊断日志
  • 触发降级处理流程

事件绑定

在卡片图编辑器中绑定

  1. 选中要绑定事件的卡片
  2. 在属性面板中选择 事件 标签页
  3. 点击事件旁边的 + 按钮添加动作
┌──────────────────────────────────────┐
│ 卡片: 目标检测 │
│ ┌──────┬─────────────────────────┐ │
│ │ 参数 │ 事件 │ │
│ ├──────┼─────────────────────────┤ │
│ │ │ ● OnInferenceCompleted │ │
│ │ │ ├─ 写入 PLC 变量 │ │
│ │ │ ├─ 保存图像 │ │
│ │ │ └─ 记录日志 │ │
│ │ │ │ │
│ │ │ ○ OnFault │ │
│ │ │ └─ 切换备用相机 │ │
│ │ │ │ │
│ │ │ ○ OnTimeout │ │
│ │ │ └─ 输出默认值 │ │
│ └──────┴─────────────────────────┘ │
│ │
│ [+ 添加动作] │
└──────────────────────────────────────┘

在 Vision SCL 中绑定

PROGRAM VisionWithEvents
VAR
cam : Camera;
img : Image;
result : DetectionResult;
END_VAR

// 注册事件处理器
EVENT_BIND(EVENT_ON_TRIGGER, "OnTriggerHandler");
EVENT_BIND(EVENT_ON_FRAME, "OnFrameHandler");
EVENT_BIND(EVENT_ON_INFERENCE_COMPLETED, "OnInferenceHandler");
EVENT_BIND(EVENT_ON_FAULT, "OnFaultHandler");
EVENT_BIND(EVENT_ON_TIMEOUT, "OnTimeoutHandler");

// 主流程
cam := CAM_Open("USB_CAM_1");
img := CAM_Capture(cam, TIMEOUT := 5000);
result := OBJ_Detect(img, MODEL := "model.onnx");

// 等待所有事件处理完成
EVENT_WAIT_ALL(TIMEOUT := 1000);
END_PROGRAM

// 事件处理器: 推理完成
ACTION OnInferenceHandler
VAR
i : INT;
END_VAR
VIS_Log(LOG_INFO, "推理完成, 检测到 " +
INT_TO_STRING(result.object_count) + " 个目标");

// 逐一输出结果
FOR i := 0 TO result.object_count - 1 DO
VIS_WriteVariable("VIS_OBJ_" + INT_TO_STRING(i) + "_CLASS",
STRING_TO_REAL(result.objects[i].class_name));
END_FOR;
END_ACTION

// 事件处理器: 故障处理
ACTION OnFaultHandler
VAR
alt_cam : Camera;
END_VAR
VIS_Log(LOG_ERROR, "视觉故障: " + error_message);

// 尝试切换备用相机
IF error_code = ERR_CAMERA_DISCONNECTED THEN
alt_cam := CAM_Open("USB_CAM_2");
IF alt_cam <> INVALID_CAMERA THEN
VIS_WriteVariable("VIS_CAM_SWITCHED", 1.0);
END_IF;
END_IF;
END_ACTION

// 事件处理器: 超时处理
ACTION OnTimeoutHandler
VIS_Log(LOG_WARN, "视觉超时: " + stage + " 已耗时 " +
INT_TO_STRING(elapsed_ms) + "ms");

// 输出默认值
VIS_WriteVariable("VIS_RESULT_COUNT", 0.0);
VIS_WriteVariable("VIS_JOB_TIMEOUT", 1.0);
END_ACTION

动作配置

可用动作类型

动作类型说明适用事件
写入 PLC 变量将指定值写入 PLC 变量全部
保存图像将当前图像保存到文件OnFrame, OnInferenceCompleted
记录日志写入诊断日志全部
发送通知发送报警或通知OnFault, OnTimeout
执行 SCL 脚本执行一段 Vision SCL 代码全部
触发另一视觉程序启动另一个视觉 JobOnInferenceCompleted
切换相机切换到备用相机OnFault
输出默认值输出预配置的默认结果OnTimeout

动作执行顺序

同一事件可以绑定多个动作,按配置顺序执行:

  1. 同步动作(如写入 PLC 变量、记录日志)立即执行
  2. 异步动作(如保存图像、触发另一 Job)加入队列,不阻塞主流程
  3. 所有动作在 EVENT_WAIT_ALL 超时时间内完成

动作条件

可以为动作设置执行条件,仅当条件满足时执行:

动作: 保存图像
条件: result.object_count > 0 // 仅当检测到目标时保存
条件类型说明示例
数值比较比较事件参数result.confidence > 0.8
字符串匹配匹配字符串参数trigger_source == "PLC"
布尔表达式组合条件pass AND count > 0
复合条件多条件 AND/OR(error_code <> 0) OR (elapsed_ms > 5000)

事件优先级

当多个事件同时发生时,按优先级处理:

优先级事件说明
最高OnFault故障优先处理
OnTimeout超时次之
OnTrigger触发事件
OnFrame帧事件
最低OnInferenceCompleted推理完成

最佳实践

  1. 事件处理器保持轻量:事件处理器中避免长时间操作,耗时操作应异步执行
  2. OnFault 必须处理:每个视觉程序都应绑定 OnFault,确保故障可追溯
  3. OnTimeout 设置默认值:超时时输出默认结果,避免 PLC 读到脏数据
  4. 避免事件循环:注意不要在事件处理器中触发同一事件,防止无限循环
  5. 日志分级:OnFault 用 ERROR 级别、OnTimeout 用 WARN 级别、正常事件用 INFO 级别