
上位机报警界面的核心挑战在于PLC、机器人、相机三类设备的通信机制完全不同报警的“发生—确认—消失”状态流转逻辑复杂且必须在 UI 层做线程安全的汇聚展示。这里从架构到三类设备的具体对接方式逐层拆解。️ 整体架构报警汇聚层是核心报警界面不能让每个设备的回调线程直接去更新 UI也不能把报警判定逻辑塞在通信循环里。推荐的结构是六层工作域 事件总线┌─────────────────────────────────────────────────────┐ │ UI 线程仅显示与交互不阻塞、不计算 │ ├─────────────────────────────────────────────────────┤ │ 报警汇聚层Alarm Hub │ │ - 订阅三类设备的报警事件 │ │ - 统一报警编号、级别、时间戳 │ │ - 维护报警状态机Raised → Acked → Cleared │ │ - 节流同一条报警 5 秒内不重复弹窗 │ ├─────────────────────────────────────────────────────┤ │ 事件总线EventBus │ │ - 所有线程通过 ChannelT 或 BlockingCollection 通信 │ ├──────────────┬──────────────┬───────────────────────┤ │ PLC 通信线程 │ 机器人线程 │ 相机回调线程 │ │ S7/Modbus│ PC SDK/ │ Basler/海康 SDK │ │ │ TCP 直连 │ │ └──────────────┴──────────────┴───────────────────────┘关键原则相机 SDK 的回调线程“什么都别干除了入队”。PLC 通信线程只负责周期读写数据镜像报警判定放在独立的报警循环里读镜像。这样任何一路设备卡死或断线都不会让报警界面失去响应。 三类设备的报警获取方式完全不同PLC读数据镜像自己判定报警PLC 报警有两种模式PLC 内部判定PLC 程序比较阈值置位一个 BOOL 变量和上位机判定上位机读模拟量自己比较。推荐优先用 PLC 判定因为 PLC 的扫描周期确定判定时机精确。上位机侧的做法通信线程周期性读取报警位到ProcessImage对象中报警循环每个周期检查镜像里的报警位检测上升沿从 0 变 1时触发报警事件。机器人通过组输出信号映射故障码这是三类设备中最需要协议设计的。ABB 机器人的典型做法是在机器人控制器中配置系统输出或错误处理程序将故障码写入一个组输出信号PLC 读取该组信号后传递给上位机。具体流程整理一份故障码清单Errnum→ 文本描述例如119136: Robot not on path。在机器人错误处理程序中执行SetGO goMyErrorGroup, ERRNO把故障码写入组输出。PLC 读取该组输入上位机从 PLC 数据镜像中获取故障码查表得到报警文本。优先使用系统输出如ExecutionError、MotorsOn因为系统输出不依赖 RAPID 程序是否在执行更可靠。用户自定义的TPWrite消息则需要确认是否已写入事件日志并非所有消息都会自动进入 EVENTS。相机回调线程只做“入队 标记”相机的报警来源有两种SDK 内部的错误回调相机掉线、触发超时、采集失败和算法判定的 OK/NG 结果。无论哪种回调线程的处理逻辑都是复制数据 写入一个带时间戳的报警记录 丢进队列然后立即返回。相机掉线自动重连是必备功能。开一个后台线程定时发心跳连续 3 次无响应就判定掉线标记工位状态为异常并通知 MES 或上位机报警层不要静默重连导致产线“盲跑”。 报警状态机比“弹窗”重要得多一条报警的完整生命周期不是“发生 → 弹窗 → 关掉”这么简单。标准的工业报警状态流转是正常 → 报警发生(Raised) → 操作员确认(Acknowledged) → 报警消失(Cleared) → 归档中间的“已确认但未消失”Acked but not Cleared状态是最重要的操作员按了确认按钮声音停了弹窗不再闪烁但报警仍然处于激活状态设备的实际故障还没排除。这时报警记录不能从界面上消失必须以“已确认”的视觉状态保留。数据库设计要存事件流不是只存“当前状态”。每条记录包含报警名、级别、发生时间、确认时间、确认人、消失时间。这样才能回答“这条报警是谁什么时候处理的”。️ 用 HslControls 做报警界面呈现报警界面的视觉层可以结合 HslControls 的控件来增强表达信号灯控件每个报警位对应一盏灯颜色编码灰正常黄未确认红已确认但未消失绿消失归档。HslControls 的信号灯支持渐变和闪烁效果比标准 PictureBox 更直观。数码管控件显示“当前活动报警数”“未确认报警数”等统计值。实时曲线如果报警与温度、压力等模拟量关联在报警发生时用辅助线标记阈值线操作员能立即看到触发报警的数据点位置。弹窗节流是必须的同一条报警在 5 秒内不重复弹窗。如果 PLC 的报警位因为通信抖动而快速跳变没有节流的话弹窗会刷屏。做法是在报警汇聚层维护一个Dictionarystring, DateTime _lastPopupTime触发弹窗前检查距上次弹出是否超过节流窗口。 调试重点状态转换的边界报警界面的调试核心在状态机边界用条件断点验证“未确认就消失”报警从Raised直接跳到Cleared没有经过Acknowledged。状态记录应该标记为RaisedCleared而不是错误地记录为RaisedAcknowledgedCleared。“重复报警”同一个报警位在 1 秒内跳变多次通信抖动导致验证去抖逻辑是否生效。“确认权限”如果报警复位需要权限如工程师级在确认逻辑处设断点验证低权限用户的操作被正确拦截。 核心思维提炼1. 报警不是“消息”是“状态机”PLC 编程里用R_TRIG检测上升沿触发报警C# 里的报警汇聚层必须实现同样的边沿检测逻辑。不要每次读到的报警位是 1 就触发一次那会重复报警。2. 三类设备的通信差异要用“事件总线”抹平相机回调线程是 SDK 的非托管线程机器人可能通过组输出信号PLC 是周期读写。事件总线让报警汇聚层不需要关心报警来自哪里只处理“一条报警发生了”这个事实。3. UI 只做最后一件事渲染报警汇聚层完成所有判定、去抖、状态流转然后把一个已经确定状态的报警对象推送到 UI。UI 收到后只负责弹窗、变色、写入 ListBox。不要在 UI 事件里做任何等待、查询、判断。4. 相机报警最容易出“静默故障”PLC 断线你会看到通信超时机器人报错你会看到故障码。但相机可能静默掉线——没有回调、没有异常只是不再产生图像。必须用心跳机制主动检测不能依赖 SDK 的错误回调。