CANopen 通讯
Darra PLC 通过 CANopenDriver 实现 CANopen 主站功能, 支持 NMT 网络管理、PDO 过程数据、SDO 服务数据等 CANopen 核心协议。
协议概述
CANopen 基于 CAN 总线 (ISO 11898), 广泛用于运动控制、传感器网络和嵌入式系统。
支持的通讯对象
| 对象 | COB-ID 范围 | 方向 | 说明 |
|---|---|---|---|
| NMT | 0x000 | 主→从 | 网络管理 (启动/停止/复位) |
| SYNC | 0x080 | 主→全部 | 同步触发 |
| EMCY | 0x081~0x0FF | 从→主 | 紧急报文 |
| TPDO1~4 | 0x181~0x480 | 从→主 | 过程数据 (从站发送) |
| RPDO1~4 | 0x201~0x500 | 主→从 | 过程数据 (从站接收) |
| TSDO | 0x581~0x5FF | 从→主 | 服务数据响应 |
| RSDO | 0x601~0x67F | 主→从 | 服务数据请求 |
| Heartbeat | 0x701~0x77F | 从→主 | 心跳检测 |
NMT 状态机
CANopen 从站遵循标准 NMT 状态机:
┌──────────────┐
上电 → │ Initializing │
└──────┬───────┘
↓ (自动)
┌──────────────┐
│ Pre-Operational │ ← SDO 配置
└──────┬───────┘
↓ (NMT Start)
┌──────────────┐
│ Operational │ ← PDO 数据交换
└──────┬───────┘
↓ (NMT Stop)
┌──────────────┐
│ Stopped │
└──────────────┘
连接配置
{
"protocol": "CANopen",
"interface": "PCAN-USB",
"channel": 1,
"baudRate": 500000,
"nodeId": 1,
"syncPeriodMs": 10,
"heartbeatMs": 1000
}
支持的 CAN 接口:
- PCAN-USB (Peak Systems)
- Kvaser USB
- Ixxat USB-to-CAN
- SocketCAN (Linux, 待支持)
PDO 映射
PDO 映射通过对象字典 (Object Dictionary) 配置:
| PDO | 默认映射 (CiA 402) | 用途 |
|---|---|---|
| RPDO1 | 0x6040 (Controlword) | 伺服控制字 |
| RPDO2 | 0x607A (Target Position) | 目标位置 |
| TPDO1 | 0x6041 (Statusword) | 伺服状态字 |
| TPDO2 | 0x6064 (Position Actual) | 实际位置 |
SDO 读写
SDO 用于参数配置和诊断:
// 创建 CANopen 主站
var driver = new CANopenDriver();
driver.Initialize("PCAN-USB", 500000);
// SDO 读取: 节点 1, 索引 0x6041 (Statusword)
ushort status = driver.SdoRead<ushort>(nodeId: 1, index: 0x6041, subIndex: 0);
// SDO 写入: 节点 1, 索引 0x6040 (Controlword)
driver.SdoWrite(nodeId: 1, index: 0x6040, subIndex: 0, value: (ushort)0x0006);
// 启动所有从站
driver.NmtCommand(0x00, NmtState.Operational); // NodeId=0 广播
与 PLC 集成
CANopen 数据通过共享内存与 PLC 引擎交互:
- PDO 数据 自动映射到 PLC 的 IO 区域 (DI/DO/AI/AO)
- CiA 402 伺服 自动映射到关节数据区域 (与 EtherCAT 共享结构)
- SYNC 周期与 PLC 扫描周期对齐
CAN 总线波特率与最大线缆长度成反比:
- 1 Mbps: 最大 25m
- 500 kbps: 最大 100m
- 125 kbps: 最大 500m
对象字典
CANopen 的核心是 Object Dictionary (对象字典), 每个节点暴露一个 64K 条目的索引空间:
| 索引范围 | 用途 |
|---|---|
| 0x0001~0x001F | 标准数据类型 |
| 0x0020~0x003F | 标准复合类型 |
| 0x1000~0x1FFF | 通讯对象 (CiA 301) |
| 0x2000~0x5FFF | 厂商自定义 |
| 0x6000~0x9FFF | 标准设备档 (CiA 401/402/...) |
| 0xA000~0xFFFF | 网络变量 |
常用条目:
0x1000Device Type (必须)0x1001Error Register0x1008Manufacturer Device Name0x1017Heartbeat Producer Time0x1018Identity Object (Vendor ID / Product Code / Revision / Serial)0x1600~0x17FFRPDO 映射0x1800~0x1BFFTPDO 通讯参数0x1A00~0x1DFFTPDO 映射
EDS 文件
Electronic Data Sheet (EDS) 是文本格式, 描述节点的对象字典。Darra 从 EDS 导入节点:
[FileInfo]
FileName=Servo_XYZ.eds
Description=XYZ Servo Drive
[DeviceInfo]
VendorName=XYZ Industrial
ProductName=Model 100
GranularityOfFractionalPart=0
[1000]
ParameterName=Device Type
ObjectType=0x7
DataType=0x0007
AccessType=ro
DefaultValue=0x00020192
[6040]
ParameterName=Controlword
ObjectType=0x7
DataType=0x0006
AccessType=rww
PDOMapping=1
导入后 IDE 自动:
- 生成 PDO 映射模板
- 在变量表建立 PDO → PLC 地址映射
- 把厂商参数暴露为 SDO 读写界面
PDO 类型
主站 节点
│ RPDO │
├──────────────→ │ (主站发给节点)
│ │
│ TPDO │
│ ←──────────── │ (节点发给主站)
PDO 触发方式 (由 0x1800.02 Transmission Type 决定):
| 代码 | 含义 |
|---|---|
| 0 | 同步 (SYNC), 每次 SYNC 后更新 |
| 1~240 | 每 N 次 SYNC 后传 |
| 252 | 同步采样, 异步传 |
| 253 | 远程请求 (RTR) 后传 |
| 254 | 厂商定义事件 |
| 255 | 异步事件触发 (如值变化) |
CiA 402 伺服
CiA 402 定义了伺服驱动器的标准对象和状态机:
| 对象 | 索引 | 大小 | 说明 |
|---|---|---|---|
| Controlword | 0x6040 | UINT16 | 控制命令 |
| Statusword | 0x6041 | UINT16 | 当前状态 |
| Mode of Operation | 0x6060 | INT8 | 运行模式选择 |
| Mode of Operation Display | 0x6061 | INT8 | 实际运行模式 |
| Target Position | 0x607A | INT32 | CSP 模式目标位置 |
| Target Velocity | 0x60FF | INT32 | CSV 模式目标速度 |
| Target Torque | 0x6071 | INT16 | CST 模式目标扭矩 |
| Position Actual Value | 0x6064 | INT32 | 反馈位置 |
| Velocity Actual Value | 0x606C | INT32 | 反馈速度 |
| Torque Actual Value | 0x6077 | INT16 | 反馈扭矩 |
| Profile Velocity | 0x6081 | UINT32 | PP 模式速度 |
| Profile Acceleration | 0x6083 | UINT32 | 加速度 |
典型 PDO 映射 (CiA 402):
- RPDO1: Controlword (0x6040) + Mode of Operation (0x6060)
- RPDO2: Target Position (0x607A)
- TPDO1: Statusword (0x6041) + Mode of Operation Display (0x6061)
- TPDO2: Position Actual Value (0x6064)
SDO 上传 / 下载
SDO 有两种传输模式:
快速传输 (Expedited)
≤ 4 字节数据, 一次请求响应完成:
请求: [22 40 60 00 06 00 00 00] (Write Index 6040, SubIdx 0, Value 0x0006)
响应: [60 40 60 00 00 00 00 00] (OK)
分段传输 (Segmented)
4 字节, 多帧完成:
- Initiate: 协商长度
- Segment: 每次传 7 字节, 最多 127 段
- End: 最后一段
块传输 (Block)
CiA 301 v4 引入, 速度比分段快。不是所有从站都支持。
NMT 命令
| 命令码 | 含义 |
|---|---|
| 0x01 | 进入 Operational |
| 0x02 | 进入 Stopped |
| 0x80 | 进入 Pre-Operational |
| 0x81 | Reset Node (复位整个节点) |
| 0x82 | Reset Communication (仅复位通讯) |
NMT 帧格式: COB-ID=0x000, 数据=[命令, 节点号], 节点号=0 表示广播。
心跳 vs 节点保护
两种检测节点在线状态的方式:
| 机制 | 推荐度 | 说明 |
|---|---|---|
| Heartbeat | 推荐 | 节点主动发心跳, 主站监听 |
| Node Guarding | 过时 | 主站询问, 节点回应; 增加总线负载 |
心跳配置:
- 节点
0x1017Producer Heartbeat Time: 例如 500ms - 主站侧
0x1016Consumer Heartbeat Time: 略大于 Producer, 如 1500ms
主站超过 Consumer Time 没收到心跳 → 视为掉线 → 触发报警。
紧急报文 (EMCY)
节点发生错误时主动发 EMCY:
COB-ID: 0x081 + NodeID
数据: [错误码低, 错误码高, 错误寄存器, 厂商特定数据 (5B)]
常见错误码:
- 0x0000 Error Reset (恢复)
- 0x1000 Generic Error
- 0x2000~0x2FFF Current 电流错
- 0x3000~0x3FFF Voltage 电压错
- 0x4000~0x4FFF Temperature 温度错
- 0x5000~0x5FFF Hardware 硬件
- 0x6000~0x6FFF Software 软件
- 0x7000~0x7FFF Additional Modules 附加模块
- 0x8000~0x8FFF Monitoring 监控 (常指通讯)
- 0x9000~0x9FFF External Error 外部
- 0xFF00~0xFFFF Device Specific 设备特定
同步时钟
CANopen 支持时间戳对象 (0x1012), 主站广播 TIME 消息给所有节点:
canopen.BroadcastTime(DateTime.UtcNow);
精度约 ±1ms, 适合事件时标对齐。
LSS (Layer Setting Services)
用于在未知节点号的情况下配置节点 (例如出厂初次配置):
- 把所有节点置于 LSS 等待模式
- 用 Vendor/Product/Rev/Serial 唯一标识某节点
- 设置该节点的 Node ID 和波特率
- 节点生效后退出 LSS
诊断
IDE 提供 CAN 总线监视窗:
- 实时显示所有 CAN 帧 (时间戳 + COB-ID + 数据)
- 按节点 / 对象类型过滤
- CAN 错误计数 (bus off, error passive, warning)
- 总线负载率 (%)
排错
| 症状 | 处理 |
|---|---|
| 节点不上线 | 波特率错 / 终端电阻缺 / 供电不足 |
| 通讯间歇性错 | 布线问题 / 屏蔽接地 |
| Bus Off | 总线上有短路或大量错误帧 |
| SDO 超时 | 节点忙, 加大超时; 避免 Bootup 期间访问 |
| PDO 不更新 | 节点不在 Operational 状态 |
| 总线负载 > 70% | 减少 PDO 数量 / 增大 SYNC 周期 |