目录
- CANopen通信协议完整指南
- 文档版本
- 目录
- 一、CANopen协议概述
- [1.1 什么是CANopen](#1.1 什么是CANopen)
- [1.2 协议分层](#1.2 协议分层)
- [1.3 协议特点](#1.3 协议特点)
- 二、CAN总线基础
- [2.1 物理层特性](#2.1 物理层特性)
- [2.1.1 差分信号](#2.1.1 差分信号)
- [2.1.2 终端电阻](#2.1.2 终端电阻)
- [2.2 总线仲裁机制](#2.2 总线仲裁机制)
- [2.3 CAN的广播特性](#2.3 CAN的广播特性)
- [2.1 物理层特性](#2.1 物理层特性)
- 三、CAN帧格式详解
- [3.1 帧类型概览](#3.1 帧类型概览)
- [3.2 标准数据帧结构](#3.2 标准数据帧结构)
- [3.3 各段详细说明](#3.3 各段详细说明)
- [3.3.1 仲裁段 (Arbitration Field)](#3.3.1 仲裁段 (Arbitration Field))
- [3.3.2 控制段 (Control Field)](#3.3.2 控制段 (Control Field))
- [3.3.3 数据段 (Data Field)](#3.3.3 数据段 (Data Field))
- [3.4 远程帧详解](#3.4 远程帧详解)
- [3.4.1 什么是远程帧](#3.4.1 什么是远程帧)
- [3.4.2 数据帧 vs 远程帧结构](#3.4.2 数据帧 vs 远程帧结构)
- [3.4.3 远程帧仲裁机制](#3.4.3 远程帧仲裁机制)
- [3.4.4 远程帧的DLC字段](#3.4.4 远程帧的DLC字段)
- [3.4.5 远程帧完整实例](#3.4.5 远程帧完整实例)
- [3.4.6 CANopen中远程帧的应用](#3.4.6 CANopen中远程帧的应用)
- [3.5 位填充规则](#3.5 位填充规则)
- [3.5.1 位填充原理](#3.5.1 位填充原理)
- [3.5.2 填充示例](#3.5.2 填充示例)
- [3.6 错误帧](#3.6 错误帧)
- [3.7 完整帧实例](#3.7 完整帧实例)
- [实例1: 发送8字节数据](#实例1: 发送8字节数据)
- [实例2: 远程帧请求](#实例2: 远程帧请求)
- 四、CAN寻址与过滤机制
- [4.1 广播通信原理](#4.1 广播通信原理)
- [4.2 硬件过滤器](#4.2 硬件过滤器)
- [4.3 过滤器配置示例](#4.3 过滤器配置示例)
- 五、CANopen帧格式
- [5.1 COB-ID结构](#5.1 COB-ID结构)
- [5.2 预定义连接集](#5.2 预定义连接集)
- [5.3 节点寻址机制](#5.3 节点寻址机制)
- 六、对象字典 (Object Dictionary)
- [6.1 初学者导读:对象字典是什么](#6.1 初学者导读:对象字典是什么)
- [6.2 索引区域划分(简明)](#6.2 索引区域划分(简明))
- [示例 A:读取
0x1000(Device Type,通信子协议区)](#示例 A:读取 0x1000(Device Type,通信子协议区)) - [示例 B:查看/映射 TPDO(0x1800 与 0x1A00)](#示例 B:查看/映射 TPDO(0x1800 与 0x1A00))
- [示例 C:制造商特定区写入(0x2000)](#示例 C:制造商特定区写入(0x2000))
- [示例 A:读取
- [6.3 对象类型(VAR / ARRAY / RECORD)](#6.3 对象类型(VAR / ARRAY / RECORD))
- [6.4 对象条目关键属性(每个对象都会包含)](#6.4 对象条目关键属性(每个对象都会包含))
- [6.5 设备示例:温度传感器 + LED 控制(完整 OD 演示)](#6.5 设备示例:温度传感器 + LED 控制(完整 OD 演示))
- [6.5 初学者常见操作示例(速查)](#6.5 初学者常见操作示例(速查))
- [6.6 常用对象速览表(初学者)](#6.6 常用对象速览表(初学者))
- 七、CANopen通信对象详解
- [7.1 NMT网络管理](#7.1 NMT网络管理)
- [7.1.1 状态机](#7.1.1 状态机)
- [7.1.2 NMT命令帧格式](#7.1.2 NMT命令帧格式)
- [7.1.3 实例:启动所有节点](#7.1.3 实例:启动所有节点)
- [7.1.4 实例:复位节点5](#7.1.4 实例:复位节点5)
- [7.2 Heartbeat心跳报文](#7.2 Heartbeat心跳报文)
- [7.2.1 心跳机制](#7.2.1 心跳机制)
- [7.2.2 心跳实例:节点0x0A正常运行](#7.2.2 心跳实例:节点0x0A正常运行)
- [7.2.3 配置心跳周期](#7.2.3 配置心跳周期)
- [7.3 SYNC同步对象](#7.3 SYNC同步对象)
- [7.3.1 SYNC帧格式](#7.3.1 SYNC帧格式)
- [7.3.2 同步窗口](#7.3.2 同步窗口)
- [7.4 EMCY紧急报文](#7.4 EMCY紧急报文)
- [7.4.1 EMCY帧格式](#7.4.1 EMCY帧格式)
- [7.4.2 标准错误代码](#7.4.2 标准错误代码)
- [7.4.3 EMCY实例](#7.4.3 EMCY实例)
- [7.5 SDO服务数据对象](#7.5 SDO服务数据对象)
- [7.5.1 基本概念](#7.5.1 基本概念)
- [7.5.2 SDO帧格式](#7.5.2 SDO帧格式)
- [7.5.3 CCS/SCS命令字](#7.5.3 CCS/SCS命令字)
- [7.5.4 快速SDO实例](#7.5.4 快速SDO实例)
- [7.5.5 分段SDO实例](#7.5.5 分段SDO实例)
- [7.6 PDO过程数据对象](#7.6 PDO过程数据对象)
- [7.6.1 PDO特点](#7.6.1 PDO特点)
- [7.6.2 PDO类型](#7.6.2 PDO类型)
- [7.6.3 传输类型](#7.6.3 传输类型)
- [7.6.4 PDO配置流程](#7.6.4 PDO配置流程)
- [7.6.5 TPDO完整实例](#7.6.5 TPDO完整实例)
- [7.6.6 RPDO完整实例](#7.6.6 RPDO完整实例)
- [7.6.7 同步PDO实例](#7.6.7 同步PDO实例)
- [7.1 NMT网络管理](#7.1 NMT网络管理)
- 八、设备子协议
- [8.1 DS402 驱动与运动控制](#8.1 DS402 驱动与运动控制)
- [8.2 DS401 I/O模块](#8.2 DS401 I/O模块)
- 九、开发实践与典型设备示例
- [9.1 常用工具与调试技巧](#9.1 常用工具与调试技巧)
- [9.2 设备示例A:maxon EPOS4伺服驱动器(DS402)](#9.2 设备示例A:maxon EPOS4伺服驱动器(DS402))
- [9.3 设备示例B:分布式数字I/O模块(DS401)](#9.3 设备示例B:分布式数字I/O模块(DS401))
- [9.4 关键对象索引速查表](#9.4 关键对象索引速查表)
- [9.5 常见问题校验点](#9.5 常见问题校验点)
- [9.6 总结](#9.6 总结)
一、CANopen协议概述
1.1 什么是CANopen
CANopen是基于CAN(Controller Area Network)总线的高层应用协议,由CiA(CAN in Automation)组织制定。它不仅仅定义了通信方式,还定义了设备的行为和状态机。
- 核心规范: CIA 301(应用层和通信子协议)
- 起源: 德国BOSCH公司开发CAN物理层与数据链路层,后由CiA标准化CANopen
- 应用领域: 工业自动化(伺服驱动、IO模块)、医疗设备、轨道交通、新能源
1.2 协议分层
CANopen遵循OSI模型,主要涉及以下层级:
┌─────────────────────────────────────┐
│ 应用层 (Application Layer) │ ← CANopen定义 (CiA 301)
│ - 对象字典 (Object Dictionary) │
│ - 通信对象 (SDO, PDO, NMT等) │
│ - 设备子协议 (DS402, DS401等) │
├─────────────────────────────────────┤
│ 数据链路层 (Data Link Layer) │ ← CAN 2.0A/B定义
│ - 逻辑链路控制 (LLC) │
│ - 介质访问控制 (MAC) │
├─────────────────────────────────────┤
│ 物理层 (Physical Layer) │ ← ISO 11898定义
│ - 物理信号 (差分电平) │
│ - 物理介质 (双绞线) │
└─────────────────────────────────────┘
1.3 协议特点
| 特性 | 说明 | 优势 |
|---|---|---|
| 标准化 | 统一的对象字典接口 | 不同厂商设备可互换,兼容性强 |
| 实时性 | PDO支持同步/异步、事件驱动 | 高优先级过程数据延迟 < 1ms |
| 可靠性 | 结合CAN的物理优势与协议层保护 | 极低的错误率,抗干扰能力强 |
| 灵活性 | 对象字典可动态配置 | 适应各种应用场景 |
| 模块化 | 支持通过EDS文件描述设备 | 易于系统集成和配置工具使用 |
二、CAN总线基础
2.1 物理层特性
2.1.1 差分信号
CAN使用CAN_H 和CAN_L两条双绞线构成差分对,有效抑制共模干扰。
- 显性电平 (Dominant, Logic 0): 电压差 Vdiff ≈ 2.0V (CAN_H ≈ 3.5V, CAN_L ≈ 1.5V)
- 隐性电平 (Recessive, Logic 1): 电压差 Vdiff ≈ 0V (CAN_H ≈ 2.5V, CAN_L ≈ 2.5V)
2.1.2 终端电阻
- 阻值: 120Ω
- 位置: 总线两端的最远端节点
- 作用: 消除信号反射,确保信号完整性
2.2 总线仲裁机制
CAN总线采用非破坏性逐位仲裁(Non-destructive Bitwise Arbitration)机制。
- 线与 (Wired-AND): 总线上只要有一个节点发送显性(0),总线即为显性(0)。只有所有节点都发送隐性(1),总线才为隐性(1)。
- 仲裁过程 :
- 所有节点同时监听总线。
- 当节点发送隐性位(1)但检测到显性位(0)时,意味着有更高优先级的节点在发送。
- 该节点立即停止发送(仲裁失败),转为接收模式。
- 优先级 : ID值越小,优先级越高 (因为0是显性电平)。
2.3 CAN的广播特性
CAN采用生产者-消费者模型,报文不包含目标地址,而是包含内容标识符(ID)。
- 广播传输: 所有节点都能收到总线上的所有报文。
- 硬件过滤: 每个节点通过硬件验收滤波器(Acceptance Filter)决定是否处理该报文,从而实现点对点、多播或广播通信。
三、CAN帧格式详解
3.1 帧类型概览
CAN 2.0B标准定义了以下几种帧,CANopen主要使用数帧 和远程帧。
| 帧类型 | 作用 |
|---|---|
| 数据帧 | 携带数据(最常用) |
| 远程帧 | 请求具有特定ID的数据帧 |
| 错误帧 | 报告检测到的错误 |
| 过载帧 | 请求延迟发送下一帧 |
3.2 标准数据帧结构
CANopen通常使用11位标识符的标准帧格式。
位图结构:
┌───┬──────────────┬──────────┬───────────┬──────────┬────┬───┐
│SOF│ 仲裁段 │ 控制段 │ 数据段 │ CRC段 │ACK │EOF│
│ 1 │ 12 │ 6 │ 0-64 │ 16 │ 2 │ 7 │
└───┴──────────────┴──────────┴───────────┴──────────┴────┴───┘
3.3 各段详细说明
3.3.1 仲裁段 (Arbitration Field)
包含11位ID和RTR位,决定报文优先级。
标准格式 (11位ID):
┌─────────────────────────────┬─────┐
│ Identifier (11位) │ RTR │
│ ID10 ID9...ID1 ID0 │(1位)│
└─────────────────────────────┴─────┘
- Identifier (11位): ID10...ID0,MSB先发送。
- RTR (Remote Transmission Request) :
- RTR=0: 数据帧 (显性,优先级高)
- RTR=1: 远程帧 (隐性,优先级低)
仲裁实例:
【场景】3个节点同时发送
节点A: ID = 0x123 (数据帧)
节点B: ID = 0x125 (数据帧)
节点C: ID = 0x200 (数据帧)
二进制对比:
0x123 = 0 0 0 1 0 0 1 0 0 1 1
0x125 = 0 0 0 1 0 0 1 0 1 0 1
0x200 = 0 0 1 0 0 0 0 0 0 0 0
│ │ │ │ │ │ │ │ │ │ │
ID10────────────────ID0
仲裁过程:
┌────┬────┬────┬────┬────┬────┬──────────────────────────┐
│时间│位 │节点A│节点B│节点C│总线│ 结果 │
├────┼────┼────┼────┼────┼────┼──────────────────────────┤
│ t0 │ID10│ 0 │ 0 │ 0 │ 0 │ 继续 │
│ t1 │ID9 │ 0 │ 0 │ 0 │ 0 │ 继续 │
│ t2 │ID8 │ 0 │ 0 │ 1 │ 0 │ 节点C失败(检测到0≠1) │
│ t3 │ID7 │ 1 │ 1 │ - │ 1 │ 节点C停止发送 │
│ t4 │ID6 │ 0 │ 0 │ - │ 0 │ A、B继续 │
│ t5 │ID5 │ 0 │ 0 │ - │ 0 │ 继续 │
│ t6 │ID4 │ 1 │ 1 │ - │ 1 │ 继续 │
│ t7 │ID3 │ 0 │ 0 │ - │ 0 │ 继续 │
│ t8 │ID2 │ 0 │ 1 │ - │ 0 │ 节点B失败(检测到0≠1) │
│ t9 │ID1 │ 1 │ - │ - │ 1 │ 节点B停止发送 │
│t10 │ID0 │ 1 │ - │ - │ 1 │ 节点A获胜 │
└────┴────┴────┴────┴────┴────┴──────────────────────────┘
最终结果:
✓ 节点A获胜 (ID=0x123) - 最高优先级
✗ 节点B失败 (ID=0x125) - ID2位仲裁失败
✗ 节点C失败 (ID=0x200) - ID8位仲裁失败
节点B和C自动转为接收模式,接收节点A的数据
3.3.2 控制段 (Control Field)
包含IDE、保留位和DLC。
- IDE (Identifier Extension): 0表示标准帧(11位ID)。
- r0: 保留位,发送显性(0)。
- DLC (Data Length Code): 4位,表示数据段字节数 (0-8)。
3.3.3 数据段 (Data Field)
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ D0 │ D1 │ D2 │ D3 │ D4 │ D5 │ D6 │ D7 │
│(8位) │(8位) │(8位) │(8位) │(8位) │(8位) │(8位) │(8位) │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
↑
先发送
包含0~8个字节的实际有效数据。
- 发送顺序: 字节顺序 D0 → D1 → ... → D7;每个字节内MSB先发送。
- 字节序 : CANopen采用小端模式 (Little Endian)。即低位数据存在低索引字节(D0),高位数据存在高索引(D7)。
小端序详细示例:
【示例1】发送16位整数 0x1234
内存布局(小端):
地址 值
0x00 0x34 ← 低字节
0x01 0x12 ← 高字节
CAN数据段:
D0 D1 D2 D3 D4 D5 D6 D7
0x34 0x12 00 00 00 00 00 00
↑ ↑
低字节 高字节
【示例2】发送32位整数 0x12345678
内存布局(小端):
地址 值
0x00 0x78 ← 最低字节
0x01 0x56
0x02 0x34
0x03 0x12 ← 最高字节
CAN数据段:
D0 D1 D2 D3 D4 D5 D6 D7
0x78 0x56 0x34 0x12 00 00 00 00
【示例3】混合数据类型
结构体:
struct {
uint8_t cmd; // 1字节命令
uint16_t value; // 2字节值 = 0x1234
uint32_t time; // 4字节时间戳 = 0x56789ABC
} data;
CAN数据段:
D0 D1 D2 D3 D4 D5 D6 D7
cmd 0x34 0x12 0xBC 0x9A 0x78 0x56 00
│ └value─┘ └──────time─────────┘
└cmd
多字节数据编码表:
| 数据类型 | 大小 | 值示例 | CAN数据段(小端) |
|---|---|---|---|
| BOOLEAN | 1字节 | TRUE(1) | 01 00 00 00 00 00 00 00 |
| UNSIGNED8 | 1字节 | 0xAB | AB 00 00 00 00 00 00 00 |
| INTEGER8 | 1字节 | -5(0xFB) | FB 00 00 00 00 00 00 00 |
| UNSIGNED16 | 2字节 | 0x1234 | 34 12 00 00 00 00 00 00 |
| INTEGER16 | 2字节 | -100(0xFF9C) | 9C FF 00 00 00 00 00 00 |
| UNSIGNED32 | 4字节 | 0x12345678 | 78 56 34 12 00 00 00 00 |
| INTEGER32 | 4字节 | -1000(0xFFFFFC18) | 18 FC FF FF 00 00 00 00 |
3.4 远程帧详解
3.4.1 什么是远程帧
远程帧 (Remote Frame) 是CAN协议中用于请求数据的特殊帧类型。
┌───────────────────────────────────────────────┐
│ 远程帧工作原理 │
├───────────────────────────────────────────────┤
│ │
│ 节点A (请求者) 节点B (提供者) │
│ │ │ │
│ │ 远程帧 (RTR=1) │ │
│ │ ID=0x185, DLC=4 │ │
│ │──────────────────────>│ │
│ │ │ │
│ │ 检测到远程帧 │
│ │ 查找对应数据 │
│ │ │ │
│ │ 数据帧 (RTR=0) │ │
│ │ ID=0x185, Data[4] │ │
│ │<──────────────────────│ │
│ │ │ │
│ 接收数据 │ │
│ │
└───────────────────────────────────────────────┘
3.4.2 数据帧 vs 远程帧结构
数据帧结构 (RTR=0):
┌───┬─────────────┬──────┬────────────┬─────┬────┬───┐
│SOF│ ID + RTR=0 │ CTRL │ DATA(0-8B) │ CRC │ACK │EOF│
└───┴─────────────┴──────┴────────────┴─────┴────┴───┘
↓ RTR=0
数据帧标志
包含数据段
远程帧结构 (RTR=1):
┌───┬─────────────┬──────┬─────┬────┬───┐
│SOF│ ID + RTR=1 │ CTRL │ CRC │ACK │EOF│
└───┴─────────────┴──────┴─────┴────┴───┘
↓ RTR=1 ↑
远程帧标志 无数据段!
对比表:
| 帧段 | 数据帧 | 远程帧 | 说明 |
|---|---|---|---|
| SOF | 1位 | 1位 | 相同 |
| Identifier | 11位 | 11位 | 相同ID |
| RTR | 0(显性) | 1(隐性) | ⚠️ 关键区别 |
| IDE | 0 | 0 | 相同 |
| r0 | 0 | 0 | 相同 |
| DLC | 0-8(实际长度) | 0-8(期望长度) | 含义不同 |
| 数据段 | 0-8字节 | 无! | ⚠️ 关键区别 |
| CRC | 16位 | 16位 | 相同 |
| ACK | 2位 | 2位 | 相同 |
| EOF | 7位 | 7位 | 相同 |
3.4.3 远程帧仲裁机制
重要规则 : 相同ID时,数据帧优先于远程帧。
【场景】节点A和节点B使用相同ID同时发送
节点A: 发送数据帧 (ID=0x185, RTR=0)
节点B: 发送远程帧 (ID=0x185, RTR=1)
仲裁过程:
┌────┬────┬────┬────┬────┬─────────────────────────────────────┐
│时间│位 │节点A│节点B│总线│ 说明 │
├────┼────┼────┼────┼────┼─────────────────────────────────────┤
│ t0 │SOF │ 0 │ 0 │ 0 │ 开始 │
│ t1 │ID10│ 0 │ 0 │ 0 │ 继续 │
│ t2 │ID9 │ 0 │ 0 │ 0 │ 继续 │
│... │... │... │... │... │ ... │
│t11 │ID0 │ 1 │ 1 │ 1 │ ID相同,继续到RTR位 │
│t12 │RTR │ 0 │ 1 │ 0 │ ← 关键!节点B仲裁失败 │
│ │ │显性│隐性│显性│ 数据帧(0)优先于远程帧(1) │
└────┴────┴────┴────┴────┴─────────────────────────────────────┘
节点B的行为:
1. 发送RTR=1(隐性)
2. 同时监听总线,检测到RTR=0(显性)
3. 发现与自己发送的不一致
4. 立即停止发送,转为接收模式
5. 接收节点A的数据帧
结果: 数据帧优先发送完成
3.4.4 远程帧的DLC字段
关键区别 : 远程帧的DLC不表示实际数据,而是期望的数据长度。
┌──────────────────────────────────────┐
│ DLC在远程帧中的特殊含义 │
├──────────────────────────────────────┤
│ │
│ 远程帧: ID=0x185, DLC=0x04 │
│ ↓ │
│ 含义: 请求4字节数据 │
│ ↓ │
│ 期望的应答数据帧: │
│ ID=0x185, DLC=0x04, Data[4] │
│ │
└──────────────────────────────────────┘
3.4.5 远程帧完整实例
场景: 节点0x10请求节点0x05的温度数据
═══════════════════════════════════════════════════════
步骤1: 节点0x10发送远程帧
═══════════════════════════════════════════════════════
CAN报文:
COB-ID: 0x185
RTR: 1
DLC: 2 (期望2字节温度值)
数据段: 无
位流:
SOF: 0
仲裁段: 0001 1000 0101 1
└────0x185────┘ └RTR=1
控制段: 0 0 0010 (IDE=0, r0=0, DLC=2)
[无数据段]
CRC段: [15位CRC] 1
ACK段: 0 1
EOF: 1111111
═══════════════════════════════════════════════════════
步骤2: 节点0x05收到远程帧后,立即发送数据帧
═══════════════════════════════════════════════════════
CAN报文:
COB-ID: 0x185
RTR: 0
DLC: 2
数据: 2C 01 (温度=300 * 0.1 = 30.0°C,小端格式)
数据段详解:
D0 D1
2C 01 ← 温度值
解析:
0x012C = 300 (小端)
实际温度 = 300 * 0.1 = 30.0°C
3.4.6 CANopen中远程帧的应用
在CANopen中,远程帧主要用于RTR触发的PDO:
TPDO传输类型:
| 类型值 | 名称 | 触发条件 |
|---|---|---|
| 0xFC | RTR同步 | 远程帧+SYNC |
| 0xFD | RTR事件驱动 | 远程帧 |
注意 : 现代CANopen中,不推荐频繁使用远程帧,原因:
- 无应答机制,不够可靠
- 事件驱动PDO和周期PDO更常用
- SDO已有完善的请求-应答机制
3.5 位填充规则
3.5.1 位填充原理
规则 : 从SOF到CRC序列,每连续5个相同位 后插入1个反向位。
┌─────────────────────────────────────┐
│ 位填充规则 │
├─────────────────────────────────────┤
│ 原始数据: 1 1 1 1 1 0 0 0 0 0 0 │
│ ↓插入 ↓插入 │
│ 填充后: 1 1 1 1 1 0 0 0 0 0 0 1 │
│ └─插0 └─插1 │
└─────────────────────────────────────┘
作用:
- 保证总线跳变,维持同步
- 防止长时间无跳变导致时钟漂移
- 增强信号完整性
3.5.2 填充示例
【示例1】连续的隐性位
原始: 1 1 1 1 1 1 0
└──5个1─┘
填充: 1 1 1 1 1 0 1 0
↑插0
【示例2】连续的显性位
原始: 0 0 0 0 0 0 1
└──5个0─┘
填充: 0 0 0 0 0 1 0 1
↑插1
【示例3】复杂情况
原始: 0 0 0 0 0 1 1 1 1 1 1 0
└──5个0─┘ └──6个1──┘
步骤1: 前5个0后插1
0 0 0 0 0 1 1 1 1 1 1 1 0
↑插入
步骤2: 现在有6个连续1,在第5个1后插0
0 0 0 0 0 1 1 1 1 1 0 1 1 0
↑插入
最终: 0 0 0 0 0 1 1 1 1 1 0 1 1 0
└插1─┘ └插0─┘
3.6 错误帧
当节点检测到CRC错误、位填充错误、格式错误等,会立即发送错误帧破坏当前传输,通知所有节点丢弃该帧。
- 主动错误帧: 6个连续显性位 (主动错误节点发送)
- 被动错误帧: 6个连续隐性位 (被动错误节点发送)
3.7 完整帧实例
实例1: 发送8字节数据
场景 : 节点0x05发送ID=0x185的数据帧,数据: 01 02 03 04 05 06 07 08
完整位流:
┌───┬─────────────────────────────────────────────────┬────┬───┐
│SOF│ 仲裁段 │ 控制段 │ 数据段 │CRC │ACK│EOF
└───┴─────────────────────────────────────────────────┴────┴───┘
详细分解:
1. SOF: 0
2. 仲裁段 (12位):
ID = 0x185 = 0001 1000 0101 (11位)
0 0 0 1 1 0 0 0 0 1 0 1 0
└──────ID10-ID0──────┘ └RTR
3. 控制段 (6位):
IDE r0 DLC
0 0 1 0 0 0 (DLC=8)
4. 数据段 (64位):
D0 D1 D2 D3 D4 D5 D6 D7
00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000
5. CRC段 (16位):
CRC序列(15位) 界定符
[根据前面位计算] 1
6. ACK段 (2位):
ACK Slot Delimiter
0 1
7. EOF (7位):
1111111
实例2: 远程帧请求
场景: 节点请求ID=0x281的数据,期望4字节
位流:
SOF: 0
仲裁段:
ID = 0x281 = 0010 1000 0001
0 0 1 0 1 0 0 0 0 0 0 1 1
└──────ID10-ID0──────┘ └RTR=1(远程帧)
控制段:
IDE r0 DLC
0 0 0 1 0 0 (DLC=4,期望长度)
[无数据段]
CRC段: [15位CRC] 1
ACK段: 0 1
EOF: 1111111
四、CAN寻址与过滤机制
4.1 广播通信原理
CAN网络本身是广播的,没有"目标地址"的概念。接收方必须通过**"验收过滤"**来挑选自己感兴趣的报文。
CANopen引入了NodeID的概念,但这只是ID分配上的一种约定,物理层依然是广播。
4.2 硬件过滤器
CAN控制器通常配备硬件掩码和过滤器(Mask & Filter):
- Filter (验收代码): 期望接收到的ID位模式。
- Mask (验收掩码): 决定Filter中的哪些位必须匹配 (1=必须匹配, 0=不关心)。
匹配逻辑:
Received_ID & Mask == Filter & Mask
4.3 过滤器配置示例
场景: 某CANopen节点只想接收发给自己的NMT命令(ID=0x00)和SDO请求(ID=0x600+NodeID)。假设NodeID=5 (0x05)。
- 目标ID1:
0x000 - 目标ID2:
0x605(110 0000 0101)
如果只有一个过滤器,很难同时精确匹配这两个相距甚远的ID。通常控制器有多个过滤器组(Filter Bank),可以分别配置。
五、CANopen帧格式
5.1 COB-ID结构
CANopen强制规定了11位CAN-ID的分配规则,称为COB-ID (Communication Object Identifier)。
┌──────────────────┬───────────────────┐
│ Function Code │ Node ID │
│ (4 bits) │ (7 bits) │
└──────────────────┴───────────────────┘
Bit10 ........ Bit7 Bit6 ......... Bit0
- Function Code: 决定报文类型和优先级 (如SDO, PDO, NMT)。
- Node ID: 区分不同设备 (1~127)。
5.2 预定义连接集
CANopen为常用通信对象预分配了缺省ID,使得设备上电即可通信。
| 通信对象 (Object) | 功能码 (Func Code) | COB-ID范围 | 优先级 |
|---|---|---|---|
| NMT (网络管理) | 0000b (0x0) |
0x000 |
最高 |
| SYNC (同步) | 0001b (0x1) |
0x080 |
高 |
| EMCY (紧急) | 0001b (0x1) |
0x081 - 0x0FF |
高 |
| TPDO1 | 0011b (0x3) |
0x181 - 0x1FF |
中高 |
| RPDO1 | 0100b (0x4) |
0x201 - 0x27F |
中高 |
| TPDO2 | 0101b (0x5) |
0x281 - 0x2FF |
中 |
| RPDO2 | 0110b (0x6) |
0x301 - 0x37F |
中 |
| SDO (Tx) (节点发) | 1011b (0xB) |
0x581 - 0x5FF |
中低 |
| SDO (Rx) (节点收) | 1100b (0xC) |
0x601 - 0x67F |
中低 |
| Heartbeat | 1110b (0xE) |
0x701 - 0x77F |
最低 |
提示 :
Tx表示从站发送,Rx表示从站接收。
下面对表中每个通信对象做简明说明与常用示例,方便初学者理解各对象的用途、COB-ID 计算规则与优先级含义。
- NMT (Network Management, 网络管理)
- 功能: 控制节点生命周期(Start/Stop/Pre-op/Reset)。只有NMT主站发送。优先级最高。
- COB-ID:
0x000(广播)。 - 数据: 2 字节
[命令字][节点ID]。例如:01 00表示广播进入 Operational。
- SYNC (同步)
- 功能: 用于在网络中同步动作(例如多轴同步)。通常由主站周期发送。
- COB-ID:
0x080。DLC 通常为 0 或 1(计数器)。 - 优先级: 高,保证同步事件能尽快传达。
- EMCY (Emergency, 紧急报文)
- 功能: 设备发生紧急故障时主动发送,告知故障码和错误寄存器,常用于故障转储和报警。
- COB-ID:
0x080 + NodeID(例如节点 0x05 →0x085)。 - 数据: 8 字节:
[ErrorCode (2B, 小端)] [ErrorRegister (1B)] [ManufacturerSpecific (5B)]。 - 优先级: 高,保证故障信息优先传输。
- TPDO / RPDO (过程数据对象)
-
功能: 用于实时过程数据传输(TPDO = Transmit PDO 节点发送,RPDO = Receive PDO 节点接收)。
-
COB-ID 计算示例(以 TPDO1 为例):
- TPDO1 默认基址:
0x180。实际 COB-ID =0x180 + NodeID(例如 NodeID=0x05 →0x185)。 - RPDO1 默认基址:
0x200。实际 COB-ID =0x200 + NodeID(例如 NodeID=0x05 →0x205)。- RPDO1 默认基址:
0x200。实际 COB-ID =0x200 + NodeID(例如 NodeID=0x05 →0x205)。
- RPDO1 默认基址:
- 传输类型决定触发方式(SYNC、事件或周期性)。TPDO1/RPDO1 优先级高于 TPDO2/RPDO2(因为基码更小)。
示例:TPDO 映射关系(逐字节说明)
- 对象字典相关项(以 TPDO1 对应的对象为例):
-
0x1800:0x01= COB‑ID(例如0x181表示 TPDO1, NodeID=1) -
0x1800:0x02= Transmission Type(触发方式) -
0x1A00:0x00= Number of mapped objects(映射数量) -
0x1A00:0x01= 映射项1(32-bit),格式为Index (16bit) | SubIndex (8bit) | Size (8bit),例如0x60640020表示 Index=0x6064, Sub=0x00, Size=0x20(bits)=32抓包视角 (示例):
CAN ID: 0x181 Data: 78 56 34 12 .. .. .. ..
-
字节位置 HEX 值 含义(简短) D0 0x78 映射的 0x6064 的最低有效字节 (小端) D1 0x56 0x6064 的次低字节 D2 0x34 0x6064 的次高字节 D3 0x12 0x6064 的最高有效字节 - 合并说明:D0...D3 (78 56 34 12) 按小端合并为 0x12345678,表示对象
0x6064:0x00的 32-bit 值。
简短结论:
0x1800/0x1A00定义谁发送(COB‑ID)和发送哪些 OD 条目;抓到 ID=0x181 且前 4 字节为78 56 34 12,即可断定映射对象0x6064:0x00值为0x12345678(小端)。 - TPDO1 默认基址:
- SDO (Service Data Object)
- 功能: 点对点访问对象字典(配置和参数读写),采用请求-应答模式(可靠但开销大)。
- COB-ID:
- SDO 请求(主站 → 从站, Rx at 从站)默认
0x600 + NodeID(从站接收ID) - SDO 响应(从站 → 主站, Tx from 从站)默认
0x580 + NodeID(从站发送ID) - 例:针对 NodeID=0x05,主站写入发到
0x605,从站回复0x585。
- SDO 请求(主站 → 从站, Rx at 从站)默认
- 优先级: 中低,因其通常为配置/非实时数据。
- Heartbeat (心跳)
- 功能: 周期性广播设备当前状态(Bootup/Pre-op/Operational/Stopped),便于主站或监控设备检测节点存活与状态。
- COB-ID:
0x700 + NodeID(例如 NodeID=0x05 →0x705)。 - Data: 1 字节状态码(如
0x05=Operational,0x7F=Pre-Operational,0x00=Boot-up,0x04=Stopped)。 - 优先级: 最低,属于状态监控类。
5.3 节点寻址机制
由于NodeID占7位,一个CANopen网络理论上最多支持 127 个从站节点 (ID 1-127)。ID 0保留给NMT广播。
六、对象字典 (Object Dictionary)
6.1 初学者导读:对象字典是什么
对象字典(Object Dictionary,简称OD)是CANopen设备的"配置表"和"运行接口",它把设备的所有可读写或可监控数据以结构化条目呈现出来。每个条目都包含:
- 索引(Index,16位) :条目的主地址(例如
0x1000)。 - 子索引(Sub-index,8位) :当条目为数组或记录时,用来标识子项(例如
0x00)。 - 数据类型 :如
UNSIGNED8,INTEGER32等。 - 访问权限:只读(RO)、读写(RW)、只写(WO)等。
- 默认值 / 单位 / 说明:便于理解用途。
对于初学者,理解对象字典的三点要点:
- 它不是内存映像,而是设备对外的接口定义表;
- 通过 SDO(点对点)可以访问任意对象;通过 PDO 可以把对象打包广播;
- 大多数工具(EDS/DCF)会导出对象字典,供主站自动配置。
6.2 索引区域划分(简明)
对象索引按功能分区,常见划分:
| 索引范围 (Hex) | 区域名称 | 说明 |
|---|---|---|
0000 |
保留 | - |
0001 - 001F |
数据类型 | 标准数据类型定义 |
0020 - 0FFF |
保留 | - |
1000 - 1FFF |
通信子协议区 | 通信/管理对象(如 0x1000、0x1018、PDO/SDO参数) |
2000 - 5FFF |
制造商特定区 | 厂商扩展功能,主站需参考厂商文档 |
6000 - 9FFF |
设备子协议区 | 特定设备功能(如 DS402 驱动参数) |
A000 - FFFF |
保留 | - |
下面通过具体示例说明如何读写常见区域(均采用小端字节序):
示例 A:读取 0x1000(Device Type,通信子协议区)
场景:主站读取节点 0x05 的 0x1000(4 字节,设备类型)。
- 主站发送(SDO 读取请求,COB-ID=
0x600 + NodeID=0x605):
主站发送(SDO 读取请求,COB-ID=0x600 + NodeID= 0x605):
40 00 10 00 00 00 00 00
字节逐项说明(更通俗的表格形式):
| 字节 | 值 | 字段 | 含义 |
|---|---|---|---|
| Byte0 | 0x40 | Command | SDO 发起"读取"(Initiate Upload 请求)。这是标准命令字,表示客户端请求从站上传对象数据。 |
| Byte1 | 0x00 | Index Low | 对象索引低字节,和 Byte2 组成索引(小端:低字节先)。 |
| Byte2 | 0x10 | Index High | 对象索引高字节;Byte1+Byte2 = 0x1000。 |
| Byte3 | 0x00 | Sub-index | 子索引,0x00 表示主条目(常见用于 VAR 或记录的主项)。 |
| Byte4...7 | 0x00 0x00 0x00 0x00 | 保留/占位 | 读取请求中一般置 0;写入/启动传输时可能携带数据或长度。 |
简明说明:
0x40是由 CiA‑301(CANopen 标准)定义的 SDO 客户端命令字,表示"发起上传(读取)"。标准应答示例:当服务器返回 4 字节数据时,会使用0x43开头的应答帧(0x43 00 10 00 <4字节数据>)。- 索引使用小端字节序,因此
Byte1=0x00、Byte2=0x10表示索引0x1000。
常见相关命令字(便于记忆):
0x40:Initiate Upload(客户端发起读取)0x43:Upload Response(服务器返回 4 字节数据)0x2B:Download 2 字节(客户端写入 2 字节)0x60:Download Response(服务器确认写入)
(应答示例)假设对象返回值为 0x00001234:
43 00 10 00 34 12 00 00 # 服务器应答:0x43 表示返回 4 字节,后四字节为小端数据
示例 B:查看/映射 TPDO(0x1800 与 0x1A00)
场景:节点 0x01 的 TPDO1 使用 COB-ID = 0x180 + NodeID = 0x181,映射 0x6064:00(32 位)。
在 OD 中(示意):
0x1800:0x01 = COB-ID (例如 0x181)
0x1800:0x02 = Transmission Type
0x1A00:0x00 = Number of mapped objects
0x1A00:0x01 = 0x60640020 # Index=0x6064, Sub=0x00, Size=0x20(bits)
运行时收到的 TPDO 示例帧(COB-ID=0x181):
181 # 78 56 34 12 ... # D0..D3 = 78 56 34 12 -> 0x12345678 (小端)
精简的"每段/每字节"说明(便于初学者快速定位含义):
| 部分 | 大小 | 值/示例 | 说明 |
|---|---|---|---|
| SOF | 1 bit | 0 | 帧起始位 |
| 仲裁 (ID) | 11 bits | 0x181 | COB-ID:功能码(4bit)=0x3 (TPDO1) + NodeID(7bit)=0x01,决定优先级 |
| RTR | 1 bit | 0 | 0=数据帧,1=远程帧 |
| 控制 (IDE r0 DLC) | 6 bits | IDE=0 r0=0 DLC=4 | DLC=4 表示数据段有 4 字节 |
| 数据 Byte0 | 8 bits | 0x78 | D0,最低有效字节(小端) |
| 数据 Byte1 | 8 bits | 0x56 | D1 |
| 数据 Byte2 | 8 bits | 0x34 | D2 |
| 数据 Byte3 | 8 bits | 0x12 | D3,最高字节(在小端组合中位于最高位) |
| CRC | 15 bits | ... | 帧校验 |
| CRC Delim | 1 bit | 1 | CRC 结束界定符 |
| ACK Slot | 1 bit | 0/1 | 接收端覆盖显性(0)表示至少一节点接收成功 |
| EOF | 7 bits | 1111111 | 帧结束 |
说明:仲裁和控制为位级字段(不是字节),数据段按字节发送且采用小端表示。若你只关心字节级别(例如抓包工具看到的),重点看数据区的 D0...Dn。
示例 C:制造商特定区写入(0x2000)
场景:主站写入节点 0x05 的 0x2000:01(2 字节,厂商自定义参数 = 0x1234)。
SDO expedited 写入帧(按字节解释):
2B 00 20 00 34 12 00 00
| 字节 | 值 | 含义 |
|---|---|---|
| Byte0 | 0x2B | 命令字:客户端发起 expedited 下载(写入),并指示有效数据长度=2 字节(命令字编码包含 e/s/n 信息)。 |
| Byte1 | 0x00 | Index Low -> 0x2000 的低字节 |
| Byte2 | 0x20 | Index High -> 0x2000 的高字节 |
| Byte3 | 0x00 | Sub-index = 0x00 |
| Byte4 | 0x34 | 数据低字节 D0(小端) -> 0x34 |
| Byte5 | 0x12 | 数据高字节 D1 -> 0x12 (组成 0x1234) |
| Byte6 | 0x00 | 保留/填充 |
| Byte7 | 0x00 | 保留/填充 |
从站应答(写入成功确认):
60 00 20 00 00 00 00 00 # 0x60 表示写入成功确认
说明:Byte0=0x2B 的位级含义可在 SDO CCS 位域章节查看,但对初学者而言,记住 0x2B 表示"写入 2 字节"即可快速判断。
6.3 对象类型(VAR / ARRAY / RECORD)
对象有三种常见类型:
VAR:单一变量,例如0x1001(Error Register,1 字节)。ARRAY:数组,子索引中索引 0 表示数组长度,后续子索引依次为元素。例如0x2000作为数组可能有0x2000:0 = N。RECORD:记录,子索引每项有不同含义,例如0x1018(Identity Object)为 RECORD,包含 VendorID、ProductCode、Revision、SerialNumber。
示例(ARRAY):
0x1600:0x00 = 0x02 # 映射项数
0x1600:0x01 = 0x60400010 # 映射项1: Index=0x6040, Sub=0x00, Size=0x10(bits)
0x1600:0x02 = 0x60600008 # 映射项2: Index=0x6060, Sub=0x00, Size=0x08(bits)
6.4 对象条目关键属性(每个对象都会包含)
- Index/Sub-index: 唯一地址
- Name/Description: 人类可读说明
6.5 设备示例:温度传感器 + LED 控制(完整 OD 演示)
下面给出一个整合示例,把前面讨论的概念放在一个真实可理解的从站上:
- 设备功能:测量温度并通过 LED 指示状态。
- 数据格式:温度为有符号 16-bit,单位 0.01°C(值 1000 表示 10.00°C);LED 控制为 UNSIGNED8(0/1)。
- NodeID:
0x01(示例)。
示例对象字典条目(简化版):
| Index | Sub | 名称 | 类型 | Size(bits) | 说明 |
|---|---|---|---|---|---|
| 0x1000 | 0x00 | Device Type | VAR (RO) | 32 | 设备类型 |
| 0x2000 | 0x00 | Temperature | VAR (RW) | 16 | 温度值 S16, 单位 0.01°C |
| 0x2001 | 0x00 | LED Control | VAR (RW) | 8 | LED 开关,0=关,1=开 |
| 0x1800 | 0x01 | TPDO1 COB‑ID | VAR (RW) | 32 | TPDO1 COB‑ID (0x180 + NodeID) |
| 0x1800 | 0x02 | TPDO1 Transmission Type | VAR (RW) | 8 | 触发方式 |
| 0x1A00 | 0x00 | TPDO1 #mapped | VAR (RW) | 8 | 映射数量 |
| 0x1A00 | 0x01 | TPDO1 Map #1 | RECORD | 32 | 映射 0x2000:00, 16 bits (0x20000010) |
| 0x1A00 | 0x02 | TPDO1 Map #2 | RECORD | 32 | 映射 0x2001:00, 8 bits (0x20010008) |
TPDO 映射配置(示例):
0x1800:0x01=0x181# TPDO1 COB‑ID (NodeID=1)0x1800:0x02=0xFF# Transmission Type (示例)0x1A00:0x00=2# 两个映射对象0x1A00:0x01=0x20000010# Index=0x2000, Sub=0x00, Size=0x10 bits0x1A00:0x02=0x20010008# Index=0x2001, Sub=0x00, Size=0x08 bits
抓包示例(TPDO1,COB‑ID=0x181)与逐字节解析:
CAN ID: 0x181 Data: E8 03 01 00 00 00 00 00
| 字节 | HEX | 含义 |
|---|---|---|
| D0 | 0xE8 | 温度低字节 -> 0xE8 |
| D1 | 0x03 | 温度高字节 -> 0x03 -> 温度 = 0x03E8 = 1000 -> 10.00°C |
| D2 | 0x01 | LED 控制 -> 0x01 = ON |
| D3 | 0x00 | 填充/保留 |
SDO 读取示例(主站读取 0x2000:0x00 温度):
-
请求(COB‑ID =
0x600 + NodeID=0x601):40 00 20 00 00 00 00 00 # 0x40 = Initiate Upload (读取请求),Index=0x2000 (00 20), Sub=0x00
-
响应(COB‑ID =
0x580 + NodeID=0x581,示意返回小端数据):43 E8 03 00 00 00 00 00 # 0xE8 0x03 为温度值 (1000 => 10.00°C)
要点回顾:
- OD 定义了哪些寄存器可访问及其数据类型和权限;
- 通过
0x1A00系列把 OD 条目映射到 PDO,映射顺序决定数据在 PDO 中的字节顺序; - 抓包时按映射把字节还原为原始 OD 值(并使用小端字节序进行数值合并)。
- Data Type: U8/U16/U32/BOOLEAN/DOMAIN 等
- Access: RO / RW / WO / CONST
- Size: 以位为单位 (8/16/32/64)
- PDO Mapping: 是否可映射到PDO
- Default: 出厂默认值
示例条目解析:
0x1017 (Producer Heartbeat Time) :
Sub 0 = U16, RW, default=0x0000 (ms)
6.5 初学者常见操作示例(速查)
-
读取一个 VAR (SDO expedited 读取)
主站发送: 40 <IndexLow> <IndexHigh> <SubIndex> 00 00 00 00
从站返回: 43 <IndexLow> <IndexHigh> <SubIndex> <Data...> -
写入一个 VAR (SDO expedited 写入, 1/2/4 字节)
主站发送: 2F/2B/23 <IndexLow> <IndexHigh> <SubIndex> <Data...>
从站返回: 60 <IndexLow> <IndexHigh> <SubIndex> 00 00 00 00
6.6 常用对象速览表(初学者)
| 索引 | 名称 | 大小 | 访问 | 说明 |
|---|---|---|---|---|
| 0x1000 | Device Type | U32 | RO | 设备类型/子协议 |
| 0x1001 | Error Register | U8 | RO | 错误指示位 |
| 0x1017 | Producer Heartbeat Time | U16 | RW | 心跳周期 (ms) |
| 0x1018 | Identity Object | REC | RO | VendorID/ProductCode/Serial |
| 0x1400 | RPDO 通信参数 | REC | RW | 接收PDO配置 |
| 0x1600 | RPDO 映射参数 | ARRAY | RW | 映射到RPDO的数据项 |
| 0x1800 | TPDO 通信参数 | REC | RW | 发送PDO配置 |
| 0x1A00 | TPDO 映射参数 | ARRAY | RW | 映射到TPDO的数据项 |
以上内容旨在把对象字典概念、索引划分、数据类型与常见操作用"例子+速查表"方式呈现,方便初学者快速上手。
七、CANopen通信对象详解
7.1 NMT网络管理
7.1.1 状态机
NMT (Network Management) 用于控制节点的状态机。只有NMT主站能发送NMT命令。
上电
↓
┌──[初始化]──┐
│Initialization│
└─────┬──────┘
↓
┌─[预操作]──┐ ←────────────┐
│Pre-Operational│ │
└─────┬──────┘ │
│ Start (0x01) │
↓ │
┌─[操作状态]─┐ │
│ Operational │─Stop(0x02)─┤
└──────────────┘ │
↑ │
│ ↓
│ ┌──[停止]───┐
└───Start(0x01)│ Stopped │
└─────────────┘
状态说明:
| 状态 | SDO | PDO | Heartbeat | 说明 |
|---|---|---|---|---|
| Initialization | ✗ | ✗ | ✗ | 上电自动进入,初始化硬件 |
| Pre-Operational | ✓ | ✗ | ✓ | 可配置SDO,不发送PDO |
| Operational | ✓ | ✓ | ✓ | 所有功能正常 |
| Stopped | ✗ | ✗ | ✓ | 仅响应NMT和Heartbeat |
7.1.2 NMT命令帧格式
COB-ID: 0x000 (广播)
DLC: 2
┌─────┬─────────┐
│ D0 │ D1 │
│ CS │ Node ID │
└─────┴─────────┘
CS (Command Specifier):
0x01: Start remote node (进入操作状态)
0x02: Stop remote node (进入停止状态)
0x80: Enter pre-operational state (进入预操作状态)
0x81: Reset node (复位节点)
0x82: Reset communication (复位通信)
D1:
0x00: 广播(所有节点)
0x01-0x7F: 指定节点ID
7.1.3 实例:启动所有节点
CAN帧:
ID: 0x000
DLC: 2
Data: 01 00
解析:
D0 = 0x01 → Start命令
D1 = 0x00 → 广播所有节点
所有节点收到后: 预操作 → 操作状态
7.1.4 实例:复位节点5
CAN帧:
ID: 0x000
DLC: 2
Data: 81 05
解析:
D0 = 0x81 → Reset Node
D1 = 0x05 → 节点5
节点5行为:
1. 重新启动应用程序
2. 发送启动报文 (0x705, Data: 0x00)
3. 进入预操作状态
4. 发送心跳报文 (0x705, Data: 0x7F)
7.2 Heartbeat心跳报文
7.2.1 心跳机制
节点周期性发送,用于表明自己还"活着"以及当前的状态。
COB-ID: 0x700 + Node ID
DLC: 1
┌──────────────┐
│ D0 │
│ State Byte │
└──────────────┘
状态编码:
0x00: Booting (启动中)
0x04: Stopped
0x05: Operational
0x7F: Pre-operational
7.2.2 心跳实例:节点0x0A正常运行
定时发送 (假设周期1000ms):
时间 CAN帧
0ms 70A # 7F (预操作)
1000ms 70A # 7F
2000ms 70A # 7F
[收到NMT启动命令: 000 # 01 0A]
2100ms 70A # 05 (操作中)
3100ms 70A # 05
4100ms 70A # 05
超时检测:
如果主站在1500ms内未收到心跳 → 节点故障
7.2.3 配置心跳周期
通过SDO配置对象 0x1017 (Producer Heartbeat Time):
【任务】设置节点5的心跳周期为1000ms
主站发送 (SDO写入, COB-ID=0x605):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 2B │ 17 │ 10 │ 00 │ E8 │ 03 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──┬──┘ │ └────┬─────┘
│ 索引0x1017│ 1000ms (0x03E8小端)
│ └─ 子索引0x00
└─ 写入2字节
从站应答 (COB-ID=0x585):
60 17 10 00 00 00 00 00 (写入成功)
7.3 SYNC同步对象
7.3.1 SYNC帧格式
主站周期性广播SYNC报文,用于同步网络中所有节点的动作(如多轴同步运动)。
COB-ID: 0x080 (固定)
DLC: 0 或 1
无计数器:
┌────┐
│ │ (空帧)
└────┘
有计数器:
┌──────────┐
│ Counter │ (1-240循环)
└──────────┘
7.3.2 同步窗口
SYNC周期 = 10ms
同步窗口 = 2ms
时间轴:
0ms 2ms 10ms 12ms 20ms
│ │ │ │ │
SYNC──┤ SYNC──┤ SYNC
└─窗口─┘ └─窗口─┘
↑ ↑
在此期间内 超出窗口
接收到的PDO 的PDO无效
才有效
7.4 EMCY紧急报文
7.4.1 EMCY帧格式
当设备发生严重故障(如过温、过流)时主动发送。
COB-ID: 0x080 + Node ID
DLC: 8
┌───────┬────────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ EEC_L │ EEC_H │ ER │MEF0 │MEF1 │MEF2 │MEF3 │MEF4 │
└───────┴────────┴─────┴─────┴─────┴─────┴─────┴─────┘
└───错误代码───┘ 错误 └────厂商自定义错误域────┘
(Error Code) 寄存器
7.4.2 标准错误代码
| EEC | 错误类型 | 说明 |
|---|---|---|
| 0x0000 | 错误复位 | 所有错误已清除 |
| 0x1000 | 通用错误 | 未分类错误 |
| 0x2310 | 电流过大 | 设备侧 |
| 0x3210 | 电压过高 | DC-Link电压 |
| 0x3220 | 电压过低 | DC-Link电压 |
| 0x4210 | 温度过高 | 环境温度 |
| 0x5441 | 通讯错误 | CAN被动 |
| 0x6320 | 软件参数错误 | 参数越界 |
7.4.3 EMCY实例
【场景】节点5发生过温报警
CAN帧:
ID: 0x085 (0x080 + 0x05)
DLC: 8
Data: 10 42 10 00 00 00 00 00
解析:
D0-D1: 0x4210 = 温度过高错误码 (小端)
D2: 0x10 = 错误寄存器 (Bit4=1, 温度错误)
D3-D7: 厂商特定数据
7.5 SDO服务数据对象
7.5.1 基本概念
Service Data Object ,用于点对点访问对象字典。采用 "请求-应答" 模式。
-
客户端-服务器模型: 通常主站为客户端,从站为服务器
-
面向连接: 每个SDO传输需要应答确认
-
访问对象字典: 读取或写入任意对象
通信方向:
主站(客户端) → 0x600+NodeID → 从站(服务器)
← 0x580+NodeID ←
7.5.2 SDO帧格式
┌─────┬────────┬────────┬────────┬─────┬─────┬─────┬─────┐
│ D0 │ D1 │ D2 │ D3 │ D4 │ D5 │ D6 │ D7 │
│CCS/ │Index_L │Index_H │SubIndex│ Data (4 bytes) │
│SCS │ │ │ │ │
└─────┴────────┴────────┴────────┴─────┴─────┴─────┴─────┘
7.5.3 CCS/SCS命令字
客户端命令 (CCS - Client Command Specifier):
| CCS | 名称 | 数据长度 | 说明 |
|---|---|---|---|
| 0x23 | 写入4字节 | 4 | n=0, e=1, s=1 |
| 0x2B | 写入2字节 | 2 | n=2, e=1, s=1 |
| 0x2F | 写入1字节 | 1 | n=3, e=1, s=1 |
| 0x22 | 写入(长度在D4-D7) | - | e=1, s=0 |
| 0x40 | 读取请求 | 0 | - |
| 0x60 | 分段上传 | - | 分段传输 |
| 0x20 | 分段下载 | - | 分段传输 |
服务器响应 (SCS - Server Command Specifier):
| SCS | 名称 | 说明 |
|---|---|---|
| 0x60 | 写入成功 | 确认写入 |
| 0x43 | 读取应答(4字节) | n=0, e=1, s=1 |
| 0x4B | 读取应答(2字节) | n=2, e=1, s=1 |
| 0x4F | 读取应答(1字节) | n=3, e=1, s=1 |
| 0x80 | 中止传输 | 错误代码在D4-D7 |
CCS位域解析:
CCS字节 (8位):
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │
└───┴───┴───┴───┴───┴───┴───┴───┘
│ │ │ │ └───┴───┴───┴───┘
│ │ │ │ n (字节数)
│ │ │ └─ e (是否快速传输)
│ │ └─ s (大小指示)
└───┴─ ccs (命令类型)
示例:
0x23 = 0010 0011
│││ │││└─ n=3 (4-n=1字节无效,即4字节有效)
│││ ││└─ e=1 (快速传输)
│││ │└─ s=1 (数据长度指示有效)
└──┴─ ccs=1 (下载请求)
7.5.4 快速SDO实例
实例1: 写入控制字
【任务】主站写入节点0x05的控制字 (0x6040:0x00 = 0x0006)
1. 主站发送 (COB-ID=0x605):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 2B │ 40 │ 60 │ 00 │ 06 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──┬──┘ │ └────┬─────┘
│ 索引0x6040 │ 数据0x0006 (小端)
│ └─ 子索引0x00
└─ 写入2字节 (0x2B)
2. 从站应答 (COB-ID=0x585):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 60 │ 40 │ 60 │ 00 │ 00 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──确认索引和子索引──┘
└─ 写入成功
3. 如果写入失败 (例如只读对象):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 80 │ 40 │ 60 │ 00 │ 12 │ 00 │ 01 │ 06 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──索引──┘ │ └────错误代码─────┘
│ └─ 子索引 0x06010012
└─ 中止 (尝试写入只读对象)
实例2: 读取心跳周期
【任务】读取节点0x08的心跳周期 (0x1017:0x00)
1. 主站发送 (COB-ID=0x608):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 40 │ 17 │ 10 │ 00 │ 00 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──┬──┘ │
│ 索引0x1017│
│ └─ 子索引0x00
└─ 读取请求
2. 从站应答 (假设心跳周期=1000ms):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 43 │ 17 │ 10 │ 00 │ E8 │ 03 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──索引──┘ │ └────┬─────┘
│ └─ 子索引 1000 (0x03E8小端)
└─ 返回4字节
7.5.5 分段SDO实例
场景: 写入64字节数据到 0x3000:0x00
阶段1: 启动下载
主站 → 从站 (0x621):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 21 │ 00 │ 30 │ 00 │ 40 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └──索引──┘ │ └────┬─────┘
│ └─ 子索引 64字节 (小端)
└─ 启动分段下载 (大小指示)
从站应答 (0x5A1):
60 00 30 00 00 00 00 00 (确认)
阶段2: 分段传输 (每次7字节)
段1: 主站 → 从站
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 00 │ D0 │ D1 │ D2 │ D3 │ D4 │ D5 │ D6 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └────────7字节数据──────────┘
└─ 段序号0, toggle=0
从站应答: 20 (确认段0)
段2: 主站 → 从站
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 10 │ D7 │ D8 │ ... │ D13│ │ │ │
└────┴────┴────┴────┴────┴────┴────┴────┘
└─ toggle=1
从站应答: 30 (确认段1)
... (继续传输)
最后一段 (段9, 仅1字节):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 0D │ D63│ 00 │ 00 │ 00 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
│ └最后1字节
└─ c=1(最后一段), n=6(6字节无效), toggle=0
从站应答: 20 (确认完成)
7.6 PDO过程数据对象
7.6.1 PDO特点
Process Data Object,用于实时数据传输。
| 特性 | SDO | PDO |
|---|---|---|
| 传输模式 | 面向连接 | 无连接(广播) |
| 确认 | 需要应答 | 无应答 |
| 实时性 | 低 | 高 |
| 数据长度 | 任意 | ≤8字节 |
| 用途 | 配置参数 | 实时过程数据 |
7.6.2 PDO类型
TPDO (Transmit PDO): 节点发送数据
┌────────┐ TPDO ┌────────┐
│ 从站 │───────→│ 主站 │
└────────┘ └────────┘
RPDO (Receive PDO): 节点接收数据
┌────────┐ RPDO ┌────────┐
│ 主站 │───────→│ 从站 │
└────────┘ └────────┘
7.6.3 传输类型
| 类型值 | 名称 | 触发条件 |
|---|---|---|
| 0x00 | 同步(周期) | 每个SYNC |
| 0x01-0xF0 | 同步(间隔) | 每N个SYNC |
| 0xFC | RTR同步 | 远程请求+SYNC |
| 0xFD | RTR事件 | 远程请求 |
| 0xFE | 事件驱动 | 数据改变 |
| 0xFF | 周期(异步) | 定时器 |
7.6.4 PDO配置流程
步骤1: 禁用PDO
写入0x1400:0x01 = 0x80000200 (bit31=1, COB-ID无效)
步骤2: 清空映射
写入0x1600:0x00 = 0x00
步骤3: 配置映射对象
写入0x1600:0x01 = 0x60400010 (控制字, 16位)
写入0x1600:0x02 = 0x60600008 (运行模式, 8位)
步骤4: 设置映射数量
写入0x1600:0x00 = 0x02
步骤5: 配置传输类型
写入0x1400:0x02 = 0xFF (异步周期)
写入0x1400:0x05 = 100 (100ms周期)
步骤6: 启用PDO
写入0x1400:0x01 = 0x00000200 (bit31=0, COB-ID有效)
7.6.5 TPDO完整实例
场景: 电机驱动器(节点0x02)周期发送速度和位置
1. 对象字典配置:
通信参数 (0x1800):
0x1800:0x00 = 0x06
0x1800:0x01 = 0x40000182 (COB-ID=0x182, bit30=0启用)
0x1800:0x02 = 0xFF (异步传输)
0x1800:0x05 = 50 (50ms周期)
映射参数 (0x1A00):
0x1A00:0x00 = 0x02
0x1A00:0x01 = 0x606C0020 (速度实际值, 32位)
0x1A00:0x02 = 0x60640020 (位置实际值, 32位)
数据对象 (DS402标准):
0x606C:0x00 = 1500 (当前速度 1500 RPM)
0x6064:0x00 = 123456 (当前位置 123456 编码器计数)
2. 生成的CAN帧:
时间 COB-ID 数据
0ms 182 DC 05 00 00 40 E2 01 00
└───速度───┘ └───位置───┘
1500 (小端) 123456 (小端)
50ms 182 E6 05 00 00 A0 E4 01 00
1510 124000
100ms 182 F0 05 00 00 00 E7 01 00
1520 124672
3. 数据解析:
帧1: 182 # DC 05 00 00 40 E2 01 00
速度 (D0-D3):
DC 05 00 00 → 0x000005DC = 1500 (小端)
位置 (D4-D7):
40 E2 01 00 → 0x0001E240 = 123456 (小端)
7.6.6 RPDO完整实例
场景: 主站控制电机(节点0x03)的目标速度
1. 从站对象字典配置:
通信参数 (0x1400):
0x1400:0x00 = 0x02
0x1400:0x01 = 0x00000203 (接收COB-ID=0x203)
0x1400:0x02 = 0xFF (异步传输)
映射参数 (0x1600):
0x1600:0x00 = 0x02
0x1600:0x01 = 0x60400010 (控制字, 16位)
0x1600:0x02 = 0x60FF0020 (目标速度, 32位)
应用对象:
0x6040:0x00 = 0x0000 (当前控制字)
0x60FF:0x00 = 0 (当前目标速度)
2. 主站发送命令:
任务: 设置控制字=0x000F (使能), 目标速度=2000 RPM
主站发送 (COB-ID=0x203):
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 0F │ 00 │ D0 │ 07 │ 00 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┴────┴────┴────┴────┘
└─┬─┘ └────┬────┘
│ └─ 2000 (0x07D0小端)
└─ 0x000F (控制字)
从站行为:
1. 接收到0x203帧
2. 解析D0-D1 → 0x6040:0x00 = 0x000F
3. 解析D2-D5 → 0x60FF:0x00 = 2000
4. 电机开始加速到2000 RPM
5. 无应答帧发送
7.6.7 同步PDO实例
场景: 2个电机节点同步启动
1. 节点配置:
节点1 (ID=0x01):
0x1400:0x02 = 0x01 (收到1个SYNC后处理RPDO)
节点2 (ID=0x02):
0x1400:0x02 = 0x01 (收到1个SYNC后处理RPDO)
2. 时序图:
时间轴 主站 节点1 节点2
│ │ │ │
├─ 0ms ─────┤ │ │
│ RPDO1→ │ │ │
│ 201#06 │ ──→ (缓存) │ │
│ │ │ │
├─ 5ms ─────┤ │ │
│ RPDO2→ │ │ │
│ 202#06 │ ──────────────→ │ (缓存) │
│ │ │ │
├─ 10ms ────┤ │ │
│ SYNC → │ │ │
│ 080# │ ──→ (执行RPDO) │ │
│ │ 电机启动 ───┴───→ (执行RPDO) │
│ │ 电机启动 ────┘
│ │ ↑ ↑
│ │ 同步启动(误差<1ms)
八、设备子协议
CANopen定义了针对不同类型设备的子协议 (Profile),确保不同厂商的同类设备具相同的接口。
8.1 DS402 驱动与运动控制
针对伺服驱动器、变频器、步进电机控制器。常用对象:
0x6040: Control Word (控制字 - 启动/停止/复位)0x6041: Status Word (状态字 - 准备好/故障/运行中)0x6060: Modes of Operation (运行模式 - 位置/速度/力矩)0x607A: Target Position (目标位置)0x60FF: Target Velocity (目标速度)
8.2 DS401 I/O模块
针对数字量/模拟量输入输出模块。
0x6000: Read Input 8-bit (读输入)0x6200: Write Output 8-bit (写输出)
九、开发实践与典型设备示例
本章将常用工具、调试技巧与两个完整硬件设备示例整合,覆盖伺服驱动器(DS402)与分布式数字I/O模块(DS401)的完整启动与运行流程,逐帧说明各类型报文的实际应用。
9.1 常用工具与调试技巧
工具:
- USB-CAN分析仪: Kvaser, PEAK-System, 周立功等。
- CANopen主站软件: CANopenNode(开源)、CanFestival(开源)、Codesys(软PLC)。
调试技巧:
- 先通NMT: 确保节点上电并发送Bootup (0x700+ID)。
- 再通SDO: 读取0x1000验证对象字典访问。
- 后配PDO: 通过SDO配置映射,监控总线PDO数据。
- 注意字节序 : CANopen采用小端模式。
- 心跳保护: 开启Heartbeat监控防止掉线未被发现。
9.2 设备示例A:maxon EPOS4伺服驱动器(DS402)
设备概述 :maxon EPOS4, NodeID=0x01, 支持DS402运动控制协议。
关键OD对象:
| Index | 名称 | 类型 | 说明 |
|---|---|---|---|
| 0x1000 | DeviceType | U32 | 设备标识 |
| 0x6040 | Control Word | U16 | 控制字(启动/停止/复位) |
| 0x6041 | Status Word | U16 | 状态字(运行/故障/就绪) |
| 0x60FF | Target Velocity | S32 | 目标速度(小端) |
| 0x2000 | Temperature | S16 | 驱动温度(0.01°C单位) |
完整运行流程与逐帧说明:
阶段1:上电与身份确认
1.1 Bootup广播
时刻: T0 (上电后100ms内)
方向: EPOS4 → 总线
COB-ID: 0x701
Data: 00 00 00 00 00 00 00 00
说明: 节点上电完成广播,通知主站设备在线
1.2 主站读取Identity
主站 → EPOS4:
COB-ID: 0x601 (0x600+ID)
Data: 40 18 10 00 00 00 00 00
说明: SDO上传请求,读取0x1018(Identity Object)
EPOS4 → 主站:
COB-ID: 0x581 (0x580+ID)
Data: 4F 00 00 B2 00 00 00 00
说明: 返回VendorID等信息(示例:0x000000B2 = maxon)
阶段2:SDO配置
2.1 设置Heartbeat间隔
主站 → EPOS4:
COB-ID: 0x601
Data: 2B 17 10 00 E8 03 00 00
说明: 写入0x1017 = 0x03E8 (1000ms),小端: E8 03
EPOS4 → 主站:
COB-ID: 0x581
Data: 60 17 10 00 00 00 00 00
说明: 写入确认
2.2 配置TPDO1映射
步骤1: 禁用TPDO1(写入COB-ID高位=1)
主站 → EPOS4: 23 00 18 01 81 01 00 80 # 0x80000181
EPOS4 → 主站: 60 00 18 01 00 00 00 00
步骤2: 设置映射项数=3
主站 → EPOS4: 2F 00 1A 00 03 00 00 00 # 0x1A00:00 = 3
步骤3: 映射StatusWord (0x6041, 16bit)
主站 → EPOS4: 23 00 1A 01 10 00 41 60 # 0x60410010
步骤4: 映射Temperature (0x2000, 16bit)
主站 → EPOS4: 23 00 1A 02 10 00 00 20 # 0x20000010
步骤5: 映射ErrorRegister (0x1001, 8bit)
主站 → EPOS4: 23 00 1A 03 08 00 01 10 # 0x10010008
步骤6: 启用TPDO1
主站 → EPOS4: 23 00 18 01 81 01 00 00 # 0x00000181
2.3 配置RPDO1映射(接收控制命令)
映射: ControlWord(0x6040,16bit) + TargetVelocity(0x60FF,32bit)
配置步骤类似TPDO,设置0x1400(RPDO通讯参数)与0x1600(映射)
阶段3:进入Operational
3.1 NMT Start
时刻: T1 (配置完成后)
方向: 主站 → 总线(广播)
COB-ID: 0x000
Data: 01 00
说明: 命令=0x01(Start), NodeID=0x00(广播所有节点)
阶段4:运行时数据交换
4.1 Heartbeat(周期性)
时刻: T2, T2+1000ms, T2+2000ms...
方向: EPOS4 → 总线
COB-ID: 0x701
Data: 05
说明: 状态=0x05 (Operational)
4.2 TPDO1(事件触发或周期)
时刻: T3 (状态变化时)
方向: EPOS4 → 总线
COB-ID: 0x181 (0x180+ID)
Data: 79 05 E8 03 00 00 00 00
解析表格:
┌────────┬──────┬──────────┬─────────────────┐
│ 字节 │ HEX │ 字段 │ 含义 │
├────────┼──────┼──────────┼─────────────────┤
│ D0-D1 │79 05 │StatusWord│0x0579(小端) │
│ D2-D3 │E8 03 │Temp │0x03E8=1000→10°C │
│ D4 │00 │ErrorReg │无错误 │
└────────┴──────┴──────────┴─────────────────┘
4.3 RPDO1(主站控制)
时刻: T4 (主站下发速度命令)
方向: 主站 → EPOS4
COB-ID: 0x201 (0x200+ID)
Data: 0F 00 D0 07 00 00 00 00
解析:
D0-D1: 0x000F = ControlWord (启动使能)
D2-D5: 0x07D0 = 2000 (目标速度, 小端)
4.4 运行时SDO查询
读取实时StatusWord:
主站 → EPOS4: 40 41 60 00 00 00 00 00 # Read 0x6041
EPOS4 → 主站: 43 79 05 00 00 00 00 00 # 返回0x0579
阶段5:SYNC同步(可选)
主站周期广播SYNC:
COB-ID: 0x080
Data: (空或含计数器)
若TPDO/RPDO配置为SYNC触发,节点会在收到SYNC后立即执行PDO操作
阶段6:故障处理
6.1 EMCY故障上报
时刻: T5 (检测到过温)
方向: EPOS4 → 总线
COB-ID: 0x081 (0x080+ID)
Data: 01 23 01 50 00 00 00 00
解析:
Byte0-1: 0x2301 = ErrorCode (过温,小端)
Byte2: 0x01 = ErrorRegister (温度错误位)
Byte3: 0x50 = 温度值80°C(示例)
Byte4-7: 厂商自定义
6.2 主站处理
1. 记录EMCY到日志
2. SDO读取详细诊断对象(如0x1003 Pre-defined Error Field)
3. 必要时发送NMT Stop (0x000, Data=02 00)
4. 或NMT Reset Node (0x000, Data=81 00)
流程图(Mermaid)
EPOS4(0x01) 主站 EPOS4(0x01) 主站 Power On loop [运行时] 故障检测 Bootup (0x701) SDO Read Identity SDO Response (VendorID) SDO Write Heartbeat SDO Configure TPDO/RPDO NMT Start (0x000) Heartbeat (0x701) TPDO1 (0x181) RPDO1 (0x201) SYNC (0x080) EMCY (0x081) SDO Read Error NMT Stop/Reset
9.3 设备示例B:分布式数字I/O模块(DS401)
设备概述 :通用数字I/O模块,NodeID=0x02, 8路输入+8路输出。
关键OD对象:
| Index | 名称 | 类型 | 说明 |
|---|---|---|---|
| 0x1000 | DeviceType | U32 | 设备标识(0x00000191=DS401) |
| 0x6000 | Read Input 8-bit | U8 | 数字输入状态(位图) |
| 0x6200 | Write Output 8-bit | U8 | 数字输出控制(位图) |
完整运行流程与逐帧说明:
阶段1:上电与配置
1.1 Bootup
I/O模块 → 总线:
COB-ID: 0x702 (0x700+0x02)
Data: 00 00 00 00 00 00 00 00
1.2 主站读取DeviceType
主站 → I/O模块:
COB-ID: 0x602
Data: 40 00 10 00 00 00 00 00 # Read 0x1000
I/O模块 → 主站:
COB-ID: 0x582
Data: 43 91 01 00 00 00 00 00 # 0x00000191
1.3 配置TPDO(上报输入状态)
映射0x6000(输入状态,8bit)到TPDO1:
设置0x1A00:01 = 0x60000008
设置TPDO1为事件触发(输入变化时发送)
1.4 配置RPDO(接收输出命令)
映射0x6200(输出控制,8bit)到RPDO1:
设置0x1600:01 = 0x62000008
阶段2:进入Operational
主站 → 总线:
COB-ID: 0x000
Data: 01 00 # NMT Start广播
阶段3:运行时数据交换
3.1 输入状态上报(TPDO)
时刻: T0 (输入端子3从0→1)
方向: I/O模块 → 总线
COB-ID: 0x182 (0x180+0x02)
Data: 04 00 00 00 00 00 00 00
解析:
Byte0 = 0x04 = 0b00000100 (第3位=1,表示输入3有效)
3.2 输出控制(RPDO)
时刻: T1 (主站打开输出端子1和5)
方向: 主站 → I/O模块
COB-ID: 0x202 (0x200+0x02)
Data: 11 00 00 00 00 00 00 00
解析:
Byte0 = 0x11 = 0b00010001 (第1位和第5位=1)
模块动作: 输出端子1和5输出高电平
3.3 运行时SDO读取
主站查询当前输入状态:
主站 → I/O: 40 00 60 00 00 00 00 00 # Read 0x6000
I/O → 主站: 4F 04 00 00 00 00 00 00 # 返回0x04
阶段4:SYNC同步输出
主站配置RPDO为SYNC触发后,输出更新流程:
T0: 主站发送RPDO (0x202: 11) → 模块缓存
T1: 主站发送SYNC (0x080) → 模块立即更新输出
好处: 多个I/O模块可在同一SYNC时刻同步动作
时序示意
T0 T100ms T200ms T300ms
│ │ │ │
├─Bootup
│ ├─SDO配置
│ │ ├─NMT Start
│ │ │ ├─TPDO(输入变化)
│ │ │ ├─RPDO(主站控制)
│ │ │ ├─Heartbeat
│ │ │ └─...运行循环
9.4 关键对象索引速查表
| 索引 | 名称 | 访问 | 类型 | 说明 |
|---|---|---|---|---|
| 1000h | Device Type | RO | U32 | 设备类型 |
| 1001h | Error Register | RO | U8 | 错误状态位 |
| 1017h | Producer Heartbeat Time | RW | U16 | 心跳间隔(ms) |
| 1018h | Identity Object | RO | REC | 设备身份信息 |
| 1400h-15FFh | RPDO Comm. Parameter | RW | REC | 接收PDO通讯参数 |
| 1600h-17FFh | RPDO Mapping | RW | REC | 接收PDO映射 |
| 1800h-19FFh | TPDO Comm. Parameter | RW | REC | 发送PDO通讯参数 |
| 1A00h-1BFFh | TPDO Mapping | RW | REC | 发送PDO映射 |
9.5 常见问题校验点
-
COB-ID计算:
- SDO请求: 0x600 + NodeID
- SDO响应: 0x580 + NodeID
- TPDO1: 0x180 + NodeID
- RPDO1: 0x200 + NodeID
- Heartbeat: 0x700 + NodeID
- EMCY: 0x080 + NodeID
-
字节序 :所有多字节数值(Index、Data)均采用小端模式。
-
SDO索引表示:Index=0x1800时,Byte1=0x00, Byte2=0x18(低字节在前)。
-
PDO映射格式:32位映射值 = Index(16bit) + SubIndex(8bit) + Size(8bit),例如0x60410010表示0x6041:00, 16bits。
9.6 总结
通过 maxon EPOS4(伺服驱动器)与分布式数字I/O模块两个典型设备的完整运行流程,本章展示了CANopen协议中所有关键帧类型(Bootup、NMT、SDO、TPDO、RPDO、Heartbeat、SYNC、EMCY)的实际应用场景与字节级示例。这些示例将前文理论知识与实际抓包/配置操作串联,便于读者从工程角度理解CANopen在运动控制与分布式I/O领域的应用。
(文档结束)