3、通信对象入门:SDO、PDO、NMT、SYNC、EMCY、LSS 六大通信对象概览

好,咱们进入正题。CANopen 从站开发,说白了就是跟这六个通信对象打交道。SDO、PDO、NMT、SYNC、EMCY、LSS,这六个家伙构成了整个协议栈的骨架。

我刚入行那会儿,面对这堆缩写也是一头雾水。后来踩了不少坑,才慢慢摸清楚每个对象该在什么场合用。今天我就把这六个对象的核心逻辑给你捋一遍。

一句话总结:

  • SDO —— 配置通道,一次传一个对象,可靠但慢
  • PDO —— 数据通道,一次传一堆数据,快但无确认
  • NMT —— 状态机,控制设备启停
  • SYNC —— 同步信号,让所有设备步调一致
  • EMCY —— 紧急报警,出事了立刻通知
  • LSS —— 节点配置,改波特率、改节点 ID
CANopen 六大通信对象关系图 CANopen 从站 SDO 配置通道 PDO 数据通道 NMT 状态管理 SYNC 同步信号 EMCY 紧急报警 LSS 节点配置 说明 SDO/PDO 是数据通道,NMT/SYNC 是控制通道,EMCY 是异常通道,LSS 是配置通道 实际项目中,PDO 占总线流量 80% 以上,SDO 只在启动时用

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(从站回)。它有一套自己的协议流程:

  1. 主站发 LSS 识别请求,从站应答
  2. 主站配置新的节点 ID 和波特率
  3. 从站保存参数并复位

我的经验:LSS 配置完成后,一定要让从站保存到非易失性存储器(对象 0x1010)。否则掉电后配置就丢了。我曾经吃过这个亏,调试了一整天,最后发现是忘了写保存命令。

3.7 六大对象怎么选?

最后给你一张速查表,方便你对照:

对象 用途 可靠性 速度 使用场景
SDO 配置参数 高(有确认) 慢 启动配置、故障诊断
PDO 传输实时数据 低(无确认) 快 运行时的控制量、反馈量
NMT 状态管理 高 快 启动、停止、复位
SYNC 同步触发 中 快 多轴同步、数据采集
EMCY 紧急报警 中(只发一次) 快 故障上报
LSS 节点配置 高 慢 批量配置节点 ID 和波特率