3. 通信对象COB-ID与预定义连接集
在CANopen网络中,每一个通信对象都由一个唯一的COB-ID(Communication Object Identifier)来标识。COB-ID本质上就是CAN总线上的11位标准帧标识符,它同时承担两个职责:一是标识这条报文属于哪个通信对象,二是通过标识符数值的大小决定总线仲裁优先级。理解COB-ID的分配规则,是从站开发中配置对象字典、实现PDO/SDO通信、以及排查通信异常的基础。
11位标识符的优先级划分
CAN总线采用非破坏性逐位仲裁机制。当多个节点同时发送报文时,标识符数值越小,二进制高位越早出现显性位(0),该报文获得总线控制权的优先级越高。因此,COB-ID的数值大小直接决定了通信对象的实时性等级。CANopen正是利用这一特性,将功能优先级映射到标识符区间上:
- 高优先级区间(0x000~0x07F):NMT网络管理报文(0x000)、SYNC同步报文(0x080)、EMCY紧急报文(0x081~0x0FF)等,这些报文对实时性和全局协调性要求最高。
- 中优先级区间(0x180~0x57F):TPDO1~TPDO4、RPDO1~RPDO4、SDO等过程数据与服务数据,是周期性或事件驱动的常规通信。
- 低优先级区间(0x580~0x77F):SDO响应、心跳/节点保护等,对实时性要求相对宽松。
这种划分不是随意的,而是CANopen协议预定义连接集(Predefined Connection Set)的核心设计。预定义连接集规定了一套默认的COB-ID分配方案,使得从站在上电后无需任何配置即可参与基本通信。
默认COB-ID分配规则
预定义连接集为每个通信对象分配了一个基础功能码(Function Code),再叠加节点号(Node-ID)构成完整的11位COB-ID。基础功能码占据标识符的高4位(bit 10~bit 7),节点号占据低7位(bit 6~bit 0)。节点号有效范围为1~127,0保留给主站或广播。
| 通信对象 | 基础功能码 | COB-ID计算式 | 节点号1的示例 | 方向 |
|---|---|---|---|---|
| NMT | 0x000 | 0x000 | 0x000 | 主站→从站(广播) |
| SYNC | 0x080 | 0x080 | 0x080 | 主站→从站(广播) |
| EMCY | 0x080 | 0x080 + Node-ID | 0x081 | 从站→主站 |
| TPDO1 | 0x180 | 0x180 + Node-ID | 0x181 | 从站→主站 |
| RPDO1 | 0x200 | 0x200 + Node-ID | 0x201 | 主站→从站 |
| TPDO2 | 0x280 | 0x280 + Node-ID | 0x281 | 从站→主站 |
| RPDO2 | 0x300 | 0x300 + Node-ID | 0x301 | 主站→从站 |
| TPDO3 | 0x380 | 0x380 + Node-ID | 0x381 | 从站→主站 |
| RPDO3 | 0x400 | 0x400 + Node-ID | 0x401 | 主站→从站 |
| TPDO4 | 0x480 | 0x480 + Node-ID | 0x481 | 从站→主站 |
| RPDO4 | 0x500 | 0x500 + Node-ID | 0x501 | 主站→从站 |
| SDO Tx(响应) | 0x580 | 0x580 + Node-ID | 0x581 | 从站→主站 |
| SDO Rx(请求) | 0x600 | 0x600 + Node-ID | 0x601 | 主站→从站 |
| 心跳/节点保护 | 0x700 | 0x700 + Node-ID | 0x701 | 从站→主站 |
需要特别注意:NMT和SYNC使用固定COB-ID,不叠加节点号,因为它们是广播报文,所有从站都必须接收。而EMCY、PDO、SDO、心跳等均为点对点或按节点区分的通信对象,必须叠加节点号才能保证同一网络中多个从站的报文互不冲突。
广播与点对点通信的标识符规则
广播通信的特点是“一个发送者,多个接收者”,其COB-ID不包含节点号,所有节点都监听同一标识符。CANopen中典型的广播对象包括:
- NMT模块控制:COB-ID固定为0x000,主站发送启动、停止、复位等命令,所有从站接收并执行。
- SYNC同步报文:COB-ID固定为0x080,主站周期性发送,触发从站同步采样或发送PDO。
- 时间戳报文:COB-ID固定为0x100,用于网络时间同步。
点对点通信则要求每个从站拥有独立的COB-ID,通过叠加节点号实现。例如节点号为5的从站,其TPDO1的COB-ID为0x180+5=0x185,SDO请求COB-ID为0x600+5=0x605。主站根据目标节点号选择对应的COB-ID发送,只有该节点会响应。
从站如何根据节点号计算自身COB-ID
从站在上电初始化阶段,需要根据自身配置的节点号,计算出所有通信对象的默认COB-ID,并写入对象字典中对应的通信参数条目。以节点号Node-ID=3为例,计算过程如下:
Node-ID = 3
NMT COB-ID = 0x000 (固定,不叠加)
SYNC COB-ID = 0x080 (固定,不叠加)
EMCY COB-ID = 0x080 + 3 = 0x083
TPDO1 COB-ID = 0x180 + 3 = 0x183
RPDO1 COB-ID = 0x200 + 3 = 0x203
TPDO2 COB-ID = 0x280 + 3 = 0x283
RPDO2 COB-ID = 0x300 + 3 = 0x303
TPDO3 COB-ID = 0x380 + 3 = 0x383
RPDO3 COB-ID = 0x400 + 3 = 0x403
TPDO4 COB-ID = 0x480 + 3 = 0x483
RPDO4 COB-ID = 0x500 + 3 = 0x503
SDO Tx COB-ID = 0x580 + 3 = 0x583
SDO Rx COB-ID = 0x600 + 3 = 0x603
心跳 COB-ID = 0x700 + 3 = 0x703
这些计算值需要写入对象字典的通信参数子索引中。例如TPDO1的COB-ID存放在索引0x1800子索引0x01中,RPDO1的COB-ID存放在索引0x1400子索引0x01中,SDO请求COB-ID存放在索引0x1200子索引0x01中。从站固件通常在初始化函数中完成这一批量赋值,之后通信栈便依据这些值进行报文过滤和发送。
如果应用需要自定义COB-ID(例如避开网络中其他设备的标识符),可以在对象字典中修改这些条目,但必须保证修改后的COB-ID不与网络中其他节点冲突,且符合11位标准帧格式(0x000~0x7FF)。修改后通常需要重新初始化通信栈或复位节点才能生效。
在实际从站开发中,建议将上述计算封装为一个初始化函数,在节点号确定后统一计算并写入对象字典。这样既保证了默认连接集的一致性,也为后续通过SDO或配置文件修改COB-ID留出了清晰的接口。理解COB-ID的分配逻辑,是读懂CANopen通信行为、分析总线报文和定位通信故障的第一步。