SDO 协议详解 -- Client/Server 模型与帧格式
目录
SDO 基本概念
SDO(Service Data Object,服务数据对象)是 CANOpen 中用于非实时、参数访问的通信机制。它采用 Client/Server 模型:
- Client:发起请求的一方(通常是主站/上位机)
- Server:响应请求的一方(通常是设备/从节点)
典型应用场景:
- 配置设备参数(波特率、节点 ID、PDO 映射)
- 读取设备信息(固件版本、制造商信息)
- 诊断和调试(读取错误记录)
- 非实时的控制参数调整
与 PDO 的对比:
| 特性 | SDO | PDO |
|---|---|---|
| 模型 | Client/Server(请求-响应) | Producer/Consumer(发布-订阅) |
| 实时性 | 非实时 | 实时 |
| 数据量 | 任意大小(分段传输) | 最多 8 字节 |
| 确认机制 | 有(确认/错误响应) | 无(广播) |
| 典型用途 | 参数配置、诊断 | 实时控制、状态反馈 |
SDO 通信参数
每个 CANOpen 节点有一对 SDO 通信参数:
| 方向 | COB-ID 计算公式 | 说明 |
|---|---|---|
| Client -> Server(SDO Request) | 0x600 + node_id | 客户端发送请求 |
| Server -> Client(SDO Response) | 0x580 + node_id | 服务端发送响应 |
示例(节点 ID = 3):
- 请求 COB-ID:
0x600 + 3 = 0x603 - 响应 COB-ID:
0x580 + 3 = 0x583
Client (主站) Server (节点 3)
│ │
│─── SDO Request ────────────>│
│ COB-ID = 0x603 │
│ │
│<── SDO Response ───────────│
│ COB-ID = 0x583 │
│ │默认节点 0 的 SDO: CANOpen 预留了节点 0 的 SDO 用于特殊用途:
- SDO 0 Request: 0x600
- SDO 0 Response: 0x580
SDO 帧格式
SDO 使用 CAN 标准帧(11 位 ID),数据场最多 8 字节。
SDO Request 帧格式(Client -> Server)
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ Byte 0 │ B 1 │ B 2 │ B 3 │ B 4 │ B 5 │ B 6 │ B 7 │
├────────┼─────┼──────┼────────┼────────┼────────┼────────┼────────┤
│ CCS+ 0 │Index │Index │SubIdx │ Data... │ Data... │ Data... │ Data... │
│ (命令) │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘字节 0 格式:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ CCS │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
╰─ Command SpecifierSDO Response 帧格式(Server -> Client)
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ Byte 0 │ B 1 │ B 2 │ B 3 │ B 4 │ B 5 │ B 6 │ B 7 │
├────────┼─────┼──────┼────────┼────────┼────────┼────────┼────────┤
│ SCS+ 0 │Index │Index │SubIdx │ Data... │ Data... │ Data... │ Data... │
│ (命令) │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘字节 0 格式:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ SCS │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
╰─ Server Command SpecifierCCS(Client Command Specifier)– 客户端命令码
| CCS | 命令 | 说明 |
|---|---|---|
| 000 (0x0) | SDO Initiate Download | 客户端写请求 |
| 001 (0x1) | SDO Initiate Upload | 客户端读请求 |
| 010 (0x2) | SDO Segment Transfer | 分段传输(客户端继续发送/接收) |
| 011 (0x3) | SDO Initiate Block Download | 块写请求 |
| 100 (0x4) | SDO Initiate Block Upload | 块读请求 |
| 101 (0x5) | SDO Block Transfer | 块传输 |
| 110 (0x6) | SDO Abort Transfer | 终止传输 |
SCS(Server Command Specifier)– 服务端命令码
| SCS | 命令 | 说明 |
|---|---|---|
| 010 (0x2) | SDO Initiate Download Response | 写请求确认 |
| 011 (0x3) | SDO Initiate Upload Response | 读响应(携带数据) |
| 100 (0x4) | SDO Segment Transfer Response | 分段传输响应 |
| 101 (0x5) | SDO Initiate Block Download Response | 块写响应 |
| 110 (0x6) | SDO Initiate Block Upload Response | 块读响应 |
| 111 (0x7) | SDO Abort Transfer | 终止传输(错误) |
三种传输模式
1. Expedited Transfer(快速传输)
适用于 ≤ 4 字节 的小数据。
特点:
- 单次请求 + 单次响应
- 数据直接嵌入帧中(字节 4-7)
- 无需后续分段
2. Segmented Transfer(分段传输)
适用于 > 4 字节 的大数据。
特点:
- 多次请求 + 多次响应
- 每段最多 7 字节(字节 1-7)
- Toggle 位机制(防止丢包)
- 有明确的开始、中间、结束阶段
3. Block Transfer(块传输)
适用于 大量数据(固件更新等)。
特点:
- 一次确认后连续发送多个数据块
- 减少通信开销
- CANopenNode 基本实现中不常用
Abort Transfer(终止传输)
当 SDO 传输中出现错误时,服务端发送 Abort 帧:
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ 0x80 │Index │Index │SubIdx │ Abort Code (4 bytes) │
│ │ (Lo) │ (Hi) │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘常见 Abort 码:
| Abort 码 | 含义 |
|---|---|
| 0x05030000 | Toggle 位不匹配 |
| 0x05040000 | SDO 同步超时 |
| 0x05040001 | Client/Server 命令码无效 |
| 0x06010000 | 不支持的访问类型 |
| 0x06010002 | 尝试写入只读对象 |
| 0x06020000 | 对象字典中不存在该索引 |
| 0x06040041 | 对象不兼容(子索引无效) |
| 0x06040043 | 一般内部错误 |
| 0x06040047 | 数据类型不匹配 |
| 0x08000000 | 一般错误 |
| 0x08000020 | 数据无法传输 |
Expedited Upload 详解
帧格式
Request(Client -> Server):
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ 0x40 │Index │Index │SubIdx │ 0x00 │ 0x00 │ 0x00 │ 0x00 │
│ │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘- 字节 0 =
0x40= CCS=1(Upload)+ e=0(非 Expedited 标记,实际由服务端决定) - 字节 1-2 = 索引(小端模式)
- 字节 3 = 子索引
Response(Server -> Client):
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ Byte 0 │Index │Index │SubIdx │ Data │ Data │ Data │ Data │
│ │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘字节 0 格式(Expedited Upload Response):
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 0 │ 1 │ 1 │ 0 │ n │ n │ s │ e │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
╰─ 未传输字节数 ╰─ 有数据 ╰─ Expediteds=1, e=1= Expedited 传输nn= 未传输的字节数(0-3)- SCS =
011= 0x3
示例: Expedited Upload 0x1000sub0,返回 4 字节数据
Request: 603 [8] 40 00 10 00 00 00 00 00
│ │ │ │ │ │ └─ 填充
│ │ │ │ │ └───── 子索引 0
│ │ │ │ └───────── 索引 0x1000(小端)
│ │ │ └───────────── CCS=1 (Upload)
│ │ └───────────────── 命令字节
│ └───────────────────── COB-ID 0x603
└────────────────────────── CAN DLC=8
Response: 583 [8] 4B 00 10 00 92 01 01 00
│ │ │ │ │ │ │ └─ 数据字节 3
│ │ │ │ │ │ └───── 数据字节 2
│ │ │ │ │ └───────── 数据字节 1
│ │ │ │ └───────────── 数据字节 0
│ │ │ └───────────────── 子索引 0
│ │ └───────────────────── 索引 0x1000
│ └───────────────────────── SCS=011, e=1, s=1, n=0 (4字节数据)
└────────────────────────────── COB-ID 0x5830x4B=0100 1011= SCS=011, n=00, s=1, e=1- 数据 =
0x00010192(小端模式)= 设备类型
Expedited Download 详解
帧格式
Request(Client -> Server):
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ Byte 0 │Index │Index │SubIdx │ Data │ Data │ Data │ Data │
│ │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘字节 0 格式:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 0 │ 0 │ 1 │ n │ n │ n │ s │ e │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
╰─ CCS=0 (Download)e=1= Expedited 传输nnn= 未传输的字节数
Response(Server -> Client):
┌────────┬─────┬──────┬────────┬────────┬────────┬────────┬────────┐
│ 0x60 │Index │Index │SubIdx │ 0x00 │ 0x00 │ 0x00 │ 0x00 │
│ │ (Lo) │ (Hi) │ │ │ │ │ │
└────────┴─────┴──────┴────────┴────────┴────────┴────────┴────────┘- 字节 0 =
0x60= SCS=010(Download Response)
示例:Expedited Download 0x1005sub0,写入 COB-ID = 0x80000080
Request: 603 [8] 2B 05 10 00 80 00 00 80
│ │ │ │ │ │ │ └─ 数据字节 3
│ │ │ │ │ │ └───── 数据字节 2
│ │ │ │ │ └───────── 数据字节 1
│ │ │ │ └───────────── 数据字节 0
│ │ │ └───────────────── 子索引 0
│ │ └───────────────────── 索引 0x1005
│ └───────────────────────── CCS=0, e=1, n=00 (4字节数据)
└────────────────────────────── COB-ID 0x603
Response: 583 [8] 60 05 10 00 00 00 00 00
│ │ │ │ └─ 填充
│ │ │ └───── 子索引 0
│ │ └───────── 索引 0x1005
│ └───────────── SCS=010 (Download Response)
└───────────────── COB-ID 0x583Segmented 传输概述
详见 05-sdo-segmented-transfer.md。
总结
| 维度 | 说明 |
|---|---|
| 模型 | Client(请求)/ Server(响应) |
| COB-ID | Request=0x600+node_id, Response=0x580+node_id |
| 帧格式 | 8 字节,字节 0 为命令码 |
| Expedited | ≤4 字节,单次请求+响应 |
| Segmented | >4 字节,多段传输,Toggle 位 |
| Abort | 字节 0=0x80,后跟 4 字节错误码 |
如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
支付宝
微信