4. 同步生产者与消费者配置
PDO,说白了就是CANopen里跑实时数据的通道。SDO像快递柜,你取一件我放一件,慢但稳;PDO像广播喇叭,一喊全听见,快但不保证每句都有人听。电机控制这种需要高频交换位置、速度、电流的场景,PDO才是主角。
我个人习惯把PDO理解成“数据管道”。你提前把管道里要传什么、什么时候传、传多少都定好,运行时就不需要再协商了。这也是PDO效率高的根本原因——配置一次,终身使用。
4.1 TPDO与RPDO:谁发谁收?
先搞清楚方向:
- TPDO(Transmit PDO):设备往外发数据。比如驱动器把当前转速、电流发到总线上。
- RPDO(Receive PDO):设备从总线收数据。比如驱动器接收上位机下发的目标位置。
一个设备可以有多个TPDO和RPDO。CANopen标准最多支持每个设备4个TPDO + 4个RPDO,但实际芯片实现各有不同。我见过有些国产驱动器只实现了2个TPDO,踩坑后才发现的。
| 类型 | 方向 | 典型用途 | COB-ID范围 |
|---|---|---|---|
| TPDO | 设备 → 总线 | 上报状态、位置、电流 | 0x180 + NodeID ~ 0x1FF + NodeID |
| RPDO | 总线 → 设备 | 下发目标值、控制字 | 0x200 + NodeID ~ 0x2FF + NodeID |
4.2 同步PDO vs 异步PDO:什么时候发?
这是PDO配置里最核心的选择。我刚开始做电机同步控制时,就因为这个没选对,导致四轴联动总是差一拍。
同步PDO(Synchronous PDO)
依赖SYNC报文触发。主站周期发SYNC,从站收到后统一采集数据、统一输出。适合多轴插补、同步运动。
- 传输类型:0~4(同步周期模式)、5~15(同步非周期模式)
- 特点:所有节点在同一时间基准上动作
- 缺点:SYNC报文丢失会导致整周期数据失效
异步PDO(Asynchronous PDO)
由事件触发。比如数据变化、定时器到期、远程帧请求等。适合单轴控制、状态监测。
- 传输类型:252~255(事件触发)、253(远程帧请求)
- 特点:响应快,不依赖SYNC
- 缺点:多个节点同时触发可能造成总线冲突
4.3 PDO映射:管道里到底装什么?
PDO映射就是告诉设备:这个PDO报文里,第1个字节是什么,第2个字节是什么。映射关系写在对象字典的0x1A00~0x1A03(TPDO映射)和0x1600~0x1603(RPDO映射)里。
举个例子,我想让TPDO1发“实际位置+实际速度”:
// 对象字典配置(以CiA 402标准为例)
0x1A00 sub0 = 2 // 映射对象数量
0x1A00 sub1 = 0x60640020 // 实际位置,32位
0x1A00 sub2 = 0x606C0010 // 实际速度,16位
// 映射值解析:
// 0x60640020 → 索引0x6064,子索引0x00,长度32位
// 0x606C0010 → 索引0x606C,子索引0x00,长度16位
映射格式是固定的:索引(16位) + 子索引(8位) + 长度(8位),拼成一个32位值。写错了设备会报错,我调试时经常因为长度写错位导致数据对不上。
4.4 事件定时器与禁止时间:控制发送节奏
这两个参数是异步PDO的“节流阀”。没有它们,数据变化一次就发一次,总线可能被冲垮。
事件定时器(Event Timer)
定义在0x1800~0x1803的子索引5。单位毫秒。定时器到期就触发一次PDO发送,不管数据有没有变化。
- 典型值:10ms(100Hz)、50ms(20Hz)、100ms(10Hz)
- 设为0表示禁用定时器触发
禁止时间(Inhibit Time)
定义在0x1800~0x1803的子索引3。单位100微秒。两次PDO发送之间的最小间隔。
- 典型值:100(即10ms禁止时间)
- 防止数据频繁变化时总线被刷屏
| 参数 | 对象字典位置 | 单位 | 作用 |
|---|---|---|---|
| 事件定时器 | 0x1800~0x1803 sub5 | ms | 周期触发PDO发送 |
| 禁止时间 | 0x1800~0x1803 sub3 | 100μs | 最小发送间隔 |
4.5 传输类型详解:一张表说清楚
PDO传输类型(0x1800~0x1803 sub2)决定了PDO的触发方式。我整理了一张速查表,调试时贴在工位上很管用:
| 类型值 | 触发方式 | 同步/异步 | 典型场景 |
|---|---|---|---|
| 0 | 每个SYNC发一次,但数据由事件更新 | 同步 | 同步采集+事件触发更新 |
| 1 | 每个SYNC发一次 | 同步 | 多轴同步控制 |
| 2~240 | 每N个SYNC发一次 | 同步 | 降频同步(如每5个SYNC发一次) |
| 252 | 事件触发+定时器触发 | 异步 | 状态监测 |
| 253 | 远程帧请求触发 | 异步 | 主站按需读取 |
| 254 | 制造商特定 | 异步 | 定制功能 |
| 255 | 事件触发(数据变化) | 异步 | 快速响应变化 |
嗯,这里要注意:类型255虽然响应最快,但如果数据在短时间内剧烈抖动(比如编码器噪声),总线会被无效报文塞满。我建议配合禁止时间一起用,设个5~10ms的最小间隔。
4.6 核心逻辑图:PDO通信全流程
下面这张图把TPDO从配置到发送的完整路径画出来了。我每次培训新人都拿这张图讲,比看半天文档管用。
4.7 避坑指南:我踩过的PDO坑
做CANopen这些年,PDO相关的坑我踩了不少。挑几个典型的说说:
- 映射长度不对齐:比如映射了3个16位数据,总长度6字节,但CAN报文是8字节。剩下的2字节是随机值,接收方如果没做掩码处理,数据会跳变。我后来强制要求所有PDO映射总长度必须是8的倍数,不够的补0。
- 禁止时间设太小:有一次把禁止时间设为10(即1ms),结果数据变化频繁时,总线负载率直接飙到80%。后来改到100(10ms),问题解决。
- 同步PDO的SYNC丢失:SYNC报文优先级不够高,被其他报文挤掉了。我建议把SYNC的COB-ID设为0x80,优先级最高,并且主站要加超时重发机制。
- 运行时改映射:这个前面提过,但值得再说一遍——改映射前必须停PDO,否则设备行为不可预测。我见过有人在线改映射导致驱动器直接进入错误状态。
CO_PDO.c里。修改映射后要调用CO_PDO_init()重新初始化,否则新映射不生效。这个细节文档里没写,我是读源码才发现的。