文章目录

  • 前言
  • 一 工作原理
  • 二 使用范围
  • 三 例子
    • 1. COB-ID分析
    • 2. 报文内容分析 --- 读操作
      • 命令提示符
      • 索引和子索引
      • 报文中的数据值
    • 3. 报文内容分析 --- 写操作
      • 命令提示符
      • 索引和子索引
      • 报文中的数据值
    • 3. Segment传输
      • 读的发起
      • 读的数据传输
      • 写的发起和数据传输
    • 4. Block传输
    • 5. Abort
  • 四 总结

前言

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 timerunning = Truedef sigint_handler(signum, frame):global runningprint('')running = Falseexit(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 = 0x123time.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传输

请查看这篇文章

5. Abort

Server和Client都可以发送abort报文来中断报文传输,其CS值定义如下,

即0x80


四 总结

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

学习CANopen --- [5] SDO相关推荐

  1. CANOpen中SDO和PDO的COB-ID理解

    CANOpen用来收发数据的通信对象有SDO(Service Data Object)和PDO(Process Data Object) 一 SDO和PDO的区别 SDO使用对象字典的Index和Su ...

  2. 学习CANopen --- [2] PythonCANopen简单用法

    本文主要讲述如何在Linux下使用python进行简单的CANopen通信,使用了一个叫CANopen for Python的库,地址是https://github.com/christiansand ...

  3. 基于STM32F4的CANopen快速SDO通信(超级详细)

    基于STM32的CANopen快速SDO通信 前言 1 快速sdo介绍 2 工程配置 2.1 主站词典配置 2.2节点词典配置 3 快速SDO调用代码 4 末尾 本专题相关教程: 基于STM32F4的 ...

  4. 学习CANopen --- [3] NMT报文

    本文主要讲述CANopen中的NMT报文,即网络管理(Network ManagemenT),该服务可以用于启动网络和监控设备. NMT报文由NMT主机发送,对从机进行启动.监控和重启,在CANope ...

  5. CANopen中SDO、PDO、以及COB-ID理解

    CAN 总线是一种串行通信协议,具有较高的通信速率的和较强的抗干扰能力,可以作为现场总线应用于电磁噪声较大的场合. 由于CAN 总线本身只定义ISO/OSI 模型中的第一层(物理层)和第二层(数据链路 ...

  6. CANopen之SDO,PDO

    一.简述 CAN 总线是一种串行通信协议,具有较高的通信速率的和较强的抗干扰能力,可以作为现场总线应用于电磁噪声较大的场合.由于 CAN 总线本身只定义ISO/OSI 模型中的第一层(物理层)和第二层 ...

  7. 理论学习-协议栈学习-CANopen协议梳理

    CANopen协议梳理 开放式系统互联模型 开放式系统互联模型 #mermaid-svg-vgZNn3jf2tTpscn0 .label{font-family:'trebuchet ms', ver ...

  8. 学习CANopen --- [10] 汽车外接OBD模块原理

    在某宝上搜索汽车OBD,可以发现很多卖OBD模块的,通过接入OBD模块可以增加车子本身没有的功能,如锁车升窗,行车自动落锁和后视镜折叠等,那么其实现原理是什么呢?使用时会造成亏电吗? 一 原理 OBD ...

  9. 机器人开发--CanOpen

    机器人开发--CanOpen 1 介绍 1.1 概述 1.2 应用 2 历史发展 3 协议 3.1 协议细节(来自CiA文档) 3.2 协议框架 OSI 模型 服务 COB-ID NMT SYNC 紧 ...

最新文章

  1. 你心动了吗?2014年iOS应用开发者收入超好莱坞美国票房
  2. 机器学习:SVM算法的对偶形式
  3. electron 入坑记
  4. 数字图像处理:视觉系统中的坐标系介绍
  5. ora28500 mysql_Oracle使用 ODBC+DBLINK 访问 Mysql
  6. Java后端知识---数据结构(1)
  7. linux 对于Vim配置的方法
  8. 深入PHP使用技巧之变量
  9. Node:项目文件使用async报错var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _calle
  10. 【TeachNLP】文本数据处理-词表获取
  11. 基于大数据的数据挖掘算法-大数据
  12. Drools规则引擎快速入门(一)
  13. shping cloud搭建大觅网-之sping cloud初体验
  14. 睡眠质量不好怎么改善,几个助眠好物帮助你睡安稳觉
  15. OSI的7层模型和TCP/IP四层模型
  16. 轻松创建FB和Ins故事广告,提升内容曝光率
  17. STM32全链路开发实战教程专栏总目录(2022.10.19更新)
  18. html语言margin,margin在html中的意思
  19. 【Python妙用】用200行Python代码制作一个迷宫小游戏
  20. Android开发 PDA网络调试

热门文章

  1. java 扑克游戏_Java扑克游戏——红心大战
  2. pycharm ValueError: source code string cannot contain null bytes
  3. tera服务器不显示,tera无法登陆怎么解决_tera无法登陆的快速解决方法介绍
  4. react ts环境搭建及ts格式写法
  5. 【科技杂谈】记录学习装重装系统的过程(非常规重装系统教学)
  6. Echarts实现世界地图
  7. 新农慕课python第四周答案_Python编程_章节测验,期末考试,慕课答案查询公众号
  8. 以下python注释代码、叙述中不正确的是_关于 Python 语言的注释,以下选项中描述错误的是( )_学小易找答案...
  9. 幼年产品狗如何养成?这是完全自我修炼教程!
  10. 开源项目-汽车管理系统