CANOpen 概览 -- 协议栈层次、通信对象与对象字典
1. CANOpen 是什么
CANOpen 是基于 CAN 总线的高层应用层协议,由 CiA(CAN in Automation)国际用户组织定义(标准文档 CiA 301)。它定义了一套完整的通信规则,使得不同厂商的设备可以在同一 CAN 网络上互操作。
1.1 为什么需要 CANOpen?
纯 CAN 只提供"传输管道"——它定义了如何发送 8 字节的帧。但它不规定:
- 帧的含义是什么?
- 如何配置设备参数?
- 如何管理网络中的节点状态?
- 如何保证实时性?
CANOpen 回答了这些问题 —— 它在 CAN 帧之上定义了一套语义层协议。
1.2 开源实现
| 项目 | 语言 | 特点 | 许可证 |
|---|---|---|---|
| CANopenNode | C | 最成熟、最活跃、CiA 402 支持 | Apache 2.0 |
| CanFestival | C | 老牌项目、轻量 | LGPL |
| libcanopen | C | 现代设计、Linux 专用 | MIT |
本系列教程基于 CANopenNode 进行集成与学习。
2. CANOpen 协议栈分层
┌──────────────────────────────────────────┐
│ 应用层 (Application) │ ← 用户业务逻辑
├──────────────────────────────────────────┤
│ CANOpen 应用层 (CiA 301) │ ← 本系列核心
│ ┌────────────────────────────────────┐ │
│ │ 通信对象 (NMT/SDO/PDO/EMCY/SYNC) │ │
│ │ 对象字典 (Object Dictionary) │ │
│ │ 设备行规 (Profiles: CiA 401/402) │ │
│ └────────────────────────────────────┘ │
├──────────────────────────────────────────┤
│ CAN 2.0A/B (数据链路层) │ ← 模块 1 前半部分
│ (帧格式、仲裁、位填充、错误检测) │
├──────────────────────────────────────────┤
│ 物理层 (ISO 11898) │ ← 模块 1 前半部分
│ (差分信号、终端电阻、拓扑) │
└──────────────────────────────────────────┘CANOpen 不修改 CAN 的物理层和数据链路层 —— 它完全运行在应用层。
3. 核心通信对象
CANOpen 定义了 6 种核心通信对象:
| 对象 | 全称 | 用途 | 通信模式 |
|---|---|---|---|
| NMT | Network Management | 节点状态控制(启动/停止/复位) | Client/Server |
| SDO | Service Data Object | 配置参数、读写对象字典条目 | Client/Server(请求/响应) |
| PDO | Process Data Object | 实时数据传输(传感器值、控制命令) | Producer/Consumer(广播) |
| EMCY | Emergency | 设备故障紧急通知 | Producer/Consumer |
| SYNC | Synchronization | 网络时间同步 | Producer/Consumer |
| Heartbeat | Heartbeat | 节点存活检测 | Producer/Consumer |
3.1 NMT(Network Management)
控制节点的状态转换:
Reset Application
|
v
+--------+ Initialization +-------------+
| Stopped| <--------------------- | |
+--------+ | |
^ | |
| NMT Stop v |
| +-------------+ |
| NMT Start | Pre-Operational| |
+---------------------- | | |
+-------------+ |
| |
NMT Enter Operational | |
v |
+-------------+ |
| Operational | |
+-------------+ || 状态 | 说明 | PDO 行为 |
|---|---|---|
| Initialization | 上电自检,加载对象字典 | 不发送任何报文 |
| Pre-Operational | 可配置,但不发送 PDO | SDO/NMT/Heartbeat 可用 |
| Operational | 正常工作状态 | 所有报文可用 |
| Stopped | 节点被停止 | 仅响应 NMT |
3.2 SDO(Service Data Object)
用于非实时的参数配置和对象字典访问:
主站 (Client) 从站 (Server)
│ │
│── SDO Upload Request (0x600+N)─→│ 请求读取对象字典条目
│←── SDO Upload Response (0x580+N)─│ 返回数据
│ │
│── SDO Download Request (0x600+N)─→│ 请求写入对象字典条目
│←── SDO Download Response (0x580+N)─│ 确认写入- Expedited 模式:数据 <= 4 字节,1 个请求 + 1 个响应
- Segmented 模式:数据 > 4 字节,需要多个分段传输
3.3 PDO(Process Data Object)
用于实时数据传输,无需请求/响应:
| 类型 | 方向 | 说明 |
|---|---|---|
| TPDO | 节点 → 网络 | 节点主动发送(如传感器数据) |
| RPDO | 网络 → 节点 | 节点接收(如控制命令) |
PDO 是广播式的,发送后无需确认。多个消费者可以同时接收同一 PDO。
3.4 EMCY(Emergency Message)
设备发生故障时立即发送,具有高优先级(COB-ID 0x080+N):
Byte 0-1: Error Code (如 0x2310 = 电流过大)
Byte 2: Error Register (全局错误状态)
Byte 3-7: 厂商特定信息3.5 SYNC
周期性发送出的同步报文,用于触发同步 PDO:
- COB-ID:0x080(默认)
- 作用:确保多个节点在同一时刻发送/接收 PDO,实现运动控制的同步
3.6 Heartbeat
节点周期性报告自身状态:
数据 Byte 0:
0x00 = Boot-up(节点启动完成)
0x04 = Stopped
0x05 = Operational
0x7F = Pre-Operational主站监控 Heartbeat,如果超时未收到,判定节点故障。
4. COB-ID 详解
COB-ID(Communication Object Identifier)= CAN ID 在 CANOpen 中的称呼。
CANOpen 预定义了默认的 COB-ID 分配表:
| 功能 | COB-ID 计算公式 | 默认值(Node ID = N) | 优先级 |
|---|---|---|---|
| NMT | 0x000 | 0x000 | 最高 |
| EMCY | 0x080 + N | 0x080 + N | 高 |
| SYNC | 0x080 | 0x080 | 高 |
| PDO1 TX | 0x180 + N | 0x180 + N | 中 |
| PDO1 RX | 0x200 + N | 0x200 + N | 中 |
| PDO2 TX | 0x280 + N | 0x280 + N | 中 |
| PDO2 RX | 0x300 + N | 0x300 + N | 中 |
| SDO TX | 0x580 + N | 0x580 + N | 低 |
| SDO RX | 0x600 + N | 0x600 + N | 低 |
| Heartbeat | 0x700 + N | 0x700 + N | 低 |
为什么 NMT 的优先级最高? 因为 NMT 使用 COB-ID 0x000,这是最小的 CAN ID,在仲裁中始终获胜。这确保了主站可以随时控制任何节点,即使总线很繁忙。
5. 对象字典(Object Dictionary)简介
对象字典是 CANOpen 设备的参数数据库,是一个 16-bit 索引 + 8-bit 子索引的二维表:
5.1 索引分区
| 索引范围 | 名称 | 用途 |
|---|---|---|
0x0000-0x0FFF | 类型定义区 | 数据类型定义 |
0x1000-0x1FFF | 通信参数区 | CiA 301 定义的通信配置 |
0x2000-0x5FFF | 制造商特定区 | 厂商自定义参数 |
0x6000-0x9FFF | 设备行规区 | CiA 401/402/417 等标准定义 |
5.2 核心对象(0x1000-0x1018)
| 索引 | 名称 | 类型 | 说明 |
|---|---|---|---|
0x1000 | Device Type | UINT32 | 设备类型标识 |
0x1001 | Error Register | UINT8 | 全局错误寄存器 |
0x1005 | COB-ID SYNC | UINT32 | SYNC 报文 COB-ID |
0x1006 | Communication Cycle Period | UINT32 | SYNC 周期(微秒) |
0x1008 | Manufacturer Device Name | STRING | 设备名称 |
0x1014 | COB-ID EMCY | UINT32 | EMCY 报文 COB-ID |
0x1017 | Producer Heartbeat Time | UINT16 | Heartbeat 生产者周期(ms) |
0x1018 | Identity Object | RECORD | 厂商 ID、产品代码、版本号、序列号 |
5.3 子索引示例
以 0x1018(Identity Object)为例:
0x1018:
Sub 0: 4 (子索引数量 = 4)
Sub 1: Vendor ID (厂商 ID)
Sub 2: Product Code (产品代码)
Sub 3: Revision Number (版本号)
Sub 4: Serial Number (序列号)通过 SDO 读取 0x1018 的各个子索引,可以获取设备的身份信息。这正是 CANOpen LSS(Layer Setting Services)识别节点的方式。
6. 完整通信示例
以下是一个典型的 CANOpen 网络启动流程:
时间 →
[主站] 上电
│
├── 监控 0x700+ 地址(Heartbeat)
│
[从站 Node 1] 上电
│
├── 发送 Boot-up: 0x701 [0x00] (Heartbeat, 状态=Boot-up)
│
[主站] 收到 Boot-up
│
├── 通过 SDO 配置从站参数:
│ 0x601#4000100000000000 (SDO 读取 0x1000 设备类型)
│ 0x601#2317100001000000 (SDO 写入 0x1017 心跳时间)
│ 0x601#2B40180002000000 (SDO 写入 PDO 映射)
│
├── 发送 NMT Start: 0x000 [0x01 0x01] (启动 Node 1)
│
[从站 Node 1] 进入 Operational
│
├── 开始周期性发送 TPDO: 0x181 [8 bytes 数据]
│
[主站] 接收 PDO,处理数据
│
├── 发送 RPDO: 0x201 [8 bytes 控制命令]
│
[从站 Node 1] 执行控制命令这个流程包含了 NMT、SDO、PDO、Heartbeat 四种通信对象的协同工作。
7. 后续模块预告
| 模块 | 主题 | 核心内容 |
|---|---|---|
| 模块 2 | 对象字典与 SDO 通信 | EDS 文件、SDO Expedited/Segmented 完整流程 |
| 模块 3 | PDO 通信与实时数据 | PDO 映射配置、触发方式、同步机制 |
| 模块 4 | NMT 状态机与网络管理 | 完整状态机实现、LSS 服务 |
| 模块 5 | 雅特力 MCU 硬件驱动适配 | CAN 控制器配置、CANopenNode 移植 |
| 模块 6 | CANopenNode 协议栈集成 | 主站/从站完整实现 |
| 模块 7 | CiA 402 伺服驱动行规 | 状态机、CSP/CSV/CST 模式 |
| 模块 8 | CiA 417 机器人关节行规 | 多轴同步、关节控制 |
| 模块 9 | 小型机械臂 CANOpen 控制系统 | 完整系统架构设计 |
8. 关键知识点总结
| 知识点 | 要点 |
|---|---|
| CANOpen 定位 | 运行在 CAN 之上的应用层协议 |
| 6 种通信对象 | NMT、SDO、PDO、EMCY、SYNC、Heartbeat |
| COB-ID | CAN ID 在 CANOpen 中的称呼,预定义分配表 |
| NMT 优先级最高 | COB-ID 0x000,仲裁中始终获胜 |
| 对象字典 | 16-bit 索引 + 8-bit 子索引的参数数据库 |
| SDO vs PDO | SDO = 非实时配置,PDO = 实时数据 |
★ Insight ─────────────────────────────────────
- CANOpen 的"生产者/消费者"模型与传统"主从"模型的根本区别:PDO 是广播式的,任何节点都可以是生产者或消费者,这比主从模型更灵活。
- COB-ID 预定义分配表的设计精妙之处:它不仅分配了 ID,还通过 ID 的数值大小自然实现了优先级分层 —— NMT(管理)> EMCY(紧急)> PDO(实时)> SDO(配置)。
- 对象字典是 CANOpen 的灵魂 —— 所有配置、状态、参数都在这个统一的二维表中,SDO 是访问这张表的"查询语言"。理解了对象字典,就理解了 CANOpen 的一半。
─────────────────────────────────────────────────
上一步
← 05-send-receive.md —— 发送与接收实战
→ 07-practice-project.md —— 实践项目
支付宝
微信