12. SDO 查询与 PDO 传输
上一课中,ESP32 已经能够通过 SDO 读取电机参数。SDO 请求中写有 Index 和 Sub-index,电机会用这个对象地址找到参数并返回它的值;这个过程也叫“访问电机的对象字典”。
例如,读取当前位置参数 0x6064:00 时,总线上实际出现过下面两帧报文:
| 方向 | CAN-ID | DATA |
|---|---|---|
| ESP32 → 电机 | 0x601 | 40 64 60 00 00 00 00 00 |
| 电机 → ESP32 | 0x581 | 43 64 60 00 AA 16 00 00 |
第一帧是请求,第二帧是响应。程序把响应中的四个数据字节 AA 16 00 00 按小端序组合,得到位置值 5802。
注意:接收
0x701Heartbeat 不属于读取对象字典。Heartbeat 是电机按周期主动发送的在线状态报文,ESP32 没有在报文中指定 Index 和 Sub-index,也没有向电机发起 SDO 请求。
这种方式很适合“现在查一次位置”。接下来先考虑一个实际需求:如果程序运行时每秒要知道 10 次当前位置,还继续使用同样的方法,会发生什么?
再看一次已经读懂的 SDO
请求中的前四个字节告诉电机“读取对象 0x6064:00”:
| 请求中的字节 | 含义 |
|---|---|
40 | 发起一次 SDO 读取 |
64 60 | Index,按小端序表示 0x6064 |
00 | Sub-index 0x00 |
响应中再次带回相同地址:
| 响应中的字节 | 含义 |
|---|---|
43 | 读取成功,返回 4 字节数据 |
64 60 | Index 0x6064 |
00 | Sub-index 0x00 |
AA 16 00 00 | 电机返回的位置值 |
这样做的好处是,请求和响应都明确写着正在访问哪个对象。程序可以先读 0x1000:00,下一次再读 0x6064:00,电机也能区分它们。
但这也意味着,每读取一次位置,都必须完成三个步骤:
- ESP32 发送请求:说明要读取
0x6064:00。 - 电机查找数据:在自己的对象字典中找到当前位置。
- 电机返回响应:把对象地址和当前位置一起发回 ESP32。
一次读取至少产生一帧请求和一帧响应。
连续查询时,总线上会重复什么
假设程序每秒读取 10 次 0x6064:00:
| 查询频率 | 请求帧 | 响应帧 | 每秒合计 |
|---|---|---|---|
| 读取 1 次 | 1 帧 | 1 帧 | 2 帧 |
| 每秒读取 10 次 | 10 帧 | 10 帧 | 20 帧 |
这 20 帧中,下面这些内容会不断重复:
| 每次查询都会重复的内容 | 数值 |
|---|---|
| 请求 CAN-ID | 0x601 |
| 响应 CAN-ID | 0x581 |
| 对象 Index | 0x6064 |
| 对象 Sub-index | 0x00 |
| 请求命令字 | 0x40 |
| 响应命令字 | 0x43 |
真正不断变化、程序最关心的,通常只有响应中的位置值。
这里不是说 20 帧一定会让 500 kbit/s 的总线立即拥堵。重点是通信方式:控制器每想知道一次数据,都要先提问,然后等待回答。读取对象越多、读取频率越高,重复的请求和地址字段就越多。
SDO 的优点没有因此消失。读取设备类型、序列号、配置参数,或者修改一个对象时,一问一答仍然很合适,因为程序需要知道这次访问成功了还是返回了 Abort。
运行数据需要另一种传输方式
电机运行时,控制器经常反复读取当前位置、当前速度和状态字,也可能周期发送目标位置或控制字。
如果发送方和接收方事先知道一帧 DATA 中放哪些值,就不必每次都把对象地址装进报文。
CANopen 把这种报文称为 Process Data Object,缩写为 PDO,中文常称“过程数据对象”。
先看图中两条通信过程。SDO 在下方,需要请求和响应;PDO 在上方,由发送节点直接发出一帧已经约定好内容的报文:

两种方式可以先这样区分:
| 通信方式 | 对象地址放在哪里 | 报文过程 |
|---|---|---|
| SDO | 写在每次请求中 | ESP32 请求,电机响应 |
| PDO | 预先保存在 PDO 配置中 | 发送节点直接发送数据 |
“已经配置好”具体是什么意思
假设某台电机的一条 PDO 使用 CAN-ID 0x181,并采用下面的 DATA 排列:
| DATA 范围 | 保存的值 | 长度 |
|---|---|---|
DATA[0..1] | Statusword | 2 字节 |
DATA[2..5] | Position Actual Value | 4 字节 |
接收程序看到 0x181 后,就会按照这张表读取前 2 字节和后 4 字节。
这一帧 DATA 中不会再出现 0x6041 或 0x6064。对象地址保存在设备的 PDO 配置中,不需要每一帧重复发送。
上面的排列只是解释通信方式的示例,不是本电机的实际配置。本教程不会根据常见用法猜测 IG35EC020 的 PDO 内容。第 14 课会用只读 SDO 从电机中读取真实配置。
SDO 和 PDO 分别适合做什么
| 要完成的事 | 通常使用 | 原因 |
|---|---|---|
| 读取设备类型 | SDO | 请求中可以指定 0x1000:00 |
| 修改一个配置参数 | SDO | 能收到成功响应或 Abort |
| 周期获得当前位置 | PDO | 配置确定后,一帧直接携带数据 |
| 周期发送控制量 | PDO | 不必每次重复对象地址 |
PDO 不是更高级的 SDO,也不会取代 SDO。调试和配置阶段通常使用 SDO 访问对象字典;正常运行阶段再使用 PDO 传输频繁变化的数据。
用真实报文做一次检查
回到开头的响应:
43 64 60 00 AA 16 00 00
请先自己指出:
- 哪一个字节是响应命令字;
- 哪两个字节组成 Index;
- 哪一个字节是 Sub-index;
- 哪四个字节才是位置值。
答案是:
| 字节 | 解释 |
|---|---|
43 | 响应命令字 |
64 60 | Index 0x6064,小端序 |
00 | Sub-index 0x00 |
AA 16 00 00 | 位置值,小端序 |
现在把前四个字节想象成不再随每次报文重复出现,只保留最后四个位置数据,就能看到 PDO 想解决的问题。
本课使用的原始电机通信记录保存在:
docs/images/sources/ig35ec020_sdo_read_2026-08-05.txt
这一课学会了什么
这一课只需要得到一个结论:
SDO 通过请求和响应访问指定对象,适合查询和配置。
PDO 按预先确定的排列直接传输数据,适合反复交换运行数据。
现在还没有解释谁发送 PDO、谁接收 PDO,也没有假定电机已经启用 PDO。下一课先把发送方向和 CAN-ID 讲清楚,再去读取配置。
资料链接
- CAN in Automation:SDO protocol:SDO 请求、响应和对象字典访问。
- CAN in Automation:PDO protocol:PDO 单帧传输和数据预配置。
- 第 11 课:用 SDO 读取电机参数:回看
0x601、0x581和一次完整的 SDO 读取。