2. CANopen协议基础:对象字典、PDO、SDO、NMT、心跳与同步报文
好,咱们进入CANopen的核心地带。说实话,很多初学者一上来就被这些缩写搞懵了——OD、PDO、SDO、NMT……我当年刚接触时也差不多,感觉像在背密码表。但你别急,这些东西一旦拆开看,其实特别接地气。
CANopen本质上是一套“约定”。它告诉总线上的各个设备:你们该怎么说话、怎么听懂对方、怎么报告自己的状态。没有这些约定,CAN总线就是一盘散沙。嗯,咱们一个一个来。
2.1 对象字典(Object Dictionary)——设备的“户口本”
我个人习惯把对象字典比作设备的“户口本”。每个CANopen设备都有一个对象字典,里面按索引号记录了设备的所有参数、配置、状态和数据。
对象字典的结构是标准化的。索引0x1000到0x1FFF是通信对象,比如设备类型、错误寄存器。索引0x2000到0x5FFF是制造商特定对象,各家自己定义。索引0x6000到0x9FFF是标准化设备行规,比如驱动器的速度、位置参数。
关键点:对象字典的每个条目都有索引(16位)和子索引(8位)。比如0x1017是心跳生产者时间,子索引0就是心跳间隔值。你在代码里读写参数,本质上就是在操作对象字典。
我在项目中遇到过一个问题:两个电机驱动器的对象字典定义不一致,导致上位机读到的速度值差了10倍。查了半天,原来是其中一个把速度单位设成了0.1 rpm,另一个是1 rpm。所以啊,对象字典的标准化和文档化,比你想的重要得多。
2.2 PDO(过程数据对象)——快车道上的数据
PDO,全称Process Data Object。说白了,它就是用来传输实时数据的,比如电机转速、电流、位置。PDO的特点是:数据长度最多8字节,传输效率极高,没有协议开销。
PDO分两种:TPDO(发送PDO)和RPDO(接收PDO)。TPDO是设备主动往外发数据,RPDO是设备接收外部数据。每个设备最多支持4个TPDO和4个RPDO,但很多芯片可以扩展到更多。
PDO的映射是个重要概念。你可以把对象字典里的任意条目映射到PDO里。比如把“实际位置”(0x6064)和“实际速度”(0x606C)映射到TPDO1,这样电机驱动器就会周期性地把这两个数据打包发出去。
我的经验:PDO的传输类型有同步、异步、事件触发等。我个人建议,对于周期性控制任务,用同步PDO配合SYNC报文;对于状态反馈,用异步PDO配合事件触发。别把所有PDO都设成同步,否则总线负载会很高。
2.3 SDO(服务数据对象)——慢车道上的配置
SDO,Service Data Object。它和PDO正好相反——用来传输非实时的配置数据,比如修改PID参数、读取设备序列号。SDO的传输是确认式的,有请求就有应答,可靠性高,但速度慢。
SDO的报文格式比较固定:8字节数据中,第1字节是命令字,后面是索引、子索引和数据。比如你要写0x2000子索引1的值为100,就得拼一个特定的SDO报文。
我记得有一次调试,设备怎么都不响应SDO写请求。查了半天,发现是命令字写错了——写操作要用0x2F(写1字节)或0x2B(写2字节),我用了0x40(读命令)。嗯,这种低级错误,犯过一次就记住了。
注意:SDO是点对点通信,不能广播。如果你要同时配置多个设备,得一个一个发SDO。另外,SDO的优先级低于PDO,所以别在实时控制任务里频繁用SDO,否则会影响控制周期。
2.4 NMT(网络管理)——设备的“开关”
NMT,Network Management。它负责控制设备的状态机。每个CANopen设备都有几个状态:初始化、预操作、操作、停止。NMT报文就是用来切换这些状态的。
NMT报文只有2字节数据:第1字节是命令字,第2字节是节点ID。比如命令字0x01表示“进入操作状态”,0x02表示“进入停止状态”,0x80表示“进入预操作状态”。节点ID为0时,表示广播给所有设备。
设备上电后,默认进入预操作状态。在这个状态下,设备只响应SDO和NMT,不发送PDO。你需要发送NMT启动命令(0x01),设备才会进入操作状态,开始收发PDO。
避坑指南:我曾经在项目里忘记发送NMT启动命令,结果电机驱动器一直不响应PDO,我还以为是硬件坏了。后来用CAN分析仪抓包才发现,设备一直卡在预操作状态。所以,上电后第一件事就是发NMT启动命令,养成习惯。
2.5 心跳报文——设备的“呼吸”
心跳报文,英文叫Heartbeat。它是设备周期性发送的一个1字节报文,内容就是设备当前的状态:0x00表示启动中,0x04表示停止,0x05表示操作状态,0x7F表示预操作。
心跳的作用是让主站知道从站是否还活着。如果主站连续一段时间没收到某个从站的心跳,就可以判定它离线了,然后采取相应措施,比如急停或报警。
心跳的周期由对象字典0x1017决定,单位是毫秒。比如设成100,就是每100ms发一次心跳。我一般设成100到500ms,太频繁浪费总线,太稀疏又反应迟钝。
我的习惯:在调试阶段,我会把心跳周期设短一点(比如100ms),方便观察设备状态。量产时再调长到500ms或1秒。另外,主站也要配置心跳消费时间(0x1016),告诉它多久没收到心跳就算超时。
2.6 同步报文——总线的“节拍器”
同步报文,SYNC。它是由主站周期性发送的一个特殊报文,COB-ID为0x80。SYNC报文本身不带数据,就是一个“滴答”信号。
SYNC的作用是让所有从站同步执行动作。比如你控制6个电机同时运动,就可以让它们都配置成同步PDO模式。主站每发一个SYNC,所有电机就同时读取PDO数据并执行一次控制周期。
同步周期由主站决定,一般是1ms到10ms。我做过一个6轴机器人项目,同步周期设成了2ms,效果很好。如果周期太短,总线负载会很高;太长,控制精度又不够。
关键点:同步PDO有两种模式:同步循环和同步非循环。同步循环是每个SYNC都触发PDO传输;同步非循环是收到SYNC后,只有数据变化时才触发。我个人建议,对于位置控制用同步循环,对于状态监测用同步非循环。
2.7 总结与对比
好了,咱们把今天的内容捋一捋。对象字典是基础,PDO和SDO是两种数据传输方式,NMT管状态,心跳管健康,同步管节奏。它们各司其职,缺一不可。
| 协议元素 | 主要用途 | 传输方式 | 优先级 |
|---|---|---|---|
| 对象字典 | 参数存储与访问 | 索引/子索引 | — |
| PDO | 实时数据交换 | 无确认,广播 | 高 |
| SDO | 配置参数读写 | 确认式,点对点 | 低 |
| NMT | 设备状态控制 | 广播 | 最高 |
| 心跳 | 设备健康监测 | 周期性广播 | 中 |
| 同步 | 多设备同步 | 周期性广播 | 高 |
你想想看,如果没有这些协议元素,你要怎么让6个电机同时转起来?怎么知道哪个电机掉线了?怎么修改它的PID参数?嗯,这就是CANopen存在的意义。
下一章,咱们会深入PDO的配置和映射,手把手教你写一个PDO通信的示例。到时候你会看到,这些理论是怎么落到代码里的。
课后小作业:打开你的CANopen设备手册,找到对象字典0x1017和0x1016,看看它们默认值是多少。然后想想,如果心跳周期设成0,会发生什么?