协议

CANopen

qianmoQqianmoQ· 更新于 2026-10-01· 阅读 11 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

banner

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://can0
  • canopen: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-socketcan
  • can-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 类型
BOOLEAN1BOOL
UNSIGNED88USINT
UNSIGNED1616UINT
UNSIGNED2424UDINT
UNSIGNED3232UDINT
UNSIGNED4040ULINT
UNSIGNED4848ULINT
UNSIGNED5656ULINT
UNSIGNED6464ULINT
INTEGER88SINT
INTEGER1616INT
INTEGER2424DINT
INTEGER3232DINT
INTEGER4040LINT
INTEGER4848LINT
INTEGER5656LINT
INTEGER6464LINT
REAL3232REAL
REAL6464LREAL
RECORD8 * sizeBYTE
OCTET_STRING8 * sizeSTRING (UTF-8)
VISIBLE_STRING8 * sizeSTRING (UTF-8)
TIME_OF_DAY不支持
TIME_DIFFERENCE不支持
UNICODE_STRING8 * sizeSTRING (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 总线最为普遍的方式。它还能屏蔽不同的硬件变体,这些硬件变体可能带有各自的驱动程序。

评论

登录后参与评论

正在加载评论…