跳到主要内容

CoE - CANopen 协议

CoE 是 EtherCAT 中最常用最广泛的应用层协议,将 CANopen 的对象字典和通信机制移植到 EtherCAT 上,掌握 CoE 是 EtherCAT 开发的基础。

协议简介

官方说明:

  • 应用范围:I/O 组件、驱动、编码器、比例阀、液压控制器等
  • 兼容机制:对象字典、PDO、SDO、网络管理
  • 固件复用:绝大部分 CANopen 固件可重复使用
  • 扩展性:可选扩展对象以利用 EtherCAT 带宽

适用设备

  • 数字/模拟 I/O 模块
  • 伺服驱动器(CiA 402)
  • 步进电机控制器
  • 编码器
  • 传感器
  • 变频器
  • 比例阀
  • 液压控制器

核心概念

对象字典 (Object Dictionary)

对象字典是 CoE 的核心,使用 16 位索引 + 8 位子索引寻址:

  • 0x0000 — 保留
  • 0x0001 - 0x0FFF — 数据类型定义(UNSIGNED8, INTEGER16 等)
  • 0x1000 - 0x1FFF — 通信参数(设备类型、同步管理器配置)
  • 0x2000 - 0x5FFF — 厂商特定参数(设备专有功能)
  • 0x6000 - 0x9FFF — 标准化设备协议(CiA 401, CiA 402 等)
  • 0xA000 - 0xFFFF — 保留

常用通信对象

索引名称类型访问说明
0x1000Device TypeUNSIGNED32RO设备类型标识
0x1001Error RegisterUNSIGNED8RO错误寄存器
0x1008Manufacturer Device NameSTRINGRO设备名称
0x1009Hardware VersionSTRINGRO硬件版本
0x100ASoftware VersionSTRINGRO软件版本
0x1018Identity ObjectRECORDRO身份信息(VendorID、ProductCode 等)
0x1C00Sync Manager TypeARRAYROSM 类型配置
0x1C10-1C13SM PDO AssignARRAYRWSM PDO 分配
0x1C32-1C33SM SynchronizationRECORDRWSM 同步配置

SDO 通信服务

SDO (Service Data Object) 用于非周期性参数访问,通过 Mailbox 通信实现。

SDO 特点

  • 非实时通信:通过 Mailbox 传输,不占用 PDO 周期
  • 完全访问:可读取/写入对象字典任意对象
  • 分段传输:支持大数据块传输
  • 确认机制:有响应确认

代码示例

// 读取设备名称
byte[] name = slave.CoE.SDORead(0x1008, 0);
string deviceName = Encoding.ASCII.GetString(name);
Console.WriteLine($"设备名称: {deviceName}");

// 读取 Identity Object
byte[] identity = slave.CoE.SDORead(0x1018, 0, completeAccess: true);

// 写入参数
slave.CoE.SDOWrite(0x6060, 0, new byte[] { 8 }); // 设置操作模式为 CSP

// 完全访问模式读取
byte[] pdoMapping = slave.CoE.SDORead(0x1600, 0, completeAccess: true);

SDO 访问类型

  • Normal Access — 访问单个子索引,用于读写单个参数
  • Complete Access — 一次访问整个对象,用于读写数组、记录类型

PDO 映射

PDO (Process Data Object) 用于周期性实时数据交换,直接映射到逻辑地址空间。

PDO 类型

  • RxPDO(Receive PDO):主站 → 从站(输出数据)
  • TxPDO(Transmit PDO):从站 → 主站(输入数据)

PDO 映射对象

  • 0x1600 - 0x17FF — RxPDO Mapping — 定义输出数据映射
  • 0x1A00 - 0x1BFF — TxPDO Mapping — 定义输入数据映射

PDO 映射结构

每个 PDO 映射对象包含多个子索引:

0x1600 - RxPDO Mapping 1
├── 0x00: 映射对象数量 (SubIndex 0)
├── 0x01: 第1个映射对象 (Index:SubIndex:BitLength)
├── 0x02: 第2个映射对象
└── ...

映射对象格式(32位):

  • Bit 31-16: 对象索引 (Index)
  • Bit 15-8: 子索引 (SubIndex)
  • Bit 7-0: 位长度 (Bit Length)

示例:伺服驱动器 PDO 映射

以下示例基于真实伺服驱动器 (Ezi-SERVO2 EtherCAT) 的 PDO 配置:

RxPDO (0x1600) — 主站到伺服(4个映射对象,共 96 bits = 12 bytes)

子索引名称对象地址位长度
0x1600:01控制字0x6040:0016 bits
0x1600:02目标位置0x607A:0032 bits
0x1600:03物理输出0x60FE:0132 bits
0x1600:04探针功能0x60B8:0016 bits

TxPDO (0x1A00) — 伺服到主站(7个映射对象,共 176 bits = 22 bytes)

子索引名称对象地址位长度
0x1A00:01状态字0x6041:0016 bits
0x1A00:02实际位置0x6064:0032 bits
0x1A00:03数字输入0x60FD:0032 bits
0x1A00:04错误代码0x603F:0016 bits
0x1A00:05探针状态0x60B9:0016 bits
0x1A00:06探针位置10x60BA:0032 bits
0x1A00:07探针位置20x60BC:0032 bits

PDO Assignment 配置:

对象索引说明配置内容
0x1C12 (RxPDO Assignment)SM2 输出映射1个PDO: 0x1600
0x1C13 (TxPDO Assignment)SM3 输入映射1个PDO: 0x1A00

代码示例

// 读取 TxPDO 映射
byte[] txPdoMap = slave.CoE.SDORead(0x1A00, 0, completeAccess: true);

// 访问 PDO 数据(通过 SDK)
byte[] outputs = slave.PDO.GetOutputs();
slave.PDO.SetOutputs(new byte[] { 0x0F, 0x00, ... });

同步管理器 (Sync Manager)

SM 负责将 PDO 映射到物理内存区域:

SM类型方向默认地址用途
SM0Mailbox主站到从站0x1000Mailbox Out (SDO, FoE 等)
SM1Mailbox从站到主站0x1080Mailbox In (SDO 响应等)
SM2Process Data主站到从站0x1100RxPDO (输出)
SM3Process Data从站到主站0x1180TxPDO (输入)

网络管理 (NMT)

CoE 支持 CANopen 网络管理功能:

NMT 状态

  • Pre-Operational — 配置状态,可访问 SDO
  • Operational — 运行状态,PDO 通信活跃
  • Stopped — 停止状态

对象字典访问方法

通过 SDK

// SDO 方式
byte[] data = slave.CoE.SDORead(index, subindex);
slave.CoE.SDOWrite(index, subindex, data);

// PDO 方式(实时周期数据)
byte[] inputs = slave.PDO.GetInputs();
slave.PDO.SetOutputs(outputs);

访问规则

  • RO (Read Only) — 只读,如设备类型
  • WO (Write Only) — 只写,如某些命令
  • RW (Read/Write) — 可读写,如配置参数
  • RWW — 可读写,写前需 Pre-OP 状态
  • RXPDO — 可通过 RxPDO 映射
  • TXPDO — 可通过 TxPDO 映射

完全访问模式

Complete Access 用于一次性读写整个对象(数组或记录类型):

// 读取完整 PDO 映射
byte[] mapping = slave.CoE.SDORead(0x1600, 0, completeAccess: true);

// 写入完整 PDO 映射
slave.CoE.SDOWrite(0x1600, 0, mappingData, completeAccess: true);

优势:

  • 原子操作,保证数据一致性
  • 减少通信次数
  • 适用于数组/记录类型

应用示例

读取设备信息

// 读取设备类型
byte[] typeData = slave.CoE.SDORead(0x1000, 0);
uint deviceType = BitConverter.ToUInt32(typeData, 0);

// 读取设备名称
byte[] nameData = slave.CoE.SDORead(0x1008, 0);
string deviceName = Encoding.ASCII.GetString(nameData);

// 读取版本信息
byte[] hwVersion = slave.CoE.SDORead(0x1009, 0);
byte[] swVersion = slave.CoE.SDORead(0x100A, 0);

Console.WriteLine($"设备: {deviceName}");
Console.WriteLine($"类型: 0x{deviceType:X8}");
Console.WriteLine($"硬件版本: {Encoding.ASCII.GetString(hwVersion)}");
Console.WriteLine($"软件版本: {Encoding.ASCII.GetString(swVersion)}");

配置 PDO 映射

// 1. 切换到 Pre-OP 状态
master.RequestState(SlaveState.PreOP);

// 2. 清空现有映射
slave.CoE.SDOWrite(0x1C12, 0, new byte[] { 0 }); // SM2 PDO Assign
slave.CoE.SDOWrite(0x1C13, 0, new byte[] { 0 }); // SM3 PDO Assign

// 3. 配置新映射
// RxPDO: 0x6040 (控制字, 16bit)
slave.CoE.SDOWrite(0x1600, 0, new byte[] { 0 }); // 清空
slave.CoE.SDOWrite(0x1600, 1, BitConverter.GetBytes(0x60400010)); // 0x6040:00, 16bits
slave.CoE.SDOWrite(0x1600, 0, new byte[] { 1 }); // 设置数量

// 4. 分配 SM
slave.CoE.SDOWrite(0x1C12, 1, BitConverter.GetBytes((ushort)0x1600));
slave.CoE.SDOWrite(0x1C12, 0, new byte[] { 1 });

// 5. 切换到 OP 状态
master.RequestState(SlaveState.OP);

与其他协议对比

特性CoESoEEoE
来源CANopenSERCOSEthernet
实时性极高
复杂度
应用通用高端运动控制网络设备
设备支持最广泛高端设备网络设备