IgH EtherCAT Diagnostics V3.0:从故障记录工具到可解释诊断系统 IgH EtherCAT Diagnostics V3.0从故障记录工具到可解释诊断系统前段时间我开源了一个基于 IgH EtherCAT Master 的故障诊断项目IgH EtherCAT DiagnosticsGitHubhttps://github.com/VictorJiaxinWang/Igh_EtherCAT_Diagnostics最早发布 V1.1.0 时这个项目解决的问题比较直接EtherCAT 偶发掉站以后自动记录故障现场并尽量找出故障边界。最近项目已经更新到V3.0.0。从代码量上看V3.0 增加了 ioctl、ESC Port Error、根因分析、Web UI、systemd 等不少内容但我认为这次版本升级真正重要的并不是“功能更多了”而是项目的定位发生了变化。V1.1 更像一个EtherCAT 黑匣子。它擅长回答刚才发生了什么而 V3.0 开始尝试回答为什么会发生最可能坏在哪里接下来应该检查什么这篇文章就从这个变化开始讲。一、V1.1 已经解决了什么EtherCAT 通信故障最麻烦的地方并不是“看不出来坏了”而是很多问题出现以后很难还原当时的现场。例如一条总线上原本有 15 个从站Master | Slave0 | Slave1 | Slave2 | ... | Slave14某一时刻主站突然只能扫描到前 4 个节点Slave0 Slave1 Slave2 Slave3执行ethercat slaves当然能看到节点掉了。但真正排查问题时我们更关心的是什么时候开始掉的 哪些节点先消失 最后一个还能访问的节点是谁 故障之前有没有异常征兆 ESC 当时是什么状态 后来网络有没有真正恢复V1.1 做的就是把这些信息自动留下来。它以独立 Linux 进程运行不进入原有 PDO 实时线程也不接管 EtherCAT Master只作为旁路观察者存在。程序周期性获取Master 状态 Slave 列表 Slave AL 状态并转换成统一的NetworkSnapshot随后比较前后两次快照。例如上一时刻 0 1 2 3 4 5 当前 0 1 2程序可以判断Slave3 LOST Slave4 LOST Slave5 LOST同时根据拓扑变化找出last_alive Slave2 first_lost Slave3那么排查范围就从整条 EtherCAT 总线缩小到了Slave2 与 Slave3 附近。故障发生以后程序还会读取边界节点的0x0110 DL Status 0x0130 AL Status 0x0134 AL Status Code并保存故障前后的一段网络状态。这就是 V1.1 的主要能力持续观察 状态变化检测 掉站边界定位 ESC 主动取证 黑匣子记录 恢复检测这套机制已经能够解决很多“偶发掉站以后现场没留下来”的问题。但做到这里我逐渐发现了另一个问题数据已经留下来了最后还是需要工程师自己分析。于是后续版本开始把重点从“记录故障”转向“理解故障”。二、V3.0 最大的变化从状态监控变成证据驱动诊断我现在对故障诊断的理解是单个状态通常不能直接代表根因。比如Slave5 LOST只能说明 Slave5 当前访问不到。它并不能直接证明Slave5 坏了因为真正原因可能是Slave4 下行 PHY 异常 Slave4 与 Slave5 之间网线异常 Slave5 掉电 Slave5 ESC Reset 接插件松动 前级链路受到干扰同样如果看到CRC Error Counter 100也不能直接说网线坏了。因为这个 100 可能是设备几个月累计出来的也可能是一秒钟内突然增加的。所以 V3.0 的设计重点开始从收集状态变成收集证据 关联证据 分析证据 输出结论整个诊断过程现在可以概括成NetworkSnapshot | 状态变化检测 | Fault Event | 故障边界定位 | ESC / Port Error 取证 | Diagnosis Evidence | Evidence Window | Root Cause Analyzer | 根因 置信度 判断依据这里最重要的一个变化就是新增了Evidence这一层。程序不会让某个模块直接看到一个 CRC 错误就输出“线缆故障”。它先把各种信息整理成事实Master Link 仍然 UP Slave4、Slave5 同时丢失 故障边界位于 Slave3 和 Slave4 Slave3 Port1 Lost Link Counter 增加 Slave3 AL Status Code 0这些都只是证据。最终根因由多个证据共同决定。这比简单的if(crc_error)cable_faulttrue;可靠得多。三、生产数据采集从 Shell 切到了 IgH ioctlV1.1 获取状态主要依赖ethercat master ethercat slaves ethercat reg_read架构大致是诊断程序 | 启动 ethercat CLI | 解析 stdout | NetworkSnapshot这个方案很适合项目早期。因为能够很快验证事件检测 黑匣子 掉站边界 恢复判断这些思路到底有没有价值。但如果作为长期运行的诊断服务Shell 并不是理想的数据接口。一次采集要经过fork / exec CLI 执行 stdout 文本解析 结构化转换而ethercat命令本身最终还是通过 IgH Master 接口获取数据。所以后续版本把生产链路改成了直接访问/dev/EtherCAT0由IoctlSnapshotReader通过 IgH ioctl 获取 Master 和 Slave 信息。现在的生产数据链路变成IgH Master | /dev/EtherCAT0 | IoctlSnapshotReader | NetworkSnapshot这样做以后诊断程序不再依赖命令行输出格式也减少了频繁创建子进程和文本解析的开销。旧的 Shell backend 并没有直接删除。项目中仍然保留它用于测试和对比例如通过snapshot_backend_compare验证Shell backend和ioctl backend得到的网络快照是否一致。我比较喜欢这种迁移方式。底层接口重构以后旧实现暂时还能作为参考源帮助验证新实现而不是一次性全部推倒重来。四、加入 Port Error 后系统开始能够看到“链路正在变坏”V1.1 主要关注的是Link Down Slave Lost AL Error这些已经发生的故障。V3.0 增加了一类很重要的数据ESC Port Error Counter。现在程序可以监控包括Invalid Frame RX Error Forwarded RX Error Lost Link在内的端口错误。更重要的是系统关注的不是某个错误计数器当前是多少而是它有没有增加。例如12:00:01 RX Error 20 12:00:02 RX Error 20 12:00:03 RX Error 20这说明虽然历史上发生过错误但目前链路是稳定的。另一种情况12:00:01 RX Error 20 12:00:02 RX Error 27 12:00:03 RX Error 38这就完全不同了。所以程序内部会计算delta current - previous并进一步生成类似PORT_RX_ERROR_INCREASED PORT_LOST_LINK_INCREASED这样的事件。这让项目获得了一个 V1.1 没有的能力不只是知道“网络已经断了”还可以发现“网络正在变差”。比如所有 Slave 仍然在线Master Link 也正常但是某个端口连续出现RX Error 5 Invalid Frame 3系统就可以判断LINK_QUALITY_DEGRADATION这类信息对于排查 EMI、线缆、接插件、PHY 等问题很有价值。很多掉站并不是突然从 100% 正常变成 100% 断开。在真正断链之前链路往往已经留下了一些征兆。五、根因分析不是简单规则而是多个解释之间竞争V3.0 当前主要分析几类根因MASTER_LINK_FAILURE BOUNDARY_LINK_FAILURE SLAVE_INTERNAL_ERROR LINK_QUALITY_DEGRADATION UNKNOWN可以简单理解成Master 入口链路故障 从站之间的链路故障 从站内部异常 链路质量退化 证据不足这里我没有采用“一条规则命中以后立刻下结论”的方式。例如Master Link DOWN确实支持MASTER_LINK_FAILURE但如果Master Link UP Slave5 以后全部丢失 Boundary Slave4 - Slave5那么BOUNDARY_LINK_FAILURE显然更加合理。如果这时候又出现Slave4 Port1 Lost Link 1这个解释的可信度会继续增加。反过来如果Slave4 AL Status Code ! 0那么SLAVE_INTERNAL_ERROR也会得到支持。所以根因分析器内部实际上是在比较多个候选解释。每一个证据都可能支持某个根因也可能反驳某个根因例如Master Link UP对于BOUNDARY_LINK_FAILURE是有利证据。但对于MASTER_LINK_FAILURE就是反证。这是我认为 V3.0 比较重要的一个设计思想诊断不能只寻找支持自己的信息也要主动寻找与结论矛盾的信息。否则很容易出现看到 CRC 一定是网线这种过度归因。最终系统会给出Root Cause Score Confidence Supporting Evidence Contradicting Evidence如果证据不足则输出UNKNOWN我并不认为 UNKNOWN 是失败。在工业系统里“目前证据不足无法确定”往往比一个看起来非常确定、实际却错误的答案更可靠。六、为什么要增加时间窗口很多 EtherCAT 故障不能只看发生故障的那一瞬间。例如12:00:00 CRC 1 12:00:02 CRC 3 12:00:05 Lost Link 1 12:00:06 Slave5 ~ Slave10 Lost如果只看12:00:06我们只能知道后面的节点掉了。但把前几秒的信息串起来CRC 开始增加 RX 错误增加 Lost Link 拓扑收缩整个故障过程就清楚了很多。所以 V3.0 增加了EvidenceWindow生产程序会保留一段时间内的相关证据。当检测到Slave4 - Slave5是本次故障边界以后还会优先从窗口里寻找和这个位置相关的证据。这样根因判断依赖的就不再是一个瞬间的状态。而是一段时间内发生在同一区域的一组现象。这更符合真实通信故障的形成过程。七、V3.0 的 Web UI本质上是在降低诊断门槛V3.0 最直观的新功能是 Web Dashboard。但这个页面的价值并不是“把终端输出换成网页”。更重要的是把底层 EtherCAT 信息翻译成测试人员能够直接理解的故障描述。例如底层可能采集到Slave3 Port1 Lost Link 1 Slave4 LOST Slave5 LOST Boundary Slave3 - Slave4根因分析最终得到BOUNDARY_LINK_FAILURE对于熟悉 EtherCAT 的工程师来说这些信息已经足够。但测试人员更需要看到的是疑似故障位置 Slave3 与 Slave4 之间 可能原因 从站之间的物理链路异常 判断依据 Master 入口仍然正常 Slave4 以后节点同时消失 边界端口 Lost Link Counter 增加 建议 检查 Slave3 到 Slave4 的网线和接插件 确认 Slave4 供电 重新连接后观察拓扑是否完整恢复这才是 Web UI 真正想解决的问题。Web 与诊断进程完全解耦V3.0 没有让浏览器直接访问 EtherCAT。整体结构是EtherCAT Diagnostics Daemon | | 发布结果 v latest_status.json events.jsonl | | 只读 v Web Server | BrowserWeb Server 只读诊断进程已经生成的数据。这样无论网页刷新多少次 同时有多少浏览器都不会改变 EtherCAT 的访问频率。这是我比较坚持的一条边界显示层不能反过来影响诊断采集层。当前状态和历史事件分开保存诊断进程会维护两类数据latest_status.json表示现在怎么样。以及events.jsonl表示之前发生过什么。latest_status.json使用临时文件写完以后再原子替换避免 Web 正好读到写了一半的 JSON。历史事件则采用append-only一行一个 JSON 对象。这种设计没有引入数据库但对于当前项目已经足够。而且tail-fevents.jsonl就可以直接观察故障事件流。页面还会判断诊断服务是否停止更新这里还有一个比较容易忽略的问题。假设最后一次状态是HEALTHY然后诊断进程崩溃。如果 Web 一直读取旧文件页面可能永远显示网络正常。实际上已经没有程序继续监控 EtherCAT。所以页面还会观察updated_ms是否持续变化。如果数据长时间不更新就进入STALE状态。这里没有直接比较 PC 时间和嵌入式板卡时间因为两个设备的系统时钟不一定同步。判断“时间戳有没有继续向前走”反而更加可靠。八、V1.1 到 V3.0到底发生了什么变化如果把两个版本放在一起区别其实很清楚。能力V1.1.0V3.0.0独立旁路诊断支持支持NetworkSnapshot支持扩展状态变化检测支持扩展掉站边界定位支持支持黑匣子支持支持网络恢复检测支持支持ESC 主动诊断DL / AL / AL Code增加 Port Error数据采集Shell CLIioctlPort Error Delta无支持链路质量退化检测无支持Evidence 模型无支持Evidence Window无支持根因分析无支持支持证据 / 反证无支持Confidence无支持Web Dashboard无支持拓扑故障高亮无支持历史事件黑匣子文件持续事件流systemd无支持使用定位调试工具长期运行诊断服务如果一定要用一句话概括V1.1 负责把故障留下来V3.0 开始尝试把故障解释清楚。九、现在这套系统是怎样工作的把前面的内容串起来一次典型故障大致会经历下面的过程。假设正常拓扑是Master | Slave0 | Slave1 | Slave2 | Slave3 | Slave4 | Slave5某一时刻 Slave3 后面的链路出现问题。下一次采样只剩Slave0 Slave1 Slave2 Slave3系统首先发现SLAVE_COUNT_CHANGED SLAVE_LOST Slave4 SLAVE_LOST Slave5随后Boundary Slave3 - Slave4诊断程序读取边界附近的DL Status AL Status AL Status Code Port Error Counter如果同时发现Master Link UP Slave3 Port1 Lost Link 1 Slave3 AL Error false这些信息会被转换成 Evidence。Root Cause Analyzer 再结合最近一段时间的相关证据进行判断。最终可能输出Root Cause: BOUNDARY_LINK_FAILURE Confidence: High同时给出Supporting Evidence Master link remains UP Downstream slaves disappeared Fault boundary is Slave3 - Slave4 Slave3 Port1 lost-link counter increased对于最终使用者来说则可以进一步转换成疑似故障位置 Slave3 与 Slave4 之间 优先检查 网线 连接器 Slave4 供电 Slave4 入口 PHY这样一次故障就完成了从原始寄存器到现场处理建议的转换。十、我现在对 EtherCAT 故障诊断的理解做到 V3.0 以后我越来越觉得一个真正有价值的诊断系统不应该只是“采更多寄存器”。真正重要的是建立下面这条链路Data Information Event Evidence Diagnosis Action比如一个最原始的数据可能只是0x0300 17经过解析以后变成Slave4 Port1 RX Error 17比较前后两次以后变成Slave4 Port1 RX Error 5和故障时间关联以后变成Slave4 Port1 在掉站前持续出现 RX Error再结合Master Link UP Slave5 以后全部消失 Fault Boundary Slave4 / Slave5系统才有理由判断Slave4 与 Slave5 之间存在链路异常最终交给现场人员的应该是优先检查 Slave4 到 Slave5 的网线、连接器和 PHY。从0x0300 17到检查 Slave4 和 Slave5 之间中间这部分才是诊断系统真正创造价值的地方。V3.0 目前还远远做不到覆盖所有 EtherCAT 故障。像DC Sync Watchdog PDO / SM 配置 ESC Reset PHY 异常 供电瞬断 EMI这些问题以后都还需要继续完善。根因权重也需要通过实际故障注入和现场案例不断标定。但项目整体方向已经比较明确不只是告诉工程师“EtherCAT 出问题了”。而是尽量回答故障发生在哪里哪些证据支持这个判断以及下一步应该检查什么。这也是我继续做这个项目最主要的原因。项目地址IgH EtherCAT Diagnostics V3.0.0GitHubhttps://github.com/VictorJiaxinWang/Igh_EtherCAT_Diagnostics项目采用 C17 开发使用 MIT License。如果你的项目同样使用Linux IgH EtherCAT Master并且经常需要处理偶发掉站 链路异常 ESC 错误 现场问题难复现 故障定位耗时可以直接下载代码进行测试也可以根据自己的 EtherCAT 拓扑和设备特征继续扩展。我后面还会继续围绕Port Error 故障时间线 Root Cause DC / Sync Watchdog 自动化故障注入 诊断可视化这些方向继续完善。