20. 电机 Heartbeat 监视与组件限制
第 19 课能用 SDO 读取电机,但“刚才读成功”不能证明电机之后一直在线。电机 Node 0x01 周期发送 0x701 Heartbeat,程序可以记录它最后一次出现的时间。
CANopenNode 原本提供专门的 Heartbeat Consumer 模块来完成这类监视。本课先说明标准做法,再解释 Espressif 组件 0.1.0 在当前移植中的实际限制。
Producer 和 Consumer
Heartbeat 通信中有两个角色:
| 角色 | 本项目中的设备 | 动作 |
|---|---|---|
| Heartbeat Producer | 电机 Node 0x01 | 周期发送 0x701 |
| Heartbeat Consumer | ESP32 Node 0x20 | 接收并判断是否超时 |
Producer 是“生产 Heartbeat 报文”的节点,Consumer 是“消费并监视 Heartbeat 报文”的节点。
电机发送:
CAN-ID 0x701 DLC 1 DATA 05
这里的 05 是电机当前 NMT Operational 状态。它不是 CiA 402 的 “Operation enabled”;两套状态要到第 22 课结合 0x6041 再区分。
官方 CANopenNode 的标准做法
标准 Heartbeat Consumer 会:
- 根据对象
0x1016配置要监视的远程 Node-ID 和超时时间; - 接收对应的
0x700 + Node-ID; - 保存远程 NMT 状态;
- 在规定时间没有收到时报告超时事件。
这比应用只打印一帧更完整,因为它维护“是否曾经启动”“当前状态”“是否超时”等状态。
CANopenNode 官方说明:Heartbeat consumer
为什么当前组件里不能直接打开
本课程固定使用 espressif/canopennode 0.1.0。检查该组件的移植配置可以看到:
#define CO_CONFIG_HB_CONS 0
同时,组件 Kconfig 没有提供一个菜单选项把 Heartbeat Consumer 打开。这不是应用工程忘记勾选,而是该版本 ESP32 移植的功能配置把模块关闭了。
如果直接在 managed_components/ 里改宏,会带来几个问题:
- 组件管理器下次重新解析可能覆盖修改;
- 工程不再能只靠依赖清单复现;
- 学员难以判断代码来自官方版本还是本地补丁;
- 还需要核对对象字典
0x1016和接收缓冲区配置。
因此当前课程不修改托管组件。
应用层临时监视怎样工作
现有 Demo 仍使用 CANopenNode 的同一套 TWAI 接收机制,没有创建第二套驱动。

程序为 0x701 配置一个接收槽,收到后记录:
- DATA 中的 NMT 状态;
- 最后接收时间;
- 是否曾收到 Boot-up;
- Heartbeat 是否超过预期时间未出现。
为什么 SDO 读取时会临时切换到 0x581
当前组件和对象字典配置只给应用留出了有限的接收资源。访问电机 SDO 时,需要接收 0x581;平时又希望监听 0x701。
于是程序按下面的顺序使用同一个接收槽:
- 平时接收
0x701; - 开始 SDO 前,把槽配置为
0x581; - SDO Client 收到响应或超时;
- 关闭本次 SDO;
- 把槽恢复为
0x701。
这就是“SDO 读取期间临时切到 0x581,读完再恢复 0x701”的完整意思。
它不是把 TWAI 驱动关掉重开,也不是两套协议栈争用总线。
这种方案会漏掉什么
在接收槽用于 0x581 的短时间内,如果电机恰好发出 0x701,应用可能不处理那一帧。只要 SDO 操作时间短、Heartbeat 周期较长,下一帧 Heartbeat 仍会恢复监视。
但这仍不是完整 Heartbeat Consumer 的等价实现:
| 能力 | 应用层临时监视 | 官方 HB Consumer |
|---|---|---|
| 打印远程 NMT 状态 | 可以 | 可以 |
| 判断简单超时 | 可以 | 可以 |
使用标准 0x1016 配置 | 没有 | 可以 |
| 监视多个节点 | 当前未实现 | 按配置支持 |
| 完整状态和回调语义 | 没有 | 有 |
项目记录
这个限制必须保留在项目说明中,后续升级组件时重新检查:
- 新版本 Kconfig 是否开放
CO_CONFIG_HB_CONS; - 对象字典是否包含正确的
0x1016; - 接收缓冲区数量是否足够;
- 能否删除应用层临时监听代码。
当前方案适合本教程的单电机调试,但不应被描述为官方 Heartbeat Consumer 已经启用。
本课回顾
0x701 是电机主动发送的在线状态,不是 SDO 读取对象。当前 Espressif 组件关闭了官方 Heartbeat Consumer,因此应用在同一套 CANopenNode/TWAI 接收机制中做了有限监视;这个限制已经明确记录,不能悄悄修改托管组件来掩盖。