CANopen

CANopen 是建立在 CAN 总线之上的特定协议,广泛用于协调共享同一总线的简单现场设备——驱动器、I/O 模块、传感器。CANopen 规范定义了对象字典(OD),本驱动通过字段的索引与子索引来遵循这一结构。它不提供电子数据表(EDS)解析器,需要使用该功能的应用可自行实现。
支持的操作
名称 值 描述
CANopen SDO
read / write
SDO 是请求/响应式的会话。读取和写入路径均受支持。
CANopen PDO
write
PDO 消息以广播方式发送到总线,必须在应用层进行映射。
subscribe
- 接收 PDO 消息需要构造有效的订阅。
- 可以订阅 CANopen NMT 和 HEARTBEAT 消息。
连接字符串
连接字符串的格式如下 canopen:<transport-code>://<transport-address>。
canopen:can-socketcan://can0canopen:can-virtualcan://test
接口名称和总线名称也可以作为选项提供——can-socketcan.interface-name 和 can-virtualcan.bus-name——供仅通过选项拼接连接字符串的调用方使用。如果两者都指定了名称,则以地址段中的名称为准。
连接字符串选项
Name
Type
Default Value
Required
Description
Name
CANopen
Code
canopen
Maven 依赖
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-canopen</artifactId>
<version>1.0.0</version>
</dependency>默认传输层
can-socketcan
支持的传输方式
can-socketcancan-virtualcan
配置选项:
node-id
INT
CAN 节点标识符。根据所使用的 CAN 版本不同,它可能是 11 位或 29 位的无符号整数。
request-timeout-ms
INT
1000
已派发的总线操作(例如 SDO 请求)在超过该时间后将被标记为失败。
传输配置选项:
can-socketcan
can-socketcan.interface-name
STRING
Linux CAN 接口名称(例如 "can0"、"vcan0")。这是在连接字符串的地址段中指定接口名称的替代方式,地址段中的指定方式优先。
can-socketcan.reuse-interface
BOOLEAN
false
在相同接口上的多个传输实例之间共享 CAN socket
can-socketcan.read-timeout-ms
INT
1000
CAN socket 上阻塞读取的读取超时时间(毫秒)
can-socketcan.filter-ids
STRING
接受的 CAN ID 逗号分隔列表(十进制或 0x 十六进制)。留空表示接受全部。
can-socketcan.filter-range-start
INT
-1
接受的 CAN ID 范围起点(包含)。-1 表示不进行范围过滤。
can-socketcan.filter-range-end
INT
-1
接受的 CAN ID 范围的结束值(包含)。-1 表示不进行范围过滤。
can-virtualcan
can-virtualcan.bus-name
STRING
default
虚拟 CAN 总线的名称。位于同一总线上的各实例在内存中交换帧。
can-virtualcan.filter-ids
STRING
以逗号分隔的可接受 CAN ID 列表(十进制或 0x 十六进制)。留空表示接受全部。
can-virtualcan.filter-range-start
INT
-1
接受的 CAN ID 范围的起始值(包含该值)。-1 表示不进行范围过滤。
can-virtualcan.filter-range-end
INT
-1
接受的 CAN ID 范围结束值(含)。-1 表示不做范围过滤。
标签地址
地址的实现位于 Java 中。请参阅 协议支持矩阵,了解各实现的具体行为。
通用格式
CANopen 规范定义了若干组地址,每组专用于特定类型的操作。与这些操作相关的关键服务和消息交换拥有较低的标识符,因此在总线仲裁中能获得优先访问权。
SDO 地址用于对单个对象字典条目进行请求/响应式的读写:SDO:nodeId:index/subindex:type[arraySize]。加快速传输和分段传输两种模式均受支持,会根据负载长度自动选择;块传输不受支持。所有数值——节点 ID、索引、子索引——均可使用十六进制表示法指定(例如 0xA)。在节点 ID 之后可加一个可选的 /answerNodeId,表示期望由与请求发送对象不同的节点作出响应。
PDO 地址用于标识节点的四条发送或接收 PDO 通道之一:TRANSMIT_PDO_1:nodeId:type[arraySize] 到 RECEIVE_PDO_4:nodeId:type[arraySize]。PDO 是异步广播,因此接收它需要订阅;订阅者会收到映射为地址中所给类型的值。
NMT 地址针对网络管理服务,该服务使用 CAN 节点 ID 0 广播,在总线上具有最高优先级。其语法为 NMT 或 NMT:nodeId;省略节点 ID(或使用 0)即为通配符,会订阅总线上所有参与者的状态更新。订阅会收到一个包含两个字段的结构体:node(USINT)和 state(USINT)。可写入的值表示所请求的 NMT 状态,以 USINT 形式提供:0x01 START、0x02 STOP、0x80 PRE_OPERATIONAL、0x81 RESET_NODE、0x82 RESET_COMMUNICATION。在应用侧可以使用 NMTStateRequest 枚举代替纯数字。
心跳地址订阅总线上优先级最低的服务,该服务仍能指示节点的运行状态(已启动、运行中)。其语法为 HEARTBEAT 或 HEARTBEAT:nodeId;与 NMT 一样,省略节点 ID(或使用 0)会订阅总线上所有参与者。订阅收到的结构体与 NMT 相同,包含两个字段:node(USINT)和 state(USINT)。
数据类型
CANopen 定义了自己的一套数据类型,本驱动将其映射到 PLC4X 类型的方式如下:
| CANopen 类型 | 长度(位) | PLC4X 类型 |
|---|---|---|
| BOOLEAN | 1 | BOOL |
| UNSIGNED8 | 8 | USINT |
| UNSIGNED16 | 16 | UINT |
| UNSIGNED24 | 24 | UDINT |
| UNSIGNED32 | 32 | UDINT |
| UNSIGNED40 | 40 | ULINT |
| UNSIGNED48 | 48 | ULINT |
| UNSIGNED56 | 56 | ULINT |
| UNSIGNED64 | 64 | ULINT |
| INTEGER8 | 8 | SINT |
| INTEGER16 | 16 | INT |
| INTEGER24 | 24 | DINT |
| INTEGER32 | 32 | DINT |
| INTEGER40 | 40 | LINT |
| INTEGER48 | 48 | LINT |
| INTEGER56 | 56 | LINT |
| INTEGER64 | 64 | LINT |
| REAL32 | 32 | REAL |
| REAL64 | 64 | LREAL |
| RECORD | 8 * size | BYTE |
| OCTET_STRING | 8 * size | STRING (UTF-8) |
| VISIBLE_STRING | 8 * size | STRING (UTF-8) |
| TIME_OF_DAY | 不支持 | |
| TIME_DIFFERENCE | 不支持 | |
| UNICODE_STRING | 8 * size | STRING (UTF-8) |
所有字符串类型不论其种类(八位字节串、可见字符串、Unicode 字符串),均使用 UTF-8 编码进行解码。如果设备以其他编码返回文本,建议使用 RECORD 类型,并在 PLC4X 之上手动构造该文本。
可变长度结构的大小会自动假定为 SDO 应答的完整长度。写入时可以省略该字段的长度;例如 write(SDO:1:2/3:RECORD, payload) 会尝试将整个负载写入指定地址。设备发送的响应也是如此,因为请求方通常事先并不知道回复负载的完整长度。
示例
SDO:20:0x10/0xAA:RECORD- 以RECORD类型读写节点 20 上索引0x10、子索引0xAA的对象。SDO:20/22:0x10/0xAA:RECORD- 同一个对象,但期望的响应来自节点 22 而非节点 20。SDO:20:0x30/40:BOOLEAN- 节点 20 上索引0x30、子索引40(十进制)的对象,类型为BOOLEAN。RECEIVE_PDO_2:20:RECORD- 节点 20 的第二个接收 PDO,映射为RECORD类型。NMT:20- 订阅或写入节点 20 的 NMT 状态变更。NMT- 订阅总线上每个节点的 NMT 状态变更(通配符)。HEARTBEAT- 订阅总线上每个节点的心跳消息(通配符)。
协议细节
CAN 由于(或正因为)其流行而具有歧义的含义。有许多文章和资料试图进行介绍,但它们彼此之间却很少一致。
帧有两种主流格式——CAN 2.0A 和 2.0B:
- CAN 2.0A 使用 11 位标识符,数据最多 8 字节。
- CAN 2.0B 使用 29 位标识符,数据最多 8 字节。
更糟糕的是,随着 CAN FD 的引入,组合数量进一步增加。请仔细核对帧格式,因为本集成支持 CANopen,但不支持 CANopen FD,也不支持 CAN 2.0B。
关于各类 CAN 变体的延伸阅读:https://en.wikipedia.org/wiki/CAN\_bus](https://en.wikipedia.org/wiki/CAN_bus)
该协议默认使用的传输方式是 socketcan。目前仅支持 2.0A 格式(数据最多 8 字节)。
已实现的驱动目前支持 socketcan 传输方式。若要更换传输方式,需要修改代码并注入新的 "transport" 类型,由该类型将 CANopen 负载编码为特定的帧格式。
Socketcan 似乎是访问 CAN 总线最为普遍的方式。它还能屏蔽不同的硬件变体,这些硬件变体可能带有各自的驱动程序。
评论
登录后参与评论
KnowForge