3、通信对象入门:SDO、PDO、NMT、SYNC、EMCY、LSS 六大通信对象概览
好,咱们进入正题。CANopen 从站开发,说白了就是跟这六个通信对象打交道。SDO、PDO、NMT、SYNC、EMCY、LSS,这六个家伙构成了整个协议栈的骨架。
我刚入行那会儿,面对这堆缩写也是一头雾水。后来踩了不少坑,才慢慢摸清楚每个对象该在什么场合用。今天我就把这六个对象的核心逻辑给你捋一遍。
一句话总结:
- SDO —— 配置通道,一次传一个对象,可靠但慢
- PDO —— 数据通道,一次传一堆数据,快但无确认
- NMT —— 状态机,控制设备启停
- SYNC —— 同步信号,让所有设备步调一致
- EMCY —— 紧急报警,出事了立刻通知
- LSS —— 节点配置,改波特率、改节点 ID
3.1 SDO —— 服务数据对象
SDO 是 CANopen 的配置通道。它的特点是:可靠,但慢。
为什么慢?因为 SDO 用的是确认服务。主站发一个请求,从站必须回一个应答。一来一回,一个对象字典条目才能读写完成。你想想看,如果一次要配置几十个参数,那总线上的 SDO 报文就排长队了。
我的经验:SDO 只适合在设备启动阶段做配置。运行时频繁读写 SDO,总线利用率会很难看。我曾经在一个项目里看到有人用 SDO 实时更新 PID 参数,结果总线负载飙到 60%,后来全改成 PDO 了。
SDO 的报文格式也值得一说。它用的是 CAN 标准帧,COB-ID 固定为 0x600 + 节点ID(主站发)和 0x580 + 节点ID(从站回)。数据域 8 个字节,前 2 个字节是命令和索引,后 4 个字节是数据。
// SDO 写请求示例(主站 → 从站,节点 ID = 1)
// COB-ID: 0x601
// 数据: 0x23 0x10 0x01 0x00 0x64 0x00 0x00 0x00
// 含义: 写对象 0x1010(保存参数),子索引 0x00,数据 0x00000064("save" 命令)
3.2 PDO —— 过程数据对象
PDO 是 CANopen 的数据高速公路。它跟 SDO 最大的区别是:无确认,一包搞定。
PDO 的数据域最多 8 个字节,可以映射多个对象字典条目。比如一个 4 字节的转速值加一个 2 字节的温度值,塞进一个 PDO 里,一包发出去。接收方不需要回复,效率极高。
PDO 有两种方向:
- TPDO(发送 PDO)—— 从站主动往外发数据
- RPDO(接收 PDO)—— 从站接收主站或其他设备的数据
触发方式也有好几种:
- 事件触发 —— 数据变化了就发
- 定时触发 —— 每隔固定时间发一次
- 远程请求 —— 主站发远程帧来要数据
- SYNC 同步触发 —— 收到 SYNC 后统一发
注意:PDO 没有确认机制。如果总线冲突导致丢包,发送方是不知道的。所以对可靠性要求高的数据(比如急停信号),建议用 SDO 或单独设计心跳机制。
3.3 NMT —— 网络管理
NMT 是 CANopen 的开关。它控制从站在四个状态之间切换:
| 状态 | 说明 | 能做什么 |
|---|---|---|
| Initialisation | 初始化 | 硬件自检,加载默认参数 |
| Pre-Operational | 预运行 | 只能 SDO 通信,不能发 PDO |
| Operational | 运行 | SDO 和 PDO 都可以用 |
| Stopped | 停止 | 只能响应 NMT 命令,其他都不行 |
NMT 报文是 CANopen 里优先级最高的。它的 COB-ID 固定为 0x000,所有从站都必须接收。主站发一个 NMT 命令,可以控制单个节点,也可以广播控制所有节点。
// NMT 启动节点示例(主站 → 所有从站)
// COB-ID: 0x000
// 数据: 0x01 0x00
// 含义: 命令 = 0x01(启动),节点 ID = 0x00(所有节点)
避坑指南:我曾经在一个项目里,从站上电后直接跳到 Operational 状态,没经过 Pre-Operational。结果主站还没来得及配置参数,从站就开始发 PDO 了,数据全是默认值。后来我强制在 Pre-Operational 状态等待 500ms,问题解决。
3.4 SYNC —— 同步对象
SYNC 是 CANopen 的节拍器。主站周期性地发 SYNC 报文,所有从站收到后同时采集数据或更新输出。
SYNC 的 COB-ID 默认是 0x080。它本身不带数据,就是一个空帧。但它的作用很大——让整个网络的动作保持同步。
举个例子:一个 6 轴机器人,每个关节一个从站。主站每 10ms 发一次 SYNC,所有关节同时读取目标位置,然后同时开始运动。如果没有 SYNC,各个关节的采样时刻会错开,机器人动作就会抖动。
我的习惯:SYNC 周期一般设在 1ms 到 100ms 之间。周期太短,总线负载高;周期太长,同步精度不够。我通常从 10ms 开始调,根据实际抖动情况再微调。
3.5 EMCY —— 紧急报文
EMCY 是 CANopen 的报警器。当从站检测到故障(比如过温、过流、通信超时),它会主动发一条 EMCY 报文。
EMCY 的 COB-ID 是 0x080 + 节点ID。数据域 8 个字节,前 2 个字节是错误码,后面是厂家自定义的附加信息。
| 错误码 | 含义 |
|---|---|
| 0x0000 | 无错误(复位) |
| 0x1000 | 通用错误 |
| 0x2000 | 电流相关错误 |
| 0x3000 | 电压相关错误 |
| 0x4000 | 温度相关错误 |
| 0x5000 | 硬件错误 |
| 0x6000 | 软件错误 |
| 0x8000 | 通信错误 |
注意:EMCY 报文只发一次,不会重发。主站收到后必须通过 SDO 读取错误寄存器来确认具体故障。如果主站没收到,那这个报警就丢了。所以关键故障建议同时用硬件信号(比如继电器)做备份。
3.6 LSS —— 层设置服务
LSS 是 CANopen 的配置工具。它用来修改从站的节点 ID 和 波特率。
为什么需要 LSS?因为传统 CANopen 设备靠硬件拨码开关设节点 ID,拨码开关多了,成本高、体积大、还容易接触不良。LSS 允许你通过软件配置,省掉拨码开关。
LSS 的通信基于 CAN 标准帧,COB-ID 固定为 0x7E5(主站发)和 0x7E4(从站回)。它有一套自己的协议流程:
- 主站发 LSS 识别请求,从站应答
- 主站配置新的节点 ID 和波特率
- 从站保存参数并复位
我的经验:LSS 配置完成后,一定要让从站保存到非易失性存储器(对象 0x1010)。否则掉电后配置就丢了。我曾经吃过这个亏,调试了一整天,最后发现是忘了写保存命令。
3.7 六大对象怎么选?
最后给你一张速查表,方便你对照:
| 对象 | 用途 | 可靠性 | 速度 | 使用场景 |
|---|---|---|---|---|
| SDO | 配置参数 | 高(有确认) | 慢 | 启动配置、故障诊断 |
| PDO | 传输实时数据 | 低(无确认) | 快 | 运行时的控制量、反馈量 |
| NMT | 状态管理 | 高 | 快 | 启动、停止、复位 |
| SYNC | 同步触发 | 中 | 快 | 多轴同步、数据采集 |
| EMCY | 紧急报警 | 中(只发一次) | 快 | 故障上报 |
| LSS | 节点配置 | 高 | 慢 | 批量配置节点 ID 和波特率 |