学习CANopen --- [4] 对象字典

对象字典英文叫Object Dictionary, 简称OD,是CANopen中的核心概念。每个CANopen设备都会有个OD。

OD主要用于设备的配置和通信。不同的设备会有不同的OD,通过读取它们的OD,用户可以知道这些设备的信息、如何与设备进行通信以及配置设备。

这和去饭馆吃饭类似,饭馆的菜单就是OD,客人阅读菜单,就知道饭馆能做哪些菜,然后就能做出正确的点菜操作。


一 概念理解

对象字典的结构和python中的dict类似,下面是设备OD内容的部分展示,
在这里插入图片描述
乍一看有点懵,这里使用python中的字典来描述上图,就比较好懂了,

myOD = {
    
    }

myOD[0x1000] = {
    
    0x000x12345678} # Device Type, UNSIGNED32
myOD[0x1001] = {
    
    0x00: 0x12}       # Error Register, UNSIGNED8
myOD[0x1008] = {
    
    0x00: "hello"}    # Device Name, VIS_STRING
myOD[0x1017] = {
    
    0x00: 0x1234}     # Heartbeat Prod. Time, UNSIGNED16

myOD[0x1018] = {
    
    
                    0x00: 0x04,       # number of subindexes, UNSIGNED8
                    0x01: 0x12345678, # Vendor ID, UNSIGNED32
                    0x02: 0x12345678, # Product Code, UNSIGNED32
                    0x03: 0x12345678, # Revision Number, UNSIGNED32
                    0x04: 0x12345678  # Serial Number, UNSIGNED32
                }

OD中存放很多对象,每个对象都有唯一的Index与之对应,占2个字节,如果想寻址对象内部元素,就需要使用SubIndex,占1个字节,所以Index和SubIndex的组合总共占3个字节。

如0x1018对应的对象,含有4个元素,分别是Vendor ID,Product Code,Revision Number和Serial Number,SubIndex分别是1,2,3,4。SubIndex 0上存放的值表示对象里包含的元素个数。如果对象中只有一个元素,那么元素值就会直接存放到SubIndex 0对应的元素上。

CANopen规定的OD结构如下图,
在这里插入图片描述
这里再简化一点,如下表,

Index 对象
0x0000 未使用
0x0001 ~ 0x009F 数据类型区,存放常规数据类型和用户自定义数据类型
0x00A0 ~ 0x0FFF 保留
0x1000 ~ 0x0FFF 通信简表区,包含设备类型,错误寄存器和通信相关对象
0x2000 ~ 0x5FFF 用户自定义区,存放用户自定义的对象
0x6000 ~ 0x9FFF 标准设备简表区 ,存放标准行规中定义的对象
0xA000 ~ 0xFFFF 保留

实际使用时,并不会用完所有的Index,都是根据需要选择一些Index来使用。例如标准设备简表区,用户开发的产品可能是用于某一行业的,那么就只需要该行业的标准行规定义的对象,如运动控制对应的DS-402


二 OD的文件格式

OD一般保存为EDS文件或DCF文件,在上一篇文章中我们已经使用了一个EDS文件,即CANopenSocket.eds

DCF文件格式与EDS基本一样,只是DCF可以保存设备的ID信息,并且可以只保存部分OD,意义在哪呢?有时我们想更新设备中的OD,但是只更新一部分,这样就可以使用DCF了。

EDS和DCF文件的具体格式可以参考CANopen的官方文件,即DS-306


三 代码实战

下面通过pythonCANopen来体验一下OD,从Client(即去饭馆吃饭的客人)的角度来看看OD中的内容,
首先要创建虚拟CAN设备vcan0,

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

然后执行下面python代码,

import time
import canopen

# 创建一个网络用来表示CAN总线
network = canopen.Network()

# 添加slave节点,其id是6,对象字典为CANopenSocket.eds
node = canopen.RemoteNode(6, 'CANopenSocket.eds')
network.add_node(node)

# 连接到CAN总线
network.connect(bustype='socketcan', channel='vcan0')


for obj in node.object_dictionary.values():
    # 打印对象的Index和名称
    print('0x{:X}: {}'.format(obj.index, obj.name))
    
    ''' 
        如果对象类型是Record,即内部包含多个元素的对象,
        就把其内部元素的SubIndex和名称打印出来
    '''
    if isinstance(obj, canopen.objectdictionary.Record):
        for subobj in obj.values():
            print('  {}: {}'.format(subobj.subindex, subobj.name))

这样就可以看到OD里的对象信息了。

如果想访问单个OD对象,可以使用ParameterName或者Index/SubIndex组合,例如想访问CANopenSocket.eds中Index为0x2301、SubIndex为01对应的值,
在这里插入图片描述
代码如下,

obj_element = node.object_dictionary[0x2301][1]
print(obj_element.default)

obj_element = node.object_dictionary['Trace config']['Size']
print(obj_element.default)

可以打印其默认值


四 总结

本文主要简单讲述了CANopen中的对象字典,这是CANopen中很重要的概念,通过python代码可以很好的理解其意义。

如果有写的不对的地方,希望能留言指正,谢谢阅读。

猜你喜欢

转载自blog.csdn.net/whahu1989/article/details/106584380