CANopen通信协议

目录

  • 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的广播特性)
    • 三、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))
      • [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实例)
    • 八、设备子协议
      • [8.1 DS402 驱动与运动控制](#8.1 DS402 驱动与运动控制)
      • [8.2 DS401 I/O模块](#8.2 DS401 I/O模块)
    • 九、开发实践与典型设备示例

一、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_HCAN_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)机制。

  1. 线与 (Wired-AND): 总线上只要有一个节点发送显性(0),总线即为显性(0)。只有所有节点都发送隐性(1),总线才为隐性(1)。
  2. 仲裁过程 :
    • 所有节点同时监听总线。
    • 当节点发送隐性位(1)但检测到显性位(0)时,意味着有更高优先级的节点在发送。
    • 该节点立即停止发送(仲裁失败),转为接收模式。
  3. 优先级 : 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      │
└─────────────────────────────────────┘

作用:

  1. 保证总线跳变,维持同步
  2. 防止长时间无跳变导致时钟漂移
  3. 增强信号完整性
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 计算规则与优先级含义。

  1. NMT (Network Management, 网络管理)
  • 功能: 控制节点生命周期(Start/Stop/Pre-op/Reset)。只有NMT主站发送。优先级最高。
  • COB-ID: 0x000(广播)。
  • 数据: 2 字节 [命令字][节点ID]。例如:01 00 表示广播进入 Operational。
  1. SYNC (同步)
  • 功能: 用于在网络中同步动作(例如多轴同步)。通常由主站周期发送。
  • COB-ID: 0x080。DLC 通常为 0 或 1(计数器)。
  • 优先级: 高,保证同步事件能尽快传达。
  1. EMCY (Emergency, 紧急报文)
  • 功能: 设备发生紧急故障时主动发送,告知故障码和错误寄存器,常用于故障转储和报警。
  • COB-ID: 0x080 + NodeID(例如节点 0x05 → 0x085)。
  • 数据: 8 字节: [ErrorCode (2B, 小端)] [ErrorRegister (1B)] [ManufacturerSpecific (5B)]
  • 优先级: 高,保证故障信息优先传输。
  1. 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)。
    • 传输类型决定触发方式(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(小端)。

  1. SDO (Service Data Object)
  • 功能: 点对点访问对象字典(配置和参数读写),采用请求-应答模式(可靠但开销大)。
  • COB-ID:
    • SDO 请求(主站 → 从站, Rx at 从站)默认 0x600 + NodeID(从站接收ID)
    • SDO 响应(从站 → 主站, Tx from 从站)默认 0x580 + NodeID(从站发送ID)
    • 例:针对 NodeID=0x05,主站写入发到 0x605,从站回复 0x585
  • 优先级: 中低,因其通常为配置/非实时数据。
  1. 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)等。
  • 默认值 / 单位 / 说明:便于理解用途。

对于初学者,理解对象字典的三点要点:

  1. 它不是内存映像,而是设备对外的接口定义表;
  2. 通过 SDO(点对点)可以访问任意对象;通过 PDO 可以把对象打包广播;
  3. 大多数工具(EDS/DCF)会导出对象字典,供主站自动配置。

6.2 索引区域划分(简明)

对象索引按功能分区,常见划分:

索引范围 (Hex) 区域名称 说明
0000 保留 -
0001 - 001F 数据类型 标准数据类型定义
0020 - 0FFF 保留 -
1000 - 1FFF 通信子协议区 通信/管理对象(如 0x10000x1018、PDO/SDO参数)
2000 - 5FFF 制造商特定区 厂商扩展功能,主站需参考厂商文档
6000 - 9FFF 设备子协议区 特定设备功能(如 DS402 驱动参数)
A000 - FFFF 保留 -

下面通过具体示例说明如何读写常见区域(均采用小端字节序):

示例 A:读取 0x1000(Device Type,通信子协议区)

场景:主站读取节点 0x050x1000(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=0x00Byte2=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)

场景:主站写入节点 0x050x2000: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 bits
  • 0x1A00: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 常用工具与调试技巧

工具

  1. USB-CAN分析仪: Kvaser, PEAK-System, 周立功等。
  2. CANopen主站软件: CANopenNode(开源)、CanFestival(开源)、Codesys(软PLC)。

调试技巧

  1. 先通NMT: 确保节点上电并发送Bootup (0x700+ID)。
  2. 再通SDO: 读取0x1000验证对象字典访问。
  3. 后配PDO: 通过SDO配置映射,监控总线PDO数据。
  4. 注意字节序 : CANopen采用小端模式
  5. 心跳保护: 开启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 常见问题校验点

  1. COB-ID计算

    • SDO请求: 0x600 + NodeID
    • SDO响应: 0x580 + NodeID
    • TPDO1: 0x180 + NodeID
    • RPDO1: 0x200 + NodeID
    • Heartbeat: 0x700 + NodeID
    • EMCY: 0x080 + NodeID
  2. 字节序 :所有多字节数值(Index、Data)均采用小端模式

  3. SDO索引表示:Index=0x1800时,Byte1=0x00, Byte2=0x18(低字节在前)。

  4. 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领域的应用。


(文档结束)

相关推荐
cooldream20098 小时前
Vim 报错 E325:swap 文件冲突的原理、处理流程与彻底避免方案
linux·编辑器·vim
i建模8 小时前
在 Rocky Linux 上安装轻量级的 XFCE 桌面
linux·运维·服务器
若风的雨8 小时前
WC (Write-Combining) 内存类型优化原理
linux
YMWM_8 小时前
不同局域网下登录ubuntu主机
linux·运维·ubuntu
zmjjdank1ng8 小时前
restart与reload的区别
linux·运维
哼?~8 小时前
进程替换与自主Shell
linux
浩浩测试一下9 小时前
DDOS 应急响应Linux防火墙 Iptable 使用方式方法
linux·网络·安全·web安全·网络安全·系统安全·ddos
niceffking9 小时前
linux 信号内核模型
linux·运维·服务器
嵌入小生0079 小时前
单向链表的常用操作方法---嵌入式入门---Linux
linux·开发语言·数据结构·算法·链表·嵌入式
.小墨迹9 小时前
C++学习——C++中`memcpy`和**赋值拷贝**的核心区别
java·linux·开发语言·c++·学习·算法·机器学习