一、对象字典——CANopen设备的灵魂
做CANopen开发这么多年,我越来越觉得,搞懂对象字典(Object Dictionary,简称OD),就等于掌握了CANopen的命门。你想想看,一个CANopen设备,不管是伺服驱动器、IO模块还是编码器,它里面到底有什么参数?怎么配置?怎么读取状态?答案全在对象字典里。
说白了,对象字典就是CANopen设备的“户口本”。每个设备都有一本,里面按编号记录了所有能访问的数据。我刚开始接触时,觉得这东西就是个参数表,后来踩过坑才明白——它是整个CANopen通信的基石。
核心定义:对象字典是一个有序的、标准化的数据集合,每个条目通过16位索引(Index)和8位子索引(Subindex)唯一标识。它描述了设备的所有功能、参数和状态。
二、对象字典的结构——索引与子索引
2.1 为什么需要两层索引?
这个问题我当年也困惑过。后来在做一个多轴控制器项目时,发现一个对象下面可能挂着一组数据,比如“电机参数”这个对象,下面有额定电流、额定转速、极对数等多个参数。如果只用一层索引,要么编号不够用,要么结构混乱。
CANopen的设计者很聪明,用了两层结构:
- 索引(Index):16位,范围0x0000~0xFFFF,用来定位“哪一类数据”
- 子索引(Subindex):8位,范围0x00~0xFF,用来定位“该类数据中的具体哪一个”
举个例子,索引0x6000是“第一轴的位置实际值”,子索引0x01是“高位字”,子索引0x02是“低位字”。这样设计,一个索引最多可以挂256个子项,够用了吧?
2.2 对象字典的地址空间划分
CANopen协议把整个对象字典空间划分成了几个区域,每个区域有特定用途。我整理了一张表,你一看就明白:
| 索引范围 | 用途 | 我常打交道的对象 |
|---|---|---|
| 0x1000~0x1FFF | 通信对象(COB) | 设备类型、错误寄存器、SDO参数、PDO映射 |
| 0x2000~0x5FFF | 制造商特定对象 | 各家驱动器的私有参数,比如增益、滤波 |
| 0x6000~0x9FFF | 标准化设备子协议 | DS402运动控制对象,比如控制字、状态字 |
| 0xA000~0xFFFF | 保留/网络变量 | 很少用到,但有些网关会占用 |
嗯,这里要注意:0x1000~0x1FFF是强制实现的,每个CANopen设备都必须有。我见过有人偷懒没实现0x1001(错误寄存器),结果主站一读就报错,排查了半天。
三、关键对象字典条目详解(1000h~1FFFh)
这部分是通信相关的核心对象,我挑几个最常用的讲讲。每个我都亲手配置过,踩过的坑也一并告诉你。
3.1 0x1000:设备类型
这个对象告诉主站:你是什么设备?比如0x00020192表示“DS402伺服驱动器”。我习惯在设备上电后先读这个,确认从站类型对不对。
3.2 0x1001:错误寄存器
8位数据,每一位代表一种错误类型。比如bit0是“通用错误”,bit4是“通信错误”。有一次现场设备报错,我读0x1001发现bit4置位,立刻知道是CAN总线出了问题,而不是电机烧了。
3.3 0x1005:COB-ID SYNC
同步报文的ID,默认是0x80。多轴同步时,所有轴都监听这个ID。我建议不要轻易改它,除非你的总线有冲突。
3.4 0x1010:保存参数
写入“save”关键字(0x65766173)到子索引0x01,就能把当前参数保存到EEPROM。注意:写入后设备会卡顿几十毫秒,别在运动过程中做这个操作。
我曾经踩过的坑:有一次在产线上,程序每10秒写一次0x1010保存参数,结果EEPROM一个月就写坏了。后来才知道,工业级EEPROM擦写寿命也就10万次。所以,只在参数改变时才保存,不要循环写。
3.5 0x1011:恢复出厂设置
写入“load”关键字(0x64616F6C)到子索引0x01,设备会恢复默认参数。这个操作很暴力,慎用。我一般只在调试阶段用,现场不敢乱动。
3.6 0x1016:心跳消费者超时时间
设置主站多久没收到从站心跳就报错。单位是毫秒,我一般设500ms。太短容易误报,太长又反应迟钝。
3.7 0x1017:心跳生产者时间
从站每隔多少毫秒发一次心跳。我习惯设100ms,既不会占用太多总线带宽,又能及时检测到设备掉线。
3.8 0x1400~0x1BFF:接收PDO和发送PDO参数
这部分是PDO通信的核心,定义了PDO的COB-ID、传输类型、禁止时间等。我后面会专门讲PDO,这里先提一句:传输类型(子索引0x02)很关键,1表示“同步周期传输”,255表示“异步事件触发”。
四、如何通过SDO读写对象字典
4.1 SDO是什么?
SDO(Service Data Object)是CANopen的“快递员”,专门用来读写对象字典。它基于“请求-应答”模式,你发一个请求帧,设备回一个应答帧。虽然速度比PDO慢,但胜在可靠,每个字节都有确认。
4.2 SDO报文格式
一个SDO报文占8个字节,结构如下:
| 字节0 | 字节1~2 | 字节3 | 字节4~7 |
|---|---|---|---|
| 命令字 | 索引(低字节在前) | 子索引 | 数据(最多4字节) |
命令字决定了操作类型:
- 0x40:读请求(上传)
- 0x42:读应答(设备返回数据)
- 0x23:写请求(下载)
- 0x60:写应答(设备确认收到)
- 0x80:异常应答(出错了)
4.3 实战:用SDO读取设备类型
假设我们要读索引0x1000(设备类型),子索引0x00。主站发送:
CAN ID: 0x600 + 节点ID(比如节点1就是0x601)
数据: 40 00 10 00 00 00 00 00
↑ ↑ ↑ ↑
| | | 子索引=0x00
| 索引=0x1000(低字节在前)
命令字=0x40(读请求)
设备应答:
CAN ID: 0x580 + 节点ID(0x581)
数据: 42 00 10 00 92 01 02 00
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
| | | | 设备类型=0x00020192
| | | 子索引=0x00
| 索引=0x1000
命令字=0x42(读应答,数据长度4字节)
4.4 实战:用SDO写入控制字
DS402协议中,控制字在索引0x6040,子索引0x00。我们要写入0x0006(使能操作):
CAN ID: 0x600 + 节点ID
数据: 23 40 60 00 06 00 00 00
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
| | | | 数据=0x00000006
| | | 子索引=0x00
| 索引=0x6040
命令字=0x23(写请求,4字节数据)
设备应答:
CAN ID: 0x580 + 节点ID
数据: 60 40 60 00 00 00 00 00
↑
命令字=0x60(写应答,成功)
我的调试小技巧:如果设备返回0x80(异常),别慌。读一下字节4~7,里面包含了错误码。比如0x06020000表示“对象不存在”,0x06010002表示“数据类型不匹配”。这些错误码在CiA301标准里都有定义,查一下就知道问题在哪。
五、对象字典的SVG结构图
下面这张图是我自己画的,把对象字典的层次结构和SDO读写流程串起来了。你看完应该能有个整体印象。
六、总结一下
对象字典这东西,说复杂也复杂,说简单也简单。你只要记住三点:
- 它是设备的“参数仓库”,所有能读能写的数据都在里面
- 用索引+子索引定位,就像门牌号一样精确
- SDO是访问它的工具,虽然慢但可靠,适合配置和诊断
我个人习惯,在调试新设备时,第一件事就是读0x1000确认设备类型,然后读0x1001看看有没有历史错误。这两个对象能帮你快速判断设备是否正常。嗯,今天就先聊到这儿,后面我们会深入PDO和同步控制,那才是多轴同步的重头戏。
一句话记住:对象字典是CANopen的“内存映射”,SDO是读写这个映射的“API”。搞懂这两样,CANopen你就入门了。
公众号:蓝海资料掘金营,微信deep3321