CANOpen 概览 -- 协议栈层次、通信对象与对象字典

1. CANOpen 是什么

CANOpen 是基于 CAN 总线的高层应用层协议,由 CiA(CAN in Automation)国际用户组织定义(标准文档 CiA 301)。它定义了一套完整的通信规则,使得不同厂商的设备可以在同一 CAN 网络上互操作。

1.1 为什么需要 CANOpen?

纯 CAN 只提供"传输管道"——它定义了如何发送 8 字节的帧。但它不规定:

  • 帧的含义是什么?
  • 如何配置设备参数?
  • 如何管理网络中的节点状态?
  • 如何保证实时性?

CANOpen 回答了这些问题 —— 它在 CAN 帧之上定义了一套语义层协议。

1.2 开源实现

项目语言特点许可证
CANopenNodeC最成熟、最活跃、CiA 402 支持Apache 2.0
CanFestivalC老牌项目、轻量LGPL
libcanopenC现代设计、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 种核心通信对象:

对象全称用途通信模式
NMTNetwork Management节点状态控制(启动/停止/复位)Client/Server
SDOService Data Object配置参数、读写对象字典条目Client/Server(请求/响应)
PDOProcess Data Object实时数据传输(传感器值、控制命令)Producer/Consumer(广播)
EMCYEmergency设备故障紧急通知Producer/Consumer
SYNCSynchronization网络时间同步Producer/Consumer
HeartbeatHeartbeat节点存活检测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可配置,但不发送 PDOSDO/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)优先级
NMT0x0000x000最高
EMCY0x080 + N0x080 + N高
SYNC0x0800x080高
PDO1 TX0x180 + N0x180 + N中
PDO1 RX0x200 + N0x200 + N中
PDO2 TX0x280 + N0x280 + N中
PDO2 RX0x300 + N0x300 + N中
SDO TX0x580 + N0x580 + N低
SDO RX0x600 + N0x600 + N低
Heartbeat0x700 + N0x700 + 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)

索引名称类型说明
0x1000Device TypeUINT32设备类型标识
0x1001Error RegisterUINT8全局错误寄存器
0x1005COB-ID SYNCUINT32SYNC 报文 COB-ID
0x1006Communication Cycle PeriodUINT32SYNC 周期(微秒)
0x1008Manufacturer Device NameSTRING设备名称
0x1014COB-ID EMCYUINT32EMCY 报文 COB-ID
0x1017Producer Heartbeat TimeUINT16Heartbeat 生产者周期(ms)
0x1018Identity ObjectRECORD厂商 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 完整流程
模块 3PDO 通信与实时数据PDO 映射配置、触发方式、同步机制
模块 4NMT 状态机与网络管理完整状态机实现、LSS 服务
模块 5雅特力 MCU 硬件驱动适配CAN 控制器配置、CANopenNode 移植
模块 6CANopenNode 协议栈集成主站/从站完整实现
模块 7CiA 402 伺服驱动行规状态机、CSP/CSV/CST 模式
模块 8CiA 417 机器人关节行规多轴同步、关节控制
模块 9小型机械臂 CANOpen 控制系统完整系统架构设计

8. 关键知识点总结

知识点要点
CANOpen 定位运行在 CAN 之上的应用层协议
6 种通信对象NMT、SDO、PDO、EMCY、SYNC、Heartbeat
COB-IDCAN ID 在 CANOpen 中的称呼,预定义分配表
NMT 优先级最高COB-ID 0x000,仲裁中始终获胜
对象字典16-bit 索引 + 8-bit 子索引的参数数据库
SDO vs PDOSDO = 非实时配置,PDO = 实时数据

★ Insight ─────────────────────────────────────

  • CANOpen 的"生产者/消费者"模型与传统"主从"模型的根本区别:PDO 是广播式的,任何节点都可以是生产者或消费者,这比主从模型更灵活。
  • COB-ID 预定义分配表的设计精妙之处:它不仅分配了 ID,还通过 ID 的数值大小自然实现了优先级分层 —— NMT(管理)> EMCY(紧急)> PDO(实时)> SDO(配置)。
  • 对象字典是 CANOpen 的灵魂 —— 所有配置、状态、参数都在这个统一的二维表中,SDO 是访问这张表的"查询语言"。理解了对象字典,就理解了 CANOpen 的一半。 ─────────────────────────────────────────────────

上一步

← 05-send-receive.md —— 发送与接收实战

→ 07-practice-project.md —— 实践项目

如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
Cygnus Yang 支付宝支付宝
Cygnus Yang 微信微信