2. CANopen核心概念:对象字典、通信对象、网络管理、PDO与SDO
好,咱们进入第二章。说实话,CANopen 协议栈移植这件事,很多人一上来就啃源码,结果越看越懵。为什么?因为你不理解它背后的那几个核心概念。这章我就带你把这几个概念彻底捋清楚。
CANopen 的核心概念,说白了就五个:对象字典(OD)、通信对象(COB-ID)、网络管理(NMT)、过程数据对象(PDO)、服务数据对象(SDO)。你把这五个东西搞明白了,整个协议栈的骨架就搭起来了。
一句话总结:对象字典是设备的“记忆体”,COB-ID 是通信的“门牌号”,NMT 管设备“死活”,PDO 传“快数据”,SDO 传“大文件”。
2.1 对象字典(Object Dictionary, OD)
对象字典是什么?我习惯把它理解成设备的“记忆体”。每个 CANopen 设备都有一个 OD,里面按索引(Index)和子索引(Subindex)存放了设备的所有参数。
举个例子,你想想看,一个伺服驱动器,它需要知道自己的额定电流、最大转速、通信波特率、故障状态……这些东西都存在哪?就存在 OD 里。
| 索引范围 | 用途 | 我见过的坑 |
|---|---|---|
| 0x1000 - 0x1FFF | 通信对象(COB-ID、同步、心跳等) | 有人把波特率写错,整个网络挂掉 |
| 0x2000 - 0x5FFF | 制造商特定参数 | 不同厂家定义不同,移植时要仔细看手册 |
| 0x6000 - 0x9FFF | 标准化设备参数(如 CIA 402 驱动) | 这部分最好别乱改,否则不符合标准 |
我的习惯:移植协议栈时,先把 OD 的 Excel 表格整理好。用脚本自动生成 C 代码,比手写快十倍,还不会出错。
2.2 通信对象(COB-ID)
COB-ID 就是 CAN 报文 ID。但 CANopen 对 ID 做了标准化分配。每个功能都有固定的 ID 范围。
我记得刚做 CANopen 时,总搞不清 0x180 和 0x200 的区别。后来发现,其实只要记住一个公式:COB-ID = 功能码 + 节点 ID。
| 功能码 | 通信对象 | COB-ID 范围 |
|---|---|---|
| 0001 | NMT 管理 | 0x000 |
| 0010 | 紧急报文 | 0x080 + 节点ID |
| 0011 | PDO1 (发送) | 0x180 + 节点ID |
| 0100 | PDO1 (接收) | 0x200 + 节点ID |
| 1011 | SDO (发送) | 0x580 + 节点ID |
| 1100 | SDO (接收) | 0x600 + 节点ID |
避坑指南:我曾经在一个项目里,两个设备配了相同的 COB-ID,结果总线直接瘫痪。排查了整整两天才发现。记住:CANopen 网络里,每个 COB-ID 必须唯一。
2.3 网络管理(NMT)
NMT 管的是设备的“死活”和“状态”。CANopen 设备有几种状态:初始化、预操作、操作、停止。
说白了,NMT 就是主站用来控制从站状态的“遥控器”。
- 初始化:设备上电后自动进入,做完自检就跳走
- 预操作:可以发 SDO,但不能发 PDO。我常用这个状态来配置参数
- 操作:正常工作状态,PDO 可以跑了
- 停止:啥也不干,只响应 NMT 命令
关键点:NMT 报文的目标节点 ID 为 0 时,表示广播给所有节点。我曾经用这个功能一键让整个产线停机——嗯,测试的时候差点被骂。
2.4 过程数据对象(PDO)
PDO 是用来传“快数据”的。比如编码器位置、电机转速、开关状态。一个 PDO 报文最多传 8 字节,实时性很高。
PDO 分两种:
- TPDO(发送 PDO):设备主动往外发
- RPDO(接收 PDO):设备从总线上收
触发方式也有讲究:
- 事件触发:数据变了就发。我习惯用在编码器上
- 同步触发:收到 SYNC 报文才发。适合多轴同步
- 远程请求:别人问我才发。用得少
我的经验:PDO 映射表一定要提前规划好。我曾经在一个 32 轴的项目里,PDO 映射配错了,结果位置和速度数据串了。电机直接飞车,吓得我赶紧按了急停。
2.5 服务数据对象(SDO)
SDO 是用来传“大文件”的。比如修改 OD 参数、下载固件。SDO 是确认模式——你发一条,对方回一条,保证可靠。
SDO 的报文格式有点复杂,我直接给你看个例子:
// 读 OD 索引 0x1017(心跳周期)
// 请求:0x40 0x17 0x10 0x00 0x00 0x00 0x00 0x00
// 响应:0x43 0x17 0x10 0x00 0xFA 0x00 0x00 0x00
// 0xFA = 250,表示心跳周期 250ms
你看,SDO 的通信模式是“一问一答”。虽然慢,但可靠。我一般在设备调试阶段用 SDO 改参数,量产阶段用 PDO 跑数据。
| 特性 | PDO | SDO |
|---|---|---|
| 速度 | 快(无确认) | 慢(有确认) |
| 数据量 | 最多 8 字节 | 可分段传大块数据 |
| 用途 | 实时控制 | 参数配置 |
| 可靠性 | 无确认 | 有确认 |
注意:SDO 通信时,如果主站和从站同时发请求,会产生冲突。我曾经遇到过 SDO 超时导致设备死锁的情况。解决办法是加超时重试机制,别死等。
好了,这五个核心概念就讲完了。你把这章吃透,后面讲协议栈移植的时候,你就知道代码里那些结构体、宏定义、回调函数到底在干什么了。