1. CANopen协议基础回顾:对象字典、PDO、SDO、NMT、心跳与同步报文

各位好,咱们开始第一讲。说实话,CANopen 协议看起来挺复杂,一堆缩写——OD、PDO、SDO、NMT……但说白了,它就是一套让设备之间“好好说话”的规则。我刚开始接触的时候也头大,后来发现只要抓住几个核心概念,剩下的都是这些概念的组合。

这一章咱们不搞长篇大论,就快速过一遍 CANopen 的六大核心要素。这些都是后面做故障定位时绕不开的基础。

1.1 对象字典——设备的“户口本”

对象字典(Object Dictionary,OD)是 CANopen 设备的核心。你可以把它理解成设备的“户口本”或“配置清单”。每个设备都有一个 OD,里面按索引(Index)和子索引(Subindex)存放了所有参数。

举个例子,我调试过一个伺服驱动器,它的运行模式、加速度、位置值都放在 OD 的不同位置。你要读或写某个参数,就得知道它的索引和子索引。

索引范围 用途 我见过的坑
0x1000 – 0x1FFF 通信对象(COB-ID、心跳、同步等) 有人把 0x1017 心跳时间设成 0,设备直接“失联”
0x2000 – 0x5FFF 制造商特定参数 不同厂家的 0x2000 含义完全不同,别想当然
0x6000 – 0x9FFF 标准化设备参数(如 CIA 402 驱动) 0x6040 控制字写错一位,电机就不转
我的习惯:调试前先把目标设备的 OD 表打印出来,或者用 CANopen 工具导出一份。没有 OD 表,就像没有地图去陌生城市——也能走,但效率极低。

1.2 PDO——过程数据对象,快就一个字

PDO(Process Data Object)用来传输实时数据,比如编码器位置、电流值、控制命令。它的特点是:一次最多传 8 字节,没有协议开销,速度极快。

PDO 分两种:

  • TPDO(发送 PDO):从站主动往外发数据。比如伺服每 1ms 发一次当前位置。
  • RPDO(接收 PDO):主站发给从站的数据。比如主站发一个目标位置给伺服。

PDO 的触发方式有几种:

  1. 事件触发:数据变化了就发。适合变化不频繁的信号。
  2. 定时触发:固定周期发。我常用 1ms 或 5ms 周期。
  3. 远程帧请求:主站发远程帧,从站回复。现在用得少了。
  4. 同步触发:收到同步报文后发。多轴同步时必用。
我曾经踩过的坑:把 PDO 映射配错了,导致发送的数据长度和实际映射的对象长度不匹配。结果从站一直发错误数据,主站那边收到一堆乱码。排查了整整一下午,最后发现是映射的字节数多配了 1 个。

1.3 SDO——服务数据对象,慢但稳

SDO(Service Data Object)用来读写对象字典里的任意条目。它走的是“请求-应答”模式,可靠但慢。每次传输至少需要两个 CAN 帧(请求 + 应答),大块数据还要分段。

SDO 的典型应用场景:

  • 设备上电后,主站通过 SDO 配置从站的参数(比如加速度、限位值)。
  • 调试时,手动读写某个 OD 条目来验证配置。
  • 固件升级时,通过 SDO 分段传输程序数据。

SDO 的报文结构是这样的:

CAN ID: 0x600 + NodeID(请求) / 0x580 + NodeID(应答)
数据域:命令字 + 索引(2字节) + 子索引(1字节) + 数据(4字节)

举个例子,读节点 1 的 0x1017(心跳时间):

请求:601 40 17 10 00 00 00 00 00
应答:581 43 17 10 00 64 00 00 00
// 0x64 = 100,表示心跳时间 100ms
关键点:SDO 是“点对点”的,一次只能和一个从站通信。如果你需要同时和多个从站交换数据,用 PDO 更合适。

1.4 NMT——网络管理,设备的“开关”

NMT(Network Management)负责控制设备的状态机。每个 CANopen 从站都运行在一个状态机里:

  • 初始化(Initialisation):上电后自动进入,完成硬件自检和 OD 加载。
  • 预操作(Pre-Operational):只能走 SDO,不能走 PDO。配置参数就在这个状态做。
  • 操作(Operational):正常运行时,PDO 和 SDO 都能用。
  • 停止(Stopped):除了 NMT 和心跳,其他通信都停了。

NMT 报文是特殊的 CAN 帧:

CAN ID: 0x000
数据域:命令字(1字节) + 节点ID(1字节)
// 命令字 0x01 启动,0x02 停止,0x80 进入预操作

比如启动节点 1:000 01 01。启动所有节点:000 01 00。

我的经验:调试时经常遇到从站卡在“预操作”状态不动。这时候先检查 NMT 报文有没有发出去,再检查从站的 NMT 状态机实现有没有 bug。CANopenNode 的 NMT 实现比较标准,但有些第三方栈会偷懒。

1.5 心跳与同步报文

这两个报文是 CANopen 网络的“节拍器”和“监控器”。

心跳报文

每个从站周期性地发送一个字节,表示自己还活着。心跳时间由 OD 0x1017 配置,单位是毫秒。比如设成 100,从站每 100ms 发一次心跳。

主站通过监控心跳来判断从站是否掉线。如果超过心跳时间的 1.5 倍还没收到心跳,主站就可以认为从站故障了。

我曾经遇到的故障:一个从站的心跳时间设成了 0(关闭心跳),结果主站一直报“节点丢失”。查了半天才发现是 OD 配置错了。后来我习惯在调试阶段把心跳时间设成 100ms,方便监控。

同步报文

同步报文(SYNC)由主站周期性发送,CAN ID 固定为 0x080。从站收到 SYNC 后,会同时采样输入或更新输出。这是实现多轴同步运动的关键。

同步周期一般设成 1ms 到 10ms。我做过一个项目,4 个伺服通过 SYNC 同步,位置误差控制在 0.1mm 以内。

1.6 知识结构总览

下面这张图把上面讲的内容串起来了。你可以看到各个要素之间的关系:

CANopen 核心要素关系图 对象字典 (OD) PDO(过程数据) SDO(服务数据) NMT(网络管理) 映射配置 读写访问 状态控制 心跳报文 同步报文 周期发送 同步触发 核心思路 OD 是数据仓库,PDO/SDO 是读写方式 NMT 控制状态,心跳和同步维持网络节奏

1.7 小结

这一章咱们快速过了一遍 CANopen 的六大核心要素。你记住一句话就行:对象字典是核心,PDO 跑实时数据,SDO 做配置读写,NMT 管状态,心跳保活,同步对齐。

后面章节我们会深入到 STM32 + CANopenNode 的具体实现。到时候你会发现,这些基础概念会反复出现。现在打好基础,后面调试的时候就能少走弯路。