跳到主要内容

CANopen 驱动

概述

CANopen — CAN 总线之上的 EN 50325-4 / CiA 301 标准应用层(普遍用于电机驱动器 / 编码器 / IO 模块)。2026-07 原生重写 — 已移除旧的 Apache PLC4j canopen 委派方式(PLC4X CANopen 仅支持本地 SocketCAN transport,无法通过 TCP 承载,在没有物理 CAN 总线的边缘侧 connect 会失败)。现在使用 plantpulse-plc-protocol 中自研的 SDO expedited upload 实现(CanopenSdoClient)+ transport 抽象(CanTransport)——与 AB-ETH / BACnet 相同的原生模式。

项目
opc_typeCANOPEN
实现类plantpulse.driver.protocol.canopen.CANOpenDriver
自研原生plantpulse-plc-protocolcanopen — SDO expedited upload)
继承BaseProtocolDriver(非 PLC4j)
getProtocol()"canopen:tcp"(沿用旧 PLC4X scheme 表记 — 兼容日志/诊断)
默认端口20200(CAN-over-TCP 网关)
状态稳定(SDO expedited 轮询)
readOK(SDO expedited upload,值 ≤4 字节)
write❌(只读 — 未实现 SDO download)
安全
以 CAN-over-TCP 网关为前提

默认 transport(tcp)与 CAN ↔ TCP 网关 之后的 CANopen 节点通信。它将 CAN 帧以 canId(4B BE) + dlc(1B) + data[dlc] 自有的二进制帧格式承载到 TCP 上(无握手/总线名协商 — 与模拟器采用相同帧格式)。transport=socketcan(本地 can0目前为桩实现(需要 AF_CAN 原生绑定/JNI),因此 connect 会失败 —— 物理 CAN 接口路线为后续工作。


类结构

BaseProtocolDriver
└── CANOpenDriver — connect() 에서 CanTransport(tcp/socketcan) + CanopenSdoClient 생성

read 失败(Abort/超时/套接字)会使套接字失效(connected=false + close),促使边缘侧重新连接。


wire 格式摘要(自研实现 — SDO expedited upload)

  • 请求:COB-ID 0x600+nodeId,data [0x40, index LE(2B), subindex, 0×4]
  • 响应:COB-ID 0x580+nodeId,command 0x43(4B)/0x47(3B)/0x4B(2B)/0x4F(1B)——值为 little-endian。0x80 = Abort(代码 u32 LE)→ 通信异常。
  • 不支持 segmented / block transfer(值 >4B,例如长字符串)——对标量标签轮询而言,expedited 已足够。

OPC 注册选项

字段含义默认
opc_agent_ipCAN-TCP 网关 IP192.168.1.20
opc_agent_port网关 TCP 端口20200
options.read-timeoutSDO 响应超时(ms)3000
options.transporttcp / socketcan(桩实现)tcp
options.can-interfacesocketcan 模式接口名can0
已移除旧 PLC4X 选项

旧表单/文档中的 node-id 选项已废弃 —— 节点 ID 现在是标签地址的第 1 个字段(见下文)。request-timeout/heartbeat 选项原生实现同样不接受(超时使用 read-timeout)。


标签 plc_address 格式(新约定)

<nodeId>:<index>:<subindex>[:<TYPE>]
字段含义表记
nodeIdCANopen 节点 id(1..127)十进制
index对象字典 index(0..0xFFFF)0x 前缀十六进制(0x6041)或十进制
subindex子 index(0..255)0x 前缀十六进制或十进制
TYPE(可选)LE 字节解释类型省略时按 data_type 推断 → 若也没有则为 UINT16
表记含义
1:0x6041:0:UINT16节点 1,DS402 Statusword
3:0x2000:0:REAL节点 3,制造商区域 float32
1:0x6064:0:INT32Position actual value(32-bit signed)
5:8192:1节点 5,index 十进制 8192(=0x2000),省略 TYPE → UINT16

TYPE 记号(含别名)

记号(别名)大小解释
BOOLBOOLEAN1非 0 即 true
UINT8U8,USINT,BYTE) / INT8I8,SINT1u8 / i8
UINT16U16,UINT,WORD) / INT16I16,INT2u16 / i16(默认 UINT16)
UINT32U32,UDINT,DWORD) / INT32I32,DINT4u32 / i32
REALFLOAT,F32,REAL324IEEE-754 float(LE)
STRINGSTR,VISIBLE_STRING≤4ASCII(去除尾部 NUL)

省略 TYPE 时按 data_type 推断:Boolean→BOOL、Integer→INT16、Long→INT32、Float→REAL、Double→REAL(4B 近似)、String→STRING。


支持 / 不支持

  • read:SDO expedited upload(≤4 字节)— OK。
  • write:不支持isWriteSupported() = falsewrite() 始终为 false。(SDO download 为后续工作。)
  • segmented / block SDO、PDO 映射、NMT / Heartbeat 监视、SYNC、EMCY、LSS:不支持。
  • 直连 SocketCAN / USB-CAN:桩实现(以 CAN-over-TCP 网关为前提)。

curl 注册示例

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_CANOPEN_DRIVE1",
"opc_type": "CANOPEN",
"opc_name": "Servo Drive 1",
"opc_agent_ip": "192.168.1.20",
"opc_agent_port": "20200",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "read-timeout": "3000" },
"tag_list": [
{"tag_id":"OPC_CANOPEN_DRIVE1_T01","tag_name":"Statusword","plc_address":"1:0x6041:0:UINT16","data_type":"Integer"},
{"tag_id":"OPC_CANOPEN_DRIVE1_T02","tag_name":"ActualPos","plc_address":"1:0x6064:0:INT32","data_type":"Long"}
]
}'

参考

  • CiA 301(Application Layer)/ CiA 402(Drives)标准。
  • 代码:plantpulse-edge-driver/src/plantpulse/driver/protocol/canopen/CANOpenDriver.java + plantpulse-plc-protocolcanopen 包。
  • 运维:网关帧格式为自有二进制(canId+dlc+data)——与 socketcand 文本协议不同。建议依据设备 EDS 文件校验地址。