解读 78 · 协议适配:飞特系与厂商私有协议
解读对象:
microduck-replica/rl-series/scripts/hl2915_bench.py(寄存器表与帧层)+docs/新手学习文档.md§12
需要的前置:解读 64(寄存器逐段)· 解读 69(Feetech2915Io 代码地图)
换到飞特系,协议适配从"改常量"升级为"写一个新帧层";换到厂商私有协议(如宇树),
则连现成库都没有。本篇以 hl2915_bench.py 为样本讲飞特怎么接,再讲私有协议的边界在哪里。
1. 飞特磁编码协议:三件套
《新手学习文档》(docs/新手学习文档.md) §12.2 给出的帧格式只有一行:
FF FF | ID | Length | Instruction | Parameters... | Checksum(~sum)
指令码五个:PING=0x01、READ=0x02、WRITE=0x03、SYNC_READ=0x82、SYNC_WRITE=0x83。
台架脚本用三个函数把它实现完:packet()(拼帧 + 取反和)、parse()(容忍残留 0xFF,
校验不过就滑动一字节)、Bus.transact()(发一收一,0.1 s 超时计数)。一个协议栈就这么大
——744 行脚本里真正属于协议的不到 80 行。
复刻最先用的寄存器(地址均为十进制):
| 地址 | 含义 | 地址 | 含义 |
|---|---|---|---|
| 5 | ID | 56 | 当前位置(遥测块起点) |
| 6 | 波特率(0=1M) |
58 / 60 | 当前速度 / 负载 |
| 40 | 扭矩开关(128=当前位置归 2048) |
62 / 63 | 电压(0.1V)/ 温度(°C) |
| 42 / 46 / 48 | 目标位置 / 速度 / 扭矩 | 65 / 69 | 状态位段 / 电流(×6.5 mA) |
56 起连读 8 字节覆盖位置/速度/负载/电压/温度,电流与状态要读满 14 字节——正好顶替 XL330 的 124 起读块,但地址和单位不能照搬。
2. 飞特系内换型号:以"那只舵机的内存表"为准
《HL-2915 路线全流程教程》(docs/HL-2915路线全流程教程.md) §9.1 给的边际成本清单里,
第二条最容易被轻视:换一只飞特舵机,寄存器差异要以它自己的内存表为准——
比如经典 STS 系列的目标位置地址就与磁编码系列不同。逐项核对清单:
| 核对项 | 为什么 |
|---|---|
| 寄存器地址(目标位置/遥测块) | 系列不同地址会漂移,抄错就是静默写错地方 |
| 电压窗与保护寄存器(14/15/28 号) | 一条写指令的事,但不写可能上电即过压保护 |
| 插头系列 | HL 用 PH1.25-3P,与 5264/JST-EH 不通用 |
| 脚序 | 文档之间都有打架的先例(见解读 76),逐只实测 |
改完常量后重跑课 1–5(体检→遥测→闭环→拷机→SYNC),通过才算适配完成。
3. 厂商私有协议:边界在哪
- 宇树 S288:自定义 20 字节命令 / 26 字节返回 + CRC32 @ 6 Mbps,与 Dynamixel V2 完全不同;
rustypot不支持,通信层要重写。总线地址只有 0–14 共 15 个(15 为广播),
官方那块 IMU 板(ID 200)挂不上,必须改走 SPI/I²C。 - 飞特也不是全家 TTL:官方手册写明 SMS 系列走 RS-485(默认 115200)、
SHC 系列走 CANopen。"飞特 = TTL 单线"只对 STS/SCS/HL 这一支成立,换系列先查手册。 - 架构上的保险:
duck-control/src/io.rs的RobotIotrait(read/write/set_gain/set_torque/slow_sensors)
是整条接缝——换任何协议,trait 不动,新写一个实现类(如Feetech2915Io)接上去。
协议适配的工作量下限,取决于接缝设计得有多干净。
你带走的收获
- 飞特协议栈小到可以手写:拼帧、容错解析、发一收一三个函数;协议本身不是门槛,寄存器表才是。
- 换飞特系内型号,以那只舵机的内存表为准逐项核对地址与单位,改完重跑课 1–5。
- 私有协议(宇树)意味着通信层重写 + 总线地址预算重排(IMU 被挤出总线)。
- 同一厂商不同系列可能是不同物理层(飞特 SMS=RS-485、SHC=CANopen),别拿家族印象代替查手册。
RobotIotrait 是换协议不换架构的关键:接缝干净,新协议就是新增一个文件。