1. CANOpen——在ISO层级中位置和诞生

CAN(Controller Area Network)现场总线仅仅定义了第1层(物理层,见ISO11898-2标准)、第2层(数据链路层,见ISO11898-1标准),而在实际设计中,这两层完全由硬件实现,设计人员无需再为此开发相关软件(Software)或固件(Firmware),只要了解如何调用相关的接口和寄存器,即可完成对CAN的控制。

但CAN没有规定应用层。也就是没有规定与实际应用相关的逻辑,比如开关量输入输出,模拟量输入输出。所以本身对于应用来说,是不完整的。这就像铁矿石(物理层)冶炼成铁锭(数据链路层),然后针对具体应用,再加工做成汽车、轮船、钢筋、坦克、钢结构建筑等等。CANOPEN协议是基于CAN总线协议建立的应用层协议。

CANopen协议是在20世纪90年代末,由总部位于德国纽伦堡的CiA组织——CAN-in-Automation,(http://www.can-cia.org )在CAL(CAN Application Layer)的基础上发展而来。
由于CANopen协议的创始人团队也是CAN-bus的创始人团队,此协议充分发挥了CAN-bus所具备的所有优势,特别是CiA组织的主席蔡豪格(Holger Zeltwanger)先生对于CANopen协议坚持开放、免费、非盈利的原则。一经推出便在欧洲得到了广泛的认可与应用。时至今日已经成为全世界最为流行的CAN应用层协议。让我们记住这位可爱的德国老人。

2、CANOpen——协议帧


CANOPEN协议的基本通信单元叫做“通信对象”。常用的通信对象有NMT、SYNC、EMERGENCY、TIME STAMP、SDO、PDO这几个,他们结构相同,包括funciton Code、Node-ID、DLC(数据长度)、DATA(数据)四部分构成,本质上都是通过封装CAN总线协议的数据帧实现的。他们的不同体现在DATA这个部分,有的对象DATA部分可以完全用来传输数据,有的对象针对DATA部分进一步做了划分和要求。报文传输采用CAN标准帧格式。即11bit的ID域,以尽量减小传输时间;

3、CANOpen——对象


CANopen总线协议也分为两种基本的数据传输机制:通过进程数据对象(PDO)对小型的数据进行高速数据交换以及通过服务数据对象(SDO)对对象字典进行访问。后者主要用于在设备配置过程中传输参数以及传输大数据块。

4、CANOpen——网络管理NMT(Network management)

一个CANopen网络中为了保证可靠、可控,必须要NMT网络管理,就像一个军队一样,要令行禁止,才能达到稳定、高效的目标。如图 6.1所示。指挥员(NMT主机,CANOPEN主站)通过发号施令,士兵(NMT从机)进行自由俯卧训练,这样整个训练都是有序的。


所以每个CANopen从节点的CANopen协议栈中,必须具备NMT管理的相应代码,这是节点具备CANopen协议的最基本的要素。

5、CANOpen——NMT节点状态


6、CANOpen——NMT节点上线报文

任何一个CANopen从站上线后,为了提示主站它已经加入网络(便于热插拔),或者避免与其他从站Node-ID冲突。这个从站必须发出节点上线报文(boot-up),如图所示,节点上线报文的ID为700h+Node-ID,数据为1个字节0。生产者为CANopen从站。

7、CANOpen——NMT节点状态与心跳报文

为了监控CANopen节点是否在线与目前的节点状态。CANopen应用中通常都要求在线上电的从站定时发送状态报文(心跳报文),以便于主站确认从站是否故障、是否脱离网络。
如图所示,为心跳报文发送的格式,CANID与节点上线报文相同为700h+Node-ID,数据为1个字节,代表节点目前的状态,04h为停止状态,05h为操作状态,7Fh为预操作状态。
CANopen从站按其对象字典中1017h中填写的心跳生产时间(ms)进行心跳报文的发送,而CANopen主站(NMT主站)则会按其1016h中填写的心跳消费时间进行检查,假设超过诺干次心跳消费时间没有收到从站的心跳报文,则认为从站已经离线或者损坏。

8、CANOpen——NMT节点状态切换命令

NMT网络管理中,最核心的就是NMT节点状态切换命令,这是NMT主站所进行网络管理的“命令”报文。使用者必须牢记这些命令。
CANID均为000h,具备最高的CAN优先级。数据为2个字节:
 第1个字节代表命令类型:
01h为启动命令(让节点进入操作状态);
02h为停止命令(让节点进入停止状态);
80h为进入预操作状态(让节点进入预操作状态);
81h为复位节点应用层(让节点的应用恢复初始状态,比如列车门都恢复打开状态);
82h为复位节点通讯(让节点的CAN和CANopen通讯重新初始化,一般用于总线收到干扰,导致节点总线错误被动,或者总线关闭时)。
 第二个字节代表被控制的节点Node-ID,
如果要对整个网络所有节点同时进行控制,则这个数值为0即可。

9、CANOpen——PDO对象(Process data object)

PDO对象称为“过程数据对象”,用于无连接的数据传输,即A站发送数据给B站后,不需要等待B站给出确认收到的应答。当然B站也可以应答一些信息给A站,这个有点像网络通信中的UDP协议,即应答不是强制要求的,B站可以回答,也可以不回答。
PDO对象的DATA部分可以完全用来传输数据,没有进步做要求。一个PDO最大可传输8字节数据。

PDO分为TPDO(发送PDO)和(接收RPDO),发送和接收是以CANopen节点自身为参考(如果CAN主站或者其他从站就相反)。TPDO和RPDO分别有4个数据对象,每种数据对象就是1条CAN报文封装。

10、CANOpen——SDO对象(Service data object)

SDO称“服务数据对象”,主要用于CANopen主站对从节点的参数配置,是一个有应答的通信对象,即主站发送RSDO给从站后,从站如果接收到,必须发送TSDO给主站进行应答。

SDO的通讯原则非常单一,发送方(客户端)发送CAN-ID为600h+Node-ID的报文,其中Node-ID为接收方(服务器)的节点地址,数据长度均为8字节; 接收方(服务器)成功接收后,回应CAN-ID为580h+Node-ID的报文。这里的Node-ID依然是接收方(服务器)的节点地址,数据长度均为8字节。


11、CANOpen——快速SDO协议(Expedited SDO protocol)

最常用最常见的SDO协议是快速SDO,所谓快速,就是1次来回就搞定。前提是读取和写入的值不能大于32位。如图所示,为快速SDO协议的示意图。命令中直接包含了要读写的索引、子索引、数据。可谓直接命中。快速SDO的难点在于CS命令符的记忆。
通过快速SDO,可以直接对CANopen节点的对象字典中的值进行读取和修改,所以在做参数配置之外,也经常作为关键性数据传输之用。比如CANopen控制机器人的电机转动角度时,就使用SDO来传输,保证可靠到达。

12、CANOpen——特殊协议(Special protocols)

一.同步协议(Sync protocol)
同步(SYNC),该报文对象主要实现整个网络的同步传输。
在同步协议中,有2个约束条件:
 同步窗口时间:索引1007h约束了同步帧发送后,从节点发送PDO的时效,即在这个时间内发送的PDO才有效,超过时间的PDO将被丢弃;
 通讯循环周期:索引1006h规定了同步帧的循环周期。

二.时间戳协议(Time-stamp protocol)
时间标记对象(Time Stamp),NMT主机发送自身的时钟,为网络各个节点提供公共的时间参考,即网络对时。
三.紧急报文协议(Emergency protocol)
紧急事件对象(Emergency),是当设备内部发生错误,触发该对象,发送设备内部错误代码,提示NMT主站。紧急报文属于诊断性报文,一般不会影响CANopen通讯.

13、CANOpen——对象字典OD(Object dictionary)

CANopen对象字典(OD: Object Dictionary)是CANopen协议最为核心的概念。所谓的对象字典就是一个有序的对象组,描述了对应CANopen节点的所有参数,包括通讯数据的存放位置也列入其索引,这个表变成可以传递形式就叫做EDS文件(电子数据文档Electronic Data Sheet)

每个对象采用一个16位的索引值来寻址,这个索引值通常被称为索引,其范围在0x0000到0xFFFF之间。为了避免数据大量时无索引可分配,所以在某些索引下也定义了一个8 位的索引值,这个索引值通常被称为子索引,其范围是0x00到0xFF之间。 每个索引内具体的参数,最大用32位的变量来表示,即Unsigned32,四个字节。

14、CANOpen——通讯对象子协议区(Communication profile area)

通讯对象子协议区(Communication profile area)定义了所有和通信有关的对象参数,如表 5.2所示,标绿色底纹的索引范围1000h to 1029h为通用通讯对象,所有CANopen节点都必须具备这些索引,否则将无法加入CANopen网络。其他索引根据实际情况进行分配与定义。

15、CANOpen——通用通讯对象(General communication objects)

由于通用通讯对象十分重要,NMT主站(CANopen主站)在启动时,通常都全部或者部分读取所有从站中通用通讯对象中的索引,所以所有的通用通讯对象都必须在CANopen从站中实现,使用者也必须熟知这些索引地址与其含义。


16、CANOpen——子协议
一、制造商特定子协议(Manufacturer-specific Profile)
对象字典索引2000h to 5FFFh为制造商特定子协议,通常是存放所应用子协议的应用数据。而上文所描述的通讯对象子协议区(Communication profile area)是存放这些应用数据的通信参数。比如广州致远电子的XGate-COP10从站模块规定了:
 RPDO的通讯参数存放在1400h to 15FFh ,映射参数存放在1600h to 17FFh ,数据存放为2000h 之后厂商自定义区;
 TPDO的通讯参数存放在1800h to 19FFh ,映射参数存放在1A00h to 1BFFh ,数据存放为2000h 之后厂商自定义区。
对于在设备子协议中未定义的特殊功能,制造商也可以在此区域根据需求定义对象字典对象。因此这个区域对于不同的厂商来说,相同的对象字典项其定义不一定相同。
二. 标准化设备子协议(Standardized profile area)
标准化设备子协议,为各种行业不同类型的标准设备定义对象字典中的对象。目前已有十几种为不同类型的设备定义的子协议,例如 DS401、DS402、DS406等,其索引值范围为0x6000~0x9FFF。同样,这个区域对于不同的标准化设备子协议来说,相同的对象字典项其定义不一定相同。

17、一些为python调试代码

from ctypes import *
if 1:dll = windll.LoadLibrary('./ControlCAN.dll')nDeviceType = 21 #* USBCAN-2E-U *nDeviceInd = 0#* 索引号0 *nReserved = 0nCANInd = 1 #can通道号class _VCI_INIT_CONFIG(Structure):_fields_ = [("AccCode", c_ulong), ("AccMask", c_ulong), ("Reserved", c_ulong), ("Filter", c_ubyte),("Timing0", c_ubyte), ("Timing1", c_ubyte), ("Mode", c_ubyte)]class _VCI_CAN_OBJ(Structure):_fields_ = [("ID", c_uint), ("TimeStamp", c_uint), ("TimeFlag", c_ubyte), ("SendType", c_ubyte),("RemoteFlag", c_ubyte), ("ExternFlag", c_ubyte), ("DataLen", c_ubyte), ("Data", c_ubyte*8),("Reserved", c_ubyte*3)]vic = _VCI_INIT_CONFIG()vic.AccCode = 0x00000000vic.AccMask = 0xffffffffvic.Filter = 0vic.Timing0 = 0x00vic.Timing1 = 0x1cvic.Mode = 0vco = _VCI_CAN_OBJ()vco.ID = 0x00000001vco.SendType = 0vco.RemoteFlag = 0vco.ExternFlag = 0vco.DataLen = 8vco.Data = (0, 0, 0, 0, 0, 0, 0, 0)vco2 = _VCI_CAN_OBJ()#ubyte_array8 = c_ubyte*8#ubyte_array3 = c_ubyte*3vco2.ID = 0x00000001vco2.SendType = 0vco2.RemoteFlag = 0vco2.ExternFlag = 0vco2.DataLen = 8vco2.Data = (0, 0, 0, 0, 0, 0, 0, 0)ret = dll.VCI_OpenDevice(nDeviceType, nDeviceInd, nReserved)print("opendevice:",ret)ret = dll.VCI_SetReference(nDeviceType, nDeviceInd, nCANInd, 0, pointer(c_int(0x060007)))print("setrefernce1:",ret)ret = dll.VCI_SetReference(nDeviceType, nDeviceInd, 0, 0, pointer(c_int(0x060007)))print("setrefernce0:",ret)  #注意,SetRefernce必须在InitCan之前ret = dll.VCI_InitCAN(nDeviceType, nDeviceInd, nCANInd, pointer(vic))print("initcan1:",ret)ret = dll.VCI_InitCAN(nDeviceType, nDeviceInd, 0, pointer(vic))print("initcan0:",ret)ret = dll.VCI_StartCAN(nDeviceType, nDeviceInd, nCANInd)print("startcan1:",ret)ret = dll.VCI_StartCAN(nDeviceType, nDeviceInd, 0)print("startcan0:",ret)
rx_n = 0
while 1:ret = dll.VCI_Receive(nDeviceType, nDeviceInd, 0, pointer(vco2), 1, -1)# 发送1帧if ret > 0:rx_n +=1show = 'RXD n: {}\t ID:  {}\t len:  {}\t data:{}'.format(rx_n,hex(vco2.ID), vco2.DataLen, [hex(i) for i in list(vco2.Data[0:vco2.DataLen])])print(show)# ret = dll.VCI_Transmit(nDeviceType, nDeviceInd, 0, pointer(vco2), 1)  # 发送两帧# print("transmit:", ret)# ret = 0if vco2.ID&0xf80 == 0x600 and vco2.DataLen==8 and (vco2.Data[0]==0x23 or vco2.Data[0] == 0x2f or vco2.Data[0] == 0x2b or vco2.Data[0] == 0x27):vco.ID = 0x580+vco2.ID&0x07fData = [0,0,0,0,0,0,0,0]Data[0] = 0x60Data[1] = vco2.Data[1]Data[2] = vco2.Data[2]Data[3] = vco2.Data[3]vco.Data = tuple(Data)show = 'TXD n: {}\t ID:  {}\t len:  {}\t data:{}'.format(rx_n, hex(vco.ID), vco.DataLen,[hex(i) for i in list(vco.Data[0:vco.DataLen])])print(show)ret = dll.VCI_Transmit(nDeviceType, nDeviceInd, 0, pointer(vco), 1)  # 发送两帧print("transmit:", ret)
from ctypes import *dll = windll.LoadLibrary('./ControlCAN.dll')
nDeviceType = 21 #* USBCAN-2E-U *
nDeviceInd = 0#* 索引号0 *
nReserved = 0
nCANInd = 1 #can通道号class _VCI_INIT_CONFIG(Structure):_fields_ = [("AccCode", c_ulong), ("AccMask", c_ulong), ("Reserved", c_ulong), ("Filter", c_ubyte),("Timing0", c_ubyte), ("Timing1", c_ubyte), ("Mode", c_ubyte)]
class _VCI_CAN_OBJ(Structure):_fields_ = [("ID", c_uint), ("TimeStamp", c_uint), ("TimeFlag", c_ubyte), ("SendType", c_ubyte),("RemoteFlag", c_ubyte), ("ExternFlag", c_ubyte), ("DataLen", c_ubyte), ("Data", c_ubyte*8),("Reserved", c_ubyte*3)]
#ubyte_array8 = c_ubyte*8
#ubyte_array3 = c_ubyte*3
vic = _VCI_INIT_CONFIG()
vic.AccCode = 0x00000000
vic.AccMask = 0xffffffff
vic.Filter = 0
vic.Timing0 = 0x00
vic.Timing1 = 0x1c
vic.Mode = 0vco = _VCI_CAN_OBJ()
vco.ID = 0x00000001
vco.SendType = 0
vco.RemoteFlag = 0
vco.ExternFlag = 0
vco.DataLen = 8
vco.Data = (1, 2, 3, 4, 5, 6, 7, 8)ret = dll.VCI_OpenDevice(nDeviceType, nDeviceInd, nReserved)
print("opendevice:",ret)
ret = dll.VCI_SetReference(nDeviceType, nDeviceInd, nCANInd, 0, pointer(c_int(0x060007)))
print("setrefernce0:",ret)  #注意,SetRefernce必须在InitCan之前
ret = dll.VCI_InitCAN(nDeviceType, nDeviceInd, nCANInd, pointer(vic))
print("initcan0:",ret)
ret = dll.VCI_StartCAN(nDeviceType, nDeviceInd, nCANInd)
print("startcan0:",ret)
while 1:# print("transmit:",ret)ret = dll.VCI_Receive(nDeviceType, nDeviceInd, nCANInd, pointer(vco), 1, -1)#if ret > 0:show = 'ID:{},len:{},data:{}'.format(hex(vco.ID),vco.DataLen,vco.Data)print(show)ret = dll.VCI_Transmit(nDeviceType, nDeviceInd, nCANInd, pointer(vco), 1)  #

CanOpen通信协议python实现相关推荐

  1. CanOpen协议的伺服驱动控制

    一.CanOpen的基本介绍: 1.基本介绍: CanOpen在CAN网络7层协议中,处于应用层.CANopen协议是在20世纪90年代末,由CIA组织CAN-in-Automation,(http: ...

  2. 基于STM32F4的CANOpen移植教程(超级详细)

    CANopen移植到STM32F4平台 前言 1 物品准备 2 相关软件安装 2.1 CAN上位机 2.2 对象字典生成工具objdictedit环境配置 3 将CANopen移植到STM32F407 ...

  3. 虹科分享 | 简单实用的CANopen介绍,看完你就明白了(2)——CANopen框架与七种服务类型

    目前,CANopen通讯协议已经在工业领域得到了广泛的使用,由于其面向对象的设计思路,CANopen协议已成为欧洲等国家的自动化公司标配的通讯接口之一.在本系列文章中,我们将介绍CANopen协议的基 ...

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

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

  5. 西门子1200系列PLC的CANopen通信解决方案

    背景 智能制造成为趋势,其基础常常是连接各种设备.CANopen协议因其中立和推出时间较长,在变频.伺服驱动.风力发电中有较广泛的应用.西门子的1200系列PLC性价比高,也得到越来越多用户的欢迎,该 ...

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

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

  7. CANopen补充--主站检测节点是否在线

    本专题相关教程: 基于STM32F4的CANOpen移植教程 基于STM32F4的CANopen快速SDO通信 linux下CANopen for python的使用 基于Linux C的CANope ...

  8. 基于Linux C的CANopen移植

    基于Linux C的CANopen移植 0 基础要求 1 新建工程 1.1 h文件移植 1.2 c文件移植 2 建立自己的底层驱动文件 3 建立词典 4 main文件 5 CMakeLists编写 6 ...

  9. 广成GCAN-IO模块介绍

    广成GCAN-IO模块介绍 1 介绍 1.1 概述 1.2 特点 2 功能(8000) 2.1 图示 2.2 电源接线端子排 2.3 串口修改配置 3 协议(8000) 3.0 CiA301 CANo ...

最新文章

  1. linux sh文件case,Shell脚本case语句简明教程
  2. FAT AP和FIT AP 区别 (无线篇)
  3. HIT 2634 How to earn more
  4. Django从理论到实战(part36)--QuerySet转换SQL
  5. ASP.NET刷新页面的六种方法
  6. Linux系统查看版本和位数
  7. hive udf 分组取top1_Hive中分组取前N个值的实现-row_number()
  8. gin的Bindxxx和ShouldBindxxx的区别
  9. livechart 只显示 y 值_【科研工具51】谷歌,谷歌学术,Scihub有效网址检索软件——Y学术...
  10. [机器学习]正则化项L1和L2的学习与理解
  11. spring boot入门学习---热部署
  12. matlab计算系统过渡过程时间,MATLAB在电机拖动拖动系统过渡过程分析中的应用
  13. 【跃迁之路】【648天】程序员高效学习方法论探索系列(实验阶段405-2018.11.21)...
  14. Multisim里导入没有的元器件(以NPN型三极管2N9013为例)
  15. 影响因素分析论文用什么模型好?
  16. jeecgboot功能优化——前端表格换行与不换行
  17. 力扣(66.67)补8.27
  18. request 使用方法
  19. Ubuntu查看Linux系统版本号
  20. plc-st编程语言学习_这就是您可以学习所有编程语言的方式,是的-“全部”

热门文章

  1. 我们请来了2017 NIPS大会发文数全球前3的华人教授,讲解网络数据的表征学习(视频+PPT)
  2. Python markdown转epub (格式间转换)
  3. SAP 中Table的使用(一、显示数据)
  4. 计算机键盘怎么换键,电脑修改键盘按键的方法
  5. 这些好用的跨境电商插件,你都听说几个?
  6. 从 0 到 1 开发一个聊天通讯 服务 复盘总结
  7. python老王卖西瓜_搞不懂Python?大神教你用Python买西瓜!
  8. Java——万字总结网络编程
  9. python敲七游戏代码_酒桌上的游戏
  10. 解决Android自定义相机预览和照片分辨率差异的问题