一个优秀的工业级上位机,不只是“功能能运行”,还必须满足:
- 通讯稳定;
- 流程状态明确;
- 断线可恢复;
- 停止、复位、结批不会卡死;
- 多工站互不影响;
- 故障可追溯;
- 数据不丢失;
- 现场人员可诊断;
- 代码可以测试和扩展。
结合当前项目,结论是:
当前架构已经具备工业上位机的基础,但还属于“功能型业务架构”,尚未完全达到高可靠工业级架构标准。最大问题不是项目分层,而是状态管理、生命周期、异常处理和通讯恢复机制还不够统一。
一、当前架构梳理
当前解决方案大致如下:
MaxWell WPF界面 ViewModel 窗体、按钮、弹窗、显示状态 MaxWell.Driver.M 工站业务 自动测试流程 上料、搬运、预测试、正式测试、吹扫、下料 PLCController 工站流水线 MaxWell.Device AuxPLC MainBoard Scanner RFID LoadUnit 设备协议和报文解析 MaxWell.Communication TCP连接 Socket 通讯队列 底层连接管理 MaxWell.Automation 自动化 TCP/JSON 协议 AutomationBusinessHandler MaxWell.SecsGem SECS/GEM 通讯 MaxWell.Models 配方、状态、结果、配置、公共数据模型这个分层方向是正确的,尤其是:
AuxPLC已经放到MaxWell.Device;PLCController负责 PLC 业务信号映射;AutomaticStationPipeline使用 Channel 管理多阶段业务;- 自动化和 EAP 已经逐渐分开;
- 配方校验、PackageType 光电位置、日志分类已经开始公共化。
二、目前最需要优化的部分
1. 工站状态分散,容易产生状态冲突
当前状态分散在多个位置:
StationControlViewModelAutomaticRealtimeAcquisitionServiceAutomaticStationPipelineEnvironmentDataUniverseDataPLCController- 自动化和 EAP Handler
同时存在很多布尔字段,例如:
_stopRequested _isResetting _isBatchClosing _allowLoading _allowUnloading _automationControlsSot _waitingForNextAllowLoadingCycle _automaticLoadReleased这些字段可以组合出大量非法状态,例如:
正在复位 + 允许上料 正在结批 + 自动化仍可投料 停止中 + 流水线仍可接收新请求这也是“复位后不再触发”“结批后重新开批卡住”“收到 SOTReq 但不搬运”等问题的根本来源之一。
优化方向
每个工站应该只有一个统一的运行状态对象:
设备状态: Offline Connecting Initializing Idle Running Stopping Resetting ClosingBatch Faulted 工艺阶段: WaitingLoad Loading Transfer Testing Purging WaitingUnload Completed Failed 控制来源: Manual Automation Eap业务只通过状态转换改变状态,不再由多个布尔值自由组合。
2. PLC 轮询、事件和业务流程没有统一
当前PLCController有SignalChanged,但业务主要仍使用while + Task.Delay等待。
这会造成:
- 每个流程都有自己的等待代码;
- 超时逻辑重复;
- 取消逻辑重复;
- 日志格式不统一;
- 多个流程可能同时等待同一个信号;
- 条件判断容易漏掉当前已经成立的信号。
另外,当前单个信号变化事件不适合复杂组合条件。U、V、W 等信号可能在同一次轮询中分批更新,业务可能读到不完整状态。
优化方向
建立每站唯一的:
PlcPollingService -> 读取一批 PLC 信号 -> 生成完整 PlcSnapshot -> 标记采集时间、序列号、通讯质量 -> 发布 SnapshotChanged业务统一使用:
WaitForStateAsync WaitForRisingEdgeAsync WaitForFallingEdgeAsync WaitForConditionsAsync注意:这不是取消 PLC 轮询,而是让业务由“快照变化”唤醒。
3. 通讯层错误处理过于宽松
AuxPLC中有多处捕获异常后直接返回null或错误码。
这种做法虽然可以避免程序崩溃,但会隐藏真正故障:
PLC断线 读取超时 响应格式错误 地址配置错误 设备拒绝请求最后业务只能看到:
条件不满足 无响应 执行失败还可能继续使用旧缓存值,产生危险误判。
优化方向
每次通讯结果必须明确区分:
Success Timeout Disconnected ProtocolError InvalidAddress DeviceRejected CancelledPLC 快照需要包含:
Sequence ReadTime IsValid LastSuccessfulReadTime ConsecutiveFailureCount ErrorMessage读取失败后,安全信号应变为“未知/无效”,不能继续使用旧值执行上料、搬运和测试。
4. 设备通讯虽然有队列,但缺少统一的设备命令调度策略
当前AuxPLC有EnqueueExecute,主控板也有自己的执行器或命令队列。方向是正确的,但工业级设备通常还需要:
- 每个设备只有一个命令出口;
- 读写命令不能相互交叉;
- 停止、复位、急停类命令具有更高优先级;
- 普通实时查询不能阻塞安全命令;
- 每个命令必须有超时和唯一请求编号;
- 重试必须区分幂等命令和非幂等命令。
优化方向
每个物理设备建立独立的DeviceCommandScheduler:
高优先级: 停止 复位 关闭测试使能 关闭高压 普通优先级: 测试命令 配方下发 状态读取 实时查询同一个物理设备不能由多个业务类直接调用底层发送方法。
5. 任务生命周期不完整
当前部分Stop()方法只调用取消,没有等待后台任务真正退出。例如:
- PLC 轮询任务;
- 自动实时采集任务;
- 自动流水线 Worker;
- 等待信号任务。
这样会出现:
旧任务尚未退出 新任务已经启动 旧任务继续写日志、更新状态或执行 PLC 命令这会直接导致:
- 重复上料;
- 复位后旧流程重新触发;
- 同一个 PLC 出现多个轮询任务;
- 结批后
_automaticPipeline仍然有活动记录。
优化方向
所有后台服务统一实现:
StartAsync StopAsync DisposeAsync停止流程必须是:
禁止接收新任务 取消等待 等待 Worker 完成 清理活动产品 解除事件订阅 释放资源不能只调用Cancel()就认为流程已经停止。
6.AutomaticStationPipeline的方向正确,但需要强化清理
当前 Channel 多 Worker 适合工业流程,但需要重点确认:
- 失败时是否一定从活动产品表删除;
- 取消时是否一定执行清理;
- 队列中的产品是否能被取消;
- 停止时是否等待所有 Worker;
- 下料等待时是否阻塞其他产品;
- 结批后是否允许旧请求重新进入。
建议建立统一的产品生命周期:
Created Loading Loaded Transferring Testing Purging WaitingUnload Completed Failed Cancelled Cleaned无论成功、失败还是取消,最终都必须进入Cleaned。
Finish()不能只在正常路径调用,异常和取消也必须经过统一收尾。
7. ViewModel 业务职责过重
StationControlViewModel目前同时承担:
- 按钮状态;
- PLC 判断;
- 自动模式;
- EAP;
- 自动化;
- 复位;
- 停止;
- 结批;
- 测试;
- 取料;
- 弹窗;
- 日志;
- 状态显示。
即使拆成多个.partial.cs文件,本质仍然是一个巨大类。
优化方向
建议逐步拆成:
StationLifecycleService 初始化、复位、停止、结批 StationMaterialService 上料、搬运、清料、取料 StationTestService 预测试、正式测试、结果保存 StationRuntime 当前工站唯一状态 StationAutomationService 自动化协议 StationEapService SECS/GEM协议 StationUiAdapter WPF属性、灯态、弹窗ViewModel 只做:
接收按钮命令 调用业务服务 订阅状态变化 更新界面8. 全局静态状态较多,影响多工站隔离和测试
当前存在类似:
EnvironmentDataUniverseDataDeviceManager.InstanceLogHelper- 静态缓存和静态服务
全局对象使用方便,但工业设备中容易出现:
- A 站状态污染 B 站;
- 上一批数据残留到下一批;
- 单元测试无法构造独立环境;
- 关闭工站后对象仍被引用;
- 多线程访问没有明确边界。
优化方向
尽量采用:
IStationRuntimeContext IClock IDeviceManager ILogger IRecipeProvider IDataFileService每个工站创建独立上下文,公共服务只负责无状态能力。
全局数据可以保留用于 UI 汇总,但不能作为核心业务状态的唯一来源。
9. 日志已经分类,但还缺少统一事件模型
当前已经区分:
PrintElectricalErrorLog PrintAuxControlErrorLog PrintAutomationErrorLog这是正确方向,但还需要统一日志字段:
时间 工站 批次 器件 设备 流程阶段 命令名称 发送/接收 请求编号 错误码 耗时 重试次数 异常类型日志不能只保存一段中文字符串,否则很难检索和统计。
建议采用:
结构化日志 + 现场可读日志原始报文单独保存,业务日志保存解析后的信息。
10. 数据保存应采用“先写缓存,再正式归档”的可靠模型
当前已经有缓存文件、正式文件和备份文件的概念,这是工业数据保存的正确方向。
还需要进一步保证:
- 每条实时采集数据写入成功后才能确认;
- 文件写入不能阻塞测试线程;
- 写入失败必须进入重试队列;
- 进程崩溃后可以恢复未完成文件;
- 结批复制必须支持断点和校验;
- 目标目录不存在时自动创建;
- 数据文件需要校验记录数和文件大小;
- 备份失败不能静默忽略。
推荐:
测试线程 -> 有界 Channel CSV后台写入线程 -> 缓存文件 测试完成 -> 单器件文件归档 结批 -> 汇总文件归档三、工业级目标架构
建议目标架构如下:
┌─────────────────────────────┐ │ WPF UI │ │ 页面、按钮、属性、弹窗 │ └──────────────┬──────────────┘ │ ┌──────────────▼──────────────┐ │ Application Layer │ │ 工站服务、批次服务、流程服务 │ └──────────────┬──────────────┘ │ ┌──────────────▼──────────────┐ │ Station Runtime │ │ 状态机、快照、流水线、取消机制 │ └──────────────┬──────────────┘ │ ┌──────────────▼──────────────┐ │ Device Abstraction │ │ PLC、主控板、负载、扫描器、RFID │ └──────────────┬──────────────┘ │ ┌──────────────▼──────────────┐ │ Communication Layer │ │ TCP、Modbus、SECS/GEM、重连 │ └─────────────────────────────┘自动化和 EAP 应该是协议适配器:
AutomationAdapter EapSecsGemAdapter │ ▼ StationApplicationService │ ▼ StationRuntime两种协议可以不同,但不能各自复制一套上料、测试、下料逻辑。
四、目前距离工业级标准的评价
| 模块 | 当前情况 | 评价 |
|---|---|---|
| 项目分层 | 已有基础分层 | 基本合理 |
| 设备驱动隔离 | AuxPLC、主控板已独立 | 较合理 |
| 多工站并行 | 有独立流水线 | 需要强化生命周期 |
| PLC状态判断 | 缓存和轮询已有 | 需要统一快照事件 |
| 通讯串行化 | 部分设备已有队列 | 需要统一调度和优先级 |
| 断线恢复 | 有部分重试 | 不够统一 |
| 状态机 | 主要依赖多个布尔值 | 需要重点重构 |
| 取消机制 | 有多个取消源 | 生命周期不够清晰 |
| 异常处理 | 部分异常被吞掉 | 需要结构化错误 |
| 日志 | 已分类 | 需要结构化和关联请求 |
| 数据存储 | 有缓存和归档 | 需要可靠写入和恢复 |
| UI与业务解耦 | ViewModel仍较重 | 需要拆分 |
| 自动化/EAP扩展 | 已分开 | 需要统一业务入口 |
| 自动化测试 | 需要增加 | 当前不足 |
五、推荐优化顺序
严格按照下面顺序,每完成一步后上机验证,再进入下一步:
1. 建立基线和通讯日志 2. 修复设备连接、轮询和任务停止生命周期 3. 增加PLC完整快照和通讯质量 4. 统一PlcCondition等待器 5. 先替换一个低风险等待点 6. 逐个替换上料、搬运、测试、吹扫、取料等待 7. 优化自动流水线取消和产品清理 8. 集中工站状态,减少布尔字段 9. 拆分StationControlViewModel 10. 完善自动化和EAP协议适配器 11. 完善数据恢复、权限、审计和自动化测试六、最终判断
当前项目不需要改成微服务,也不建议拆成多个独立进程。工业设备上位机更适合:
单进程、模块化、每个工站独立运行时、每个设备单独通讯队列、流程使用状态机和 Channel。
当前最应该优先解决的是:
- 工站状态统一;
- PLC 快照和通讯有效性;
- 任务停止和取消;
- 设备命令串行化;
- 流程失败后的统一清理;
- ViewModel 与业务解耦。
完成这些后,当前项目才会从“可以运行”逐步提升为“稳定运行、可恢复、可维护、可扩展”的工业级上位机架构。