IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 学习CANopen --- [5] SDO -> 正文阅读

[Python知识库]学习CANopen --- [5] SDO


前言

SDO是Service Data Object的缩写,中文叫服务数据对象,关键是这个服务二字,指的是读写服务,Client可以通过SDO读写Server里的对象字典(Object Dictionary,简称OD)

OD存在于Server中,用户在和Server通信之前,也会有一份相同的OD表,不然没法继续操作。如果用户想读写OD里的值,那么就可以使用SDO。

PS:要记住:用户是Client,CANOpen设备是Server;如果2个CANOpen设备间互相通信,那么发起通信的那个就是Client,这里统一使用Client指代


一 工作原理

SDO的收发有点像TCP,读写请求发送出去后必须要有一个来自Server的应答,如下图
在这里插入图片描述
如果是读,那么应答里会包含读取的数据,如果是写,那么应答里会包含写成功的标志。如果读写发生错误,Server这边会返回一个紧急报文,里面包含错误码。

Client一般都会设置个SDO超时时间,如果在规定时间内没有收到应答,Client这边就会报错。

PS:CANOpen文档里读叫upload,写叫download,感觉是从Server角度来看的


二 使用范围

只有当Server处于Pre-Operational和Operational状态下,Client才可以使用SDO去和Server通信,如下图,
在这里插入图片描述
一般来说CANOen设备启动后会自动进入Pre-Operational状态,所以可以直接使用SDO,如果设备特殊,那么就要看下该设备的详细资料。

关于状态切换,请查看讲NMT的那篇文章。


三 例子

下面讲例子,实战可以让理解更加深入,首先使用pythonCANOpen来创建2个文件:server.py和client.py,如下,

'''
server.py
'''
import signal
import canopen
import time


running = True

def sigint_handler(signum, frame):
    global running
    print('')
    running = False
    exit(0)

# 处理按键发送的信号,优雅的关闭程序
signal.signal(signal.SIGINT,  sigint_handler)
signal.signal(signal.SIGHUP,  sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)

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

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

# 创建slave节点,其id是6,对象字典为CANopenSocket.eds
node = network.create_node(6, 'CANopenSocket.eds')

# node向CAN总线上发送启动消息
node.nmt.send_command(0)

# node进入PRE-OPERATIONAL状态
node.nmt.state = 'PRE-OPERATIONAL'

# node发送心跳报文,每隔1s发送一次
node.nmt.start_heartbeat(1000) # 1000ms


# 循环, 持续睡眠
while running:
    time.sleep(0.6)

client.py如下,

'''
client.py
'''
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')

# 读取Index为0x2341,Subindex是2的OD项
data = node.sdo[0x2341][2].raw
print('0x2341_02: 0x{:X}'.format(data))

time.sleep(2)

# 修改Index为0x2341,Subindex是2的OD项
node.sdo[0x2341][2].raw = 0x123

time.sleep(2)

# 再读一次验证一下
data = node.sdo[0x2341][2].raw
print('0x2341_02: 0x{:X}'.format(data))

PS:eds文件来自这个

然后创建vcan0,

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

创建好之后开一个终端,然后使用candump进行观察,

candump vcan0

最后是运行,先运行server.py,

python3 server.py

接着运行client.py,

python3 client.py

client运行结束后,观察得到的CAN报文如下,有三组,注意数字都是16进制,
在这里插入图片描述

1. COB-ID分析

先看606和586,这2个是SDO报文的COB-ID,

  • 对于发送的SDO报文来说,其COB-ID是0x600+设备id,例子中Server的id是6,所以是0x606,由Client发出,表示发给id是6的设备
  • 对于返回的应答报文来说,其COB-ID是0x580+设备id,例子中Server的id是6,所以是0x586,由Server发出,表示该报文是由id为6的设备返回的

PS:0x600号0x580是专属于SDO的,且是固定的

2. 报文内容分析 — 读操作

在这里插入图片描述

报文内容的基本结构如下,发送和接收的报文结构一样,
在这里插入图片描述
总共8个字节,

  • 字节0是命令说明符,用来描述报文意义,简写为CS,占1个字节
  • 字节1-2是Server对象字典项的Index,占2个字节
  • 字节3是Server对象字典项的Subindex,占1个字节
  • 字节4-7是报文内容,占4个字节

命令提示符

例子中第一个SDO报文是读取字典项0x2341_02,读操作对应的CS字节如下,注意这是一个字节,
在这里插入图片描述
Client发送报文的CS值是0x40,只要是读,其CS都是0x40

Server返回报文的CS值则需要考虑被读字典项的数据类型,n, e, s的含义如下,
在这里插入图片描述
PS:n是number的首字母,e是expedited的首字母,s是size的首字母

例子中返回的CS是0x4B,转为二进制后得出:n值为10b,十进制数字为2,e=1b,s=1b,根据上述含义可以得出:

  • 字节8-n到字节7,即字节6-7不包含数据,那么有效数据在字节4-5,总共2个字节
  • e为1b表示这是expedited传输,意思是数据可以一次传输完成,可以想象只要数据字节数不大于4,那么都可以一次传输完成
  • s为1b,但是在expedited传输里s是没有意义的,只有在e=0时s才有意义

然后打开eds文件,找到0x2341_02对应的描述,如下,
在这里插入图片描述
其DataType是0x0006,根据官方文档,其对应的数据长度就是2个字节,和前面分析相符,
在这里插入图片描述

索引和子索引

字节1的值为0x41,字节2的值是0x23,从右往左读就是0x2341,即字典项的索引

字节3的值是0x02,也就是字典项的子索引

发送报文和返回报文在字节1~3写入的都是相同的索引和子索引

报文中的数据值

发送报文的最后四个字节都是0,因为是读,这4个字节都是无意义的,虽然无意义,但是还是要传输,所以就写0

返回报文里字节5的值为0x7F,字节4的值为0xFF,合起来就是0x7FFF,与EDS文件里看到的这个字典项对应的默认值相同

3. 报文内容分析 — 写操作

在这里插入图片描述

写操作的内容结构和读一样,
在这里插入图片描述

命令提示符

写操作的CS值如下,
在这里插入图片描述
可以看到发送报文的CS值和字典项的数据类型有关,n,e,s的含义和读操作相同,所以这里是2B

返回报文的CS值则是固定的0x60,表示写入OK

索引和子索引

与读操作相同,就是把0x2341_02写入到字节1~3里

报文中的数据值

由于是写,所以在发送报文的字节4~5里填入期望的目标值,这里是0x123,字节4是0x23,字节5是0x01,字节6和7则为0

在返回报文里字节4~7都是无意义的,虽然无意义,但是还是要传输,所以都写0

3. Segment传输

前面的读写操作都是expedited传输,即一个来回就能传输完成,要求数据长度<=4字节,但有的字典项长度是大于4字节的,这样一次就无法传输完成,此时就需要Segment传输,也叫段传输

在eds文件里,字典项0x1009的默认值超过了4,其数据类型是0x0009,即Visible String,
在这里插入图片描述
这里改下,把其DefaultValue改长一点,如下,总共32个字节,不包含尾巴的’\0’,
在这里插入图片描述
然后重启server.py,client.py内容改为如下,

'''
client.py
'''
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')

# 读取Index为0x1009的OD项
data = node.sdo[0x1009].raw
print('0x1009: {}'.format(data))

运行client.py后观察到的报文如下,2道橘黄色的横线之间是一次收发,
在这里插入图片描述
可以看到总共出现了6次收发,需要逐个分析

读的发起

第一次收发是读的发起,其CS含义如下,
在这里插入图片描述
和之前分析expedited读是一样,只是返回报文里的n,e,s的值变了:n为00b,e为0b,s为1b,根据前面n,e,s的释义,可以得出以下结论:

  • n的值在此次报文里无效,因为e不为1
  • e为0表示这不是expedited传输,需要多次传输才能把数据传完
  • s为1表示返回报文里字节4~7的值是字典项的size,这里是0x20,即32,和前面修改后的长度一致;也可以理解为需要传输的字节数

读的数据传输

剩余的5次收发就是读的数据传输,其CS值定义如下,
在这里插入图片描述
t,n,c含义如下,
在这里插入图片描述
Client发送报文的CS值比较简单,只有个toggle bit在变化,所以其CS值在0x60和0x70间互相变化,第一次是0x60

Server返回的报文里,除了t,还有n和c,字面意义也比较好理解,要注意这里的n是3个bit,expedited传输里n是2个bit。

只要不是最后一次收发,那么n和c都为0,CS值在0x00和0x10间互相变化,第一次是0x00;每次能传输7个字节,4次收发传了28个字节;

第6次收发是最后一次,此时还剩32-28=4个字节,那么n就为3,即011b,c为1,即1b,组合在一起是0111b,另外此次的t是0b,那么最后一次返回的报文的CS就是0x07

写的发起和数据传输

写也是类似,分为写的发起和写的数据传输,分别对应下面2张图
在这里插入图片描述
在这里插入图片描述
由于这个eds文件里超过4字节的字典项都是const的,不可以修改,那么就需要改个其它项来做测试,这里修改0x2FF4_4,其原始内容如下,
在这里插入图片描述
改之后如下,只是改了DataType,
在这里插入图片描述
然后重启server.py,client.py内容改成如下,

'''
client.py
'''
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')

# 修改0x2FF4_04的OD项
node.sdo[0x2FF4][4].raw = "AABBCCDDEEFFGGHH"


运行client.py后观察得到的can报文如下,
在这里插入图片描述
总共发生了4次收发,第一次是写的发起,通过CS值来告诉Server总共有16个字节要写;后面三次是数据传输,内容分析和读类似,只要注意CS的高3位不一样就行了。

4. Block传输

由于pythonCanopen库暂时不支持block传输,所以先等等…

5. Abort

Server和Client都可以发送abort报文来中断报文传输,其CS值定义如下,
在这里插入图片描述
即0x80


四 总结

本文讲述了SDO报文的含义和实践,通过例子+理论,可以更加深刻的理解SDO及其用途。

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:14:27  更:2022-05-05 11:17:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 16:48:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码