首页 / 驱动算法 / EtherCAT专题

EtherCAT PDO 详解:过程数据对象映射与同步

PDO(Process Data Object,过程数据对象)是 EtherCAT 每周期都在传的"干货":主站下发的目标值、从站回报的实际值,都靠它跑。本文讲清 PDO 与邮箱(SDO)的分工、Tx/Rx 方向约定、PDO 映射的三元组编码(index+subindex+bitlen 怎么打包成位流)、CoE 对象字典里 0x1600/0x1A00/0x1C10/0x1C11 怎么组织 PDO、位对齐与长度计算、SM 事件与 DC 两种同步机制,以及 PDO 配置从 EEPROM/ESI 到主站覆盖的完整来源链,配位打包交互演示与可编译 C 模块。

1. PDO 是什么:实时通道 vs 邮箱通道

EtherCAT 从站和主站之间有两种数据通道,分工完全不同:

通道承载周期内容例子
过程数据(PDO)帧里的逻辑寻址区(LRW)每个通信周期(如 1ms/125μs)实时控制量:目标位置、控制字、实际位置、状态字CSP 模式每个周期下发 607Ah 目标位置
服务数据(SDO/邮箱)帧里的邮箱区(SM0/SM1)按需(非周期)配置/诊断:改对象字典、读状态、下载参数启动时读 6098h 回原点方式

一句话:PDO 是"每周期必达的实时快递",邮箱是"偶尔寄的信"。 控制环路的正确性取决于 PDO 的确定性——这也是 EtherCAT 用硬件(ESC)处理 PDO 而把邮箱留给软件(从站栈)的原因。

2. 一趟完整的 PDO 旅程:帧 → FMMU → SM → PDI → 对象字典

以一个伺服从站的输出过程数据(主站 → 从站,目标位置)为例:

环节在哪儿发生干什么
主站打包主站协议栈把 0x607A 目标位置写进过程数据缓冲,放入 LRW 数据报的逻辑地址区
FMMU 映射从站 ESC 内逻辑地址 → 从站本地内存映射(初始化时配好)
SM 缓冲从站 ESC 内数据写入 SM2 输出缓存,置"新数据"事件
PDI 交接ESC → MCUSPI/并行接口把数据交给 MCU(中断或轮询)
对象字典落地MCU 从站栈按 PDO 映射把位流拆回 0x607A 等对象值,应用层 FOC 消费

输入方向(从站 → 主站:实际位置 0x6064)对称:应用写对象字典 → 按映射打包进 SM3 输入缓存 → FMMU → 帧返回主站,WKC 工作计数器 +2。注意 PDO 全程硬件级流转,不经过 MCU 协议解析——MCU 只做"对象字典 ⇄ 位流"的搬运,这正是 EtherCAT 能跑 125μs 周期的关键。

3. TxPDO / RxPDO 方向约定与伺服典型 PDO

⚠️ 方向术语以"从站视角"为准

RxPDO = 从站接收(主站 → 从站,输出过程数据);TxPDO = 从站发送(从站 → 主站,输入过程数据)。最容易搞反——记住"R=Receive,站在从站角度看"。主站侧常叫"输出/输入 SM",含义相反,对配置文档时先确认视角。

方向对象名称典型位长
RxPDO
(主站→从站)
0x6040控制字(使能/使能运行/停机)16 bit
0x6060操作模式(CSP/CST/CSV)8 bit
0x607A目标位置32 bit
0x60FF目标速度32 bit
TxPDO
(从站→主站)
0x6041状态字(就绪/使能/故障)16 bit
0x6064实际位置32 bit
0x606C实际速度32 bit
0x6077实际转矩16 bit

4. PDO 映射:对象字典条目如何编码成位流

一个 PDO 是一串"要一起传的对象",映射表定义了哪些对象、从哪个子索引、占多少位。EtherCAT CoE 里每个 PDO 对应一个映射对象(0x1A00 起 TxPDO / 0x1600 起 RxPDO),结构如下:

子索引内容示例(0x1A00 TxPDO)
0映射条目数量(计数)3
1第 1 个映射条目(32 bit 三元组)6041h · 00h · 16 bit → 状态字
2第 2 个映射条目6064h · 00h · 32 bit → 实际位置
3第 3 个映射条目606Ch · 00h · 32 bit → 实际速度
映射条目编码(32 bit)

bit31..16 = 对象索引(16 bit) | bit15..8 = 子索引(8 bit) | bit7..0 = 位长度(8 bit)

例:0x60640020 = 索引 0x6064、子索引 0、32 bit。读取映射时先读子索引 0 得到条数,再逐条读三元组

把映射条目"排进"过程数据缓冲时,按条目顺序位连续拼接:上面 0x1A00 三个条目共 16+32+32 = 80 bit = 10 字节,主站和从站都按这个布局读写同一块缓冲——映射表就是两端共用的"快递单"。

5. CoE 对象字典里的 PDO 组织:0x1600 / 0x1A00 / 0x1C00 / 0x1C10 / 0x1C11

PDO 不是散装的,CoE 用一套固定索引把它们组织起来:

索引区含义
0x1600 ~ 0x17FFRxPDO 参数(每个接收 PDO 一个:映射条目 + 方向/触发信息)
0x1A00 ~ 0x1BFFTxPDO 参数(每个发送 PDO 一个)
0x1C00同步管理器类型:SM0/1=邮箱、SM2=过程数据输入、SM3=过程数据输出
0x1C10过程数据输入 SM 的 PDO 分配列表(= 该 SM 使用哪些 0x1Axx)
0x1C11过程数据输出 SM 的 PDO 分配列表(= 该 SM 使用哪些 0x16xx)
0x1C12 / 0x1C13邮箱输入/输出 SM 的 PDO 分配(一般为空)

主站把 0x1C11 填上 [0x1600, 0x1601, ...],从站才知道"SM3 输出通道由这些 RxPDO 组成",然后按 0x16xx 里的映射去打包/拆包。改 PDO 的标准动作就是先改映射(0x16xx/0x1Axx 子索引),再改分配(0x1C10/0x1C11),最后重启通信状态机(Init → PreOp → SafeOp → OP)。

6. 位对齐、字节序与长度计算

映射打包有两条硬规则:

  • 位连续:各条目按顺序紧密排列,不做 8/16 位对齐填充——前提是映射条目本身按规范要求"对齐友好"(EtherCAT 规范建议 8 位边界对齐,强制禁止条目跨超过 32 位的边界组合);
  • 小端(little-endian):过程数据缓冲按小端存放多字节对象,与 ARM/x86 内存一致,无需软件翻转。
过程数据长度计算

L = ⌈(Σi bitleni) / 8⌉ 字节

Rx 例:控制字 16 + 目标位置 32 + 目标速度 32 = 80 bit → 10 字节;Tx 例:状态字 16 + 实际位置 32 = 48 bit → 6 字节。主站按 ESI/EEPROM 里的映射算出的长度,必须与从站 SM2/SM3 的缓存长度一致,否则 WKC 不匹配

8 bit 边界对齐的约定还带来一个工程好处:可以直接用 memcpy 搬运,不必做位操作;只有出现"半个字节"的怪映射(如 12 bit 对象)才需要位写入器(见第 9 节代码)。

7. 同步机制:SM 事件 vs DC 分布式时钟

机制原理精度适用
SM 事件(帧同步)ESC 收到该 SM 的数据帧时产生中断/事件,MCU 收到即处理取决于主站帧抖动(μs 级~几十 μs)单从站、对同步要求不苛刻
DC(分布式时钟)全网从站对齐到参考时钟,按绝对时间(Sync0)同时启动输出ns 级(<1μs 典型)多轴联动、伺服轨迹同步——必选

DC 模式下 PDO 的消费时点由Sync0 中断决定:主站提前一个周期下发数据,所有从站在同一时刻(相位对齐的 Sync0)取数执行——这就是"多轴同起同停"的物理基础。SM 事件与 DC 可以并存:SM 负责数据到位,DC 负责消费时点。从站是否支持 DC 由 EEPROM F8 段声明(见《EtherCAT EEPROM 作用详解》)。

8. PDO 配置从哪来:EEPROM → ESI → 主站覆盖

从站出厂时的默认 PDO 长什么样,源头有三层:

  • EEPROM(F4/F5 段):出厂默认 Tx/Rx PDO 映射,主站上电时先读它建初始过程数据;
  • ESI 文件(XML):厂商发布的设备描述里带完整 PDO 定义(含所有可选映射),主站据此提供配置界面;
  • 主站运行期覆盖:CoE 写 0x1600/0x1A00 映射 + 0x1C10/0x1C11 分配,从站按新配置收发——EEPROM 里的默认值被覆盖但不必落盘。

三层的关系:EEPROM 定"出厂默认",ESI 定"能力全集",主站定"现场实配"。现场改 PDO 不写 EEPROM(重启恢复默认),要固化才需要主站工具写回。

9. 交互演示:PDO 映射位打包

勾选要放进 RxPDO(主站→伺服)的对象,看它们如何按映射顺序连续打包成字节流:

RxPDO 位打包演示(勾选对象 → 连续拼接 → 小端字节流)
已选 3 个对象 · 16+8+32 = 56 bit = 7 字节(小端打包)

观察要点:

  • 对象按勾选顺序连续拼接,不做填充;总位长 Σbitlen 向上取整字节;
  • 32 bit 对象(目标位置)在缓冲里按小端存放(低字节在前),主从两端内存模型一致;
  • 加/减对象后总字节数变化,必须同步 0x1C11 分配与 SM3 缓存长度,否则主站会报过程数据长度不匹配。

10. 代码实现(C语言,可编译模块)

从站 MCU 侧把对象字典值打包进过程数据缓冲——用位写入器处理任意位长(含非字节对齐),对齐友好的映射退化成 memcpy 也可:

/* pdo_pack.c — PDO 位流打包/拆包模块(精简) */ #include <stdint.h> #include <string.h> /* 映射条目:从对象字典 0x1Axx/0x16xx 子索引读出 */ typedef struct { uint16_t index; /* 对象索引,如 0x607A */ uint8_t subindex; /* 子索引 */ uint8_t bitlen; /* 位长度,如 32 */ } pdo_entry; /* 位写入器:把 value(bitlen 位)写进 buf 的 bit 偏移 off */ static void bit_write(uint8_t* buf, uint32_t* off, uint32_t value, uint8_t bitlen) { for (int i = 0; i < bitlen; i++) { uint32_t o = *off + i; if ((value >> i) & 1u) buf[o / 8] |= (uint8_t)(1u << (o % 8)); else buf[o / 8] &= (uint8_t)~( 1u << (o % 8)); } *off += bitlen; } /* 把 OD 值数组打包进过程数据缓冲(TxPDO:从站→主站) */ void pdo_pack_tx(uint8_t* buf, const pdo_entry* map, int n, uint32_t (*od_read)(uint16_t, uint8_t)) { memset(buf, 0, 64); uint32_t off = 0; for (int i = 0; i < n; i++) { uint32_t v = od_read(map[i].index, map[i].subindex); bit_write(buf, &off, v, map[i].bitlen); } } /* 拆包:从缓冲按映射读回 OD 值(RxPDO:主站→从站) */ void pdo_unpack_rx(const uint8_t* buf, const pdo_entry* map, int n, void (*od_write)(uint16_t, uint8_t, uint32_t)) { uint32_t off = 0; for (int i = 0; i < n; i++) { uint32_t v = 0; for (int b = 0; b < map[i].bitlen; b++) { uint32_t o = off + b; if (buf[o / 8] & (1u << (o % 8))) v |= (1u << b); } off += map[i].bitlen; od_write(map[i].index, map[i].subindex, v); } }

应用侧:映射表在 PreOp 阶段从 0x1A00/0x1600 对象字典读出(子索引 0 = 条数),存成 pdo_entry 数组;进入 OP 后每周期调 pack/unpack。位写入器对字节对齐映射也正确——只是稍慢,追求极致周期时可换成按字节 memcpy 的快速路径。

11. 工程避坑清单

坑现象对策
Tx/Rx 方向搞反配置里怎么都对,跑起来数据全错/不更新以从站视角命名:Rx=收、Tx=发;对照 ESI 的 SM 方向再填 0x1C10/0x1C11
映射与 SM 缓存长度不一致主站报过程数据长度错误 / WKC 异常总位长 ⌈Σbitlen/8⌉ 必须等于 SM2/SM3 配置长度;改映射后同步改 SM
改了映射没重启状态机新映射不生效或部分生效PDO 修改后必须 Init → PreOp → SafeOp → OP 完整走一遍(0x1C10/1C11 在 PreOp 下发)
多字节对象字节序混乱位置/速度值错乱但控制正常确认小端存放;跨架构(如大端 DSP)时在 PDI 边界做字节交换
非 8 位对齐映射打包错位、偶发数据错规范上强制禁止条目组合跨 32 bit 边界;尽量全用 8/16/32 bit 对象
DC 时相位未对齐多轴"同时"但输出时刻有固定偏移用 Sync0 周期与相移寄存器统一;DC 从站先跑"DC 同步窗口"校准
EEPROM 默认 PDO 与 ESI 不一致同一从站不同批次行为不同F4/F5 段内容由 SSC 从 ESI 生成,量产 bin 与 ESI 版本绑定校验

一句话收尾:PDO 是 EtherCAT 实时性的心脏——映射决定"传什么",分配决定"谁传",同步决定"什么时候用",三者对齐,从站才真正"实时"。