系列文章目录
前言
CANopen 标准的 Python 实现。该项目的目的是在一个简单的 Pythonic 接口中支持 CiA 301 标准中最常见的部分。它主要针对测试和自动化任务,而不是符合标准的主实施。
该库支持 Python 3.6 及以上版本。
一、特点
该库主要用作主库。
- NMT 主站
- SDO 客户端
- PDO 生产者/消费者
- SYNC 生产者
- EMCY 消费者
- 时间生产者
- LSS 主站
- 来自 EDS 的对象字典
- 402 配置文件支持
还不完全支持创建从节点。
- SDO 服务器
- PDO 生产者/消费者
- NMT 从节点
- EMCY 生产者
- 来自 EDS 的对象字典
二、安装
使用 pip 从 PyPI 安装:
pip install canopen
从 GitHub 上的最新主站安装:
pip install https://github.com/christiansandberg/canopen/archive/master.zip
如果您希望在使用过程中更改代码,请克隆它,然后在开发模式下安装:
git clone https://github.com/christiansandberg/canopen.git cd canopen pip install -e .
单元测试可使用 pytest 框架运行:
pip install pytest pytest -v
三、文档
文档可在阅读文档中找到:
http://canopen.readthedocs.io/en/latest/
也可使用 Sphinx 从本地克隆生成:
python setup.py build_sphinx
四、硬件支持
该库通过 python-can 软件包支持多种硬件和驱动程序。请参阅支持的设备列表。
还可将此库与自定义后端集成。
五、快速启动
下面是一些快速操作示例:
可以通过三种形式访问 PDO:
第 1 种:node.tpdo[n] 或 node.rpdo[n] 。
第 2 种: node.pdo.tx[n] 或 node.pdo.rx[n]
第 3 次: 节点.pdo[0x1A00] 或节点.pdo[0x1600]
n 是 PDO 索引(通常为 1 至 4)。第二种访问方式用于向后兼容。
import canopen # Start with creating a network representing one CAN bus network = canopen.Network() # Add some nodes with corresponding Object Dictionaries node = canopen.RemoteNode(6, '/path/to/object_dictionary.eds') network.add_node(node) # Connect to the CAN bus # Arguments are passed to python-can's can.Bus() constructor # (see https://python-can.readthedocs.io/en/latest/bus.html). network.connect() # network.connect(bustype='socketcan', channel='can0') # network.connect(bustype='kvaser', channel=0, bitrate=250000) # network.connect(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000) # network.connect(bustype='ixxat', channel=0, bitrate=250000) # network.connect(bustype='vector', app_name='CANalyzer', channel=0, bitrate=250000) # network.connect(bustype='nican', channel='CAN0', bitrate=250000) # Read a variable using SDO device_name = node.sdo['Manufacturer device name'].raw vendor_id = node.sdo[0x1018][1].raw # Write a variable using SDO node.sdo['Producer heartbeat time'].raw = 1000 # Read PDO configuration from node node.tpdo.read() node.rpdo.read() # Re-map TPDO[1] node.tpdo[1].clear() node.tpdo[1].add_variable('Statusword') node.tpdo[1].add_variable('Velocity actual value') node.tpdo[1].add_variable('Some group', 'Some subindex') node.tpdo[1].trans_type = 254 node.tpdo[1].event_timer = 10 node.tpdo[1].enabled = True # Save new PDO configuration to node node.tpdo[1].save() # Transmit SYNC every 100 ms network.sync.start(0.1) # Change state to operational (NMT start) node.nmt.state = 'OPERATIONAL' # Read a value from TPDO[1] node.tpdo[1].wait_for_reception() speed = node.tpdo[1]['Velocity actual value'].phys val = node.tpdo['Some group.Some subindex'].raw # Disconnect from CAN bus network.sync.stop() network.disconnect()
# 导入canopen库以实现与CANopen设备的通信 import canopen # 初始化一个CAN网络,代表一条CAN总线 # 创建一个网络实例,用于管理CAN总线上的节点与通信 network = canopen.Network() # 向网络中添加一个节点,节点ID为6,并指定对象字典(Object Dictionary)的路径 # 该对象字典包含了设备的数据结构和通信参数 node = canopen.RemoteNode(6, '/path/to/object_dictionary.eds') # 将新创建的节点添加到网络中 network.add_node(node) # 连接到CAN总线 # 连接参数将传递给python-can库中的can.Bus构造器 # 更多关于连接参数的信息请参考python-can文档:https://python-can.readthedocs.io/en/latest/bus.html network.connect() # 根据实际使用的CAN接口和配置选择合适的连接方式,例如: # network.connect(bustype='socketcan', channel='can0') # network.connect(bustype='kvaser', channel=0, bitrate=250000) # ...其他连接示例省略... # 通过SDO读取变量 # 读取设备制造商名称和供应商ID device_name = node.sdo['Manufacturer device name'].raw vendor_id = node.sdo[0x1018][1].raw # 使用SDO写入变量 # 设置生产者心跳时间 node.sdo['Producer heartbeat time'].raw = 1000 # 读取PDO配置 # 分别读取TPDO和RPDO的当前配置 node.tpdo.read() node.rpdo.read() # 重新映射TPDO[1] # 清除现有映射 node.tpdo[1].clear() # 添加新的变量到TPDO[1] node.tpdo[1].add_variable('Statusword') node.tpdo[1].add_variable('Velocity actual value') # 支持通过组名和子索引映射变量 node.tpdo[1].add_variable('Some group', 'Some subindex') # 设置传输类型、事件定时器并启用该PDO node.tpdo[1].trans_type = 254 node.tpdo[1].event_timer = 10 node.tpdo[1].enabled = True # 保存新的PDO配置至节点,以便重启后仍生效 node.tpdo[1].save() # 设置每100毫秒发送一次SYNC报文 network.sync.start(0.1) # 改变节点状态为运行中(NMT启动命令) node.nmt.state = 'OPERATIONAL' # 从TPDO[1]接收数据并读取值 # 等待TPDO[1]的接收完成 node.tpdo[1].wait_for_reception() # 获取实际速度的物理值 speed = node.tpdo[1]['Velocity actual value'].phys # 通过组名和子索引读取原始值 val = node.tpdo['Some group.Some subindex'].raw # 断开与CAN总线的连接 # 停止发送SYNC报文 network.sync.stop() # 断开网络连接 network.disconnect()
六、调试
如果需要更详细地了解发生了什么,可以提高日志记录级别:
import logging logging.basicConfig(level=logging.DEBUG)