Microduck 新手上手指南
这是一份给硬件、电路、机械、机器人都刚入门的人的路线图。它按当前
F:\microduck 仓库写,不假定你已经买齐零件。
先给结论
你现在最适合走这条顺序:
先看懂软件和仿真
→ 识别手里的舵机
→ 用树莓派做一个安全的单舵机台架
→ 让 Radxa 只跑软件,不接未知硬件
→ 买/借一只与项目协议匹配的总线舵机做通信实验
→ 最后再做整机、电源、IMU 和步态
当前仓库能直接教你的,是运行时、通信协议、控制闭环、仿真模型、部署脚本和排错方法。
仓库当前没有完整的鸭子原理图、PCB 工程、机械 CAD 装配包或 BOM;kicad-mcp-test/
是 KiCad 路由测试夹具,不是鸭子的电子板。因此,不要把文档中提到的“官方 HAT”、
“imu_to_dxl”或外部复刻仓的图纸当成已经随本仓库提供的文件。
你的第一个目标不是“马上走起来”,而是完成四个可验证的小目标:
- 能画出控制数据流;
- 能分清 PWM 舵机和总线舵机;
- 能用万用表和限流电源安全点亮一只舵机;
- 能在没有真机的情况下跑通本仓库的测试和
robotd --fake。
1. 这是什么项目
Microduck 是一只小型双足机器人。它不是用程序逐帧写死“左脚抬起、右脚落下”,而是把
姿态和关节状态输入神经网络,让网络每个控制周期给出关节目标。
当前代码里的最重要数字:
| 数字 | 在项目里的含义 | 代码出处 |
|---|---|---|
| 15 | 5 个左腿关节 + 5 个颈/头/嘴关节 + 5 个右腿关节 | duck-control/src/model.rs |
| 14 | 步态策略控制的关节数;嘴巴被排除 | MOUTH_INDEX = 9 |
| 61 → 14 | 策略输入 61 个观测,输出 14 个动作 | docs/design/robotd-design.md |
| 50 Hz | 每 20 ms 读传感器、推理、写目标 | robotd 控制循环 |
| 1 Mbps | Dynamixel 协议 V2 总线的波特率 | BAUD_RATE |
| 200 | IMU 转接板在总线上的设备 ID | IMU_DXL_ID |
把它想成一个闭环:
身体姿态 + 关节反馈
↓
61 个观测
↓
ONNX 策略
↓
14 个关节目标
↓
舵机和机械结构
↓
真实运动再次变成反馈
当前仓库的目录地图
| 目录 | 新手先把它理解成什么 |
|---|---|
robotd/ |
主控制进程:控制循环、状态机、JSON-RPC 服务 |
duck-control/ |
硬件抽象:总线、IMU、观测、策略、安全层 |
kinematics/ |
MJCF 模型、正向运动学、头部/手部几何 |
odometry/ |
根据脚和 IMU 估计机器人位移 |
robotctl/、duckctl/ |
命令行控制工具;先不急着改 |
padd/ |
手柄输入转换成机器人意图 |
tof/、mediad/、sounds/ |
深度、相机/媒体、声音;运动闭环前可暂缓 |
configd/、btd/、updater/ |
网络、蓝牙、升级;属于系统运维层 |
docs/course/ |
面向学习的课程草稿 |
docs/deep-dive/ |
对控制、电源、协议和结构的深入笔记 |
scripts/ |
在 Radxa 上配置系统、部署和测试的脚本 |
kicad-mcp-test/ |
KiCad 测试夹具,不是鸭子的真实电路板 |
第一遍只读这四个文件:
2. 先认识你手里的东西
Radxa Zero 3W
它是 Linux 主控,适合运行本仓库的 Rust 守护进程。部署脚本针对 Radxa Zero 3 / RK3566
这一类板子,默认电机串口是 /dev/ttyS2。这块板不是舵机电源,也不是把舵机插进
USB 就能工作的“万能转接板”。
没有电机和 IMU 时,Radxa 可以先做两件事:
- 刷系统、SSH 登录、学习 Linux;
- 运行假总线模式、编译和测试软件。
真正接电机之前,先读 开发板安装。不要在 Windows 终端里直接运行
setup-board.sh;这些脚本应在目标 Radxa 上执行,或由 provision-board.sh 通过 SSH
执行。
3D 打印外壳件
它们目前只是“待验收的机械零件”,不能因为外形像鸭子就假定与项目模型完全匹配。仓库里
可核对的机械来源是 MJCF 模型,不是一套可直接
打印的 CAD 装配包。
到手后的顺序:
- 给每个零件编号并拍照;
- 用游标卡尺量舵机腔、轴孔、螺丝孔和板卡空间;
- 不装电机,先用螺丝和轴承做“干装配”;
- 记录哪些孔过紧、哪些轴线不平行;
- 只改一个尺寸,再打印一个小测试件。
不要先把未知舵机硬塞进壳体。舵机的外形、安装孔、输出轴方向和重量都会改变结构。
机器狗舵机
先不要猜型号。拍清楚铭牌、插头和线色,量一只的重量,记录:
| 观察项 | 可能是 PWM 舵机 | 可能是总线舵机 |
|---|---|---|
| 接线 | 3 线:信号、正极、地 | 3 线总线或专用插头,常有 DATA 标识 |
| 控制方式 | 一只舵机占一个 PWM 信号脚 | 多只舵机共用一条数据总线,每只用 ID 区分 |
| 反馈 | 通常不能读真实位置 | 通常能读位置、电压、温度 |
| 现在能否接本项目 | 只能做 PWM 学习台架 | 还要核对协议、电压、尺寸和控制模式 |
如果不能确认型号和额定电压,就不要上电。项目的 duck-control 明确按 Dynamixel
XL330 协议、ID 和寄存器工作;“能转”不等于“能被本项目控制”。
小智 ESP32 硬件
当前仓库没有 xiaozhi-esp32/ 目录,也没有现成的小智协议适配器。因此它现在是一个
独立语音项目,不是 Microduck 的即插即用模块。
正确的接入顺序是:先让鸭子本地动作稳定,再设计一条明确的接口,例如:
ESP32 识别“坐下” → 串口/Wi‑Fi 发一个高层命令 → robotd → 安全层 → 动作
不要让 ESP32 直接抢占舵机总线;总线必须由 robotd 单一拥有。
树莓派 Pi 2 Model B
Pi 2 可以当作低成本的 PWM 实验台或 Linux 练习机。它没有本项目所需的官方控制栈,也
不能替代 Radxa 的 ARM 主控。它没有板载 Wi‑Fi,联网通常要插网线。
Pi 2 做 PWM 实验时,只有在数据手册确认舵机额定为 5–6 V 后,才使用独立、限流的
5–6 V 电源;不能从 Pi 的 5 V 脚给多只舵机供电。总线舵机要按自己的数据手册供电,不能
套用这个电压。信号地必须共地。当前仓库没有 Pi PWM 台架脚本,所以不要把某个外部教程
里的脚本路径当成仓库文件。
3. 十个必须先懂的概念
- 舵机:带齿轮和控制器的电机总成。你给目标,它负责转到目标。
- PWM 舵机:靠脉冲宽度控制,一只一根信号线,通常没有位置反馈。
- 总线舵机:多只设备共用数据线,靠 ID 寻址,可以读回位置等状态。
- UART:串行通信接口;项目用它连接舵机总线。
- 半双工:同一根数据线既发送又接收,但同一时刻只能一个方向说话。
- IMU:陀螺仪和加速度计,用来知道身体是否倾斜、正在怎样运动。
- 观测:网络看到的数字;本项目的 alpha 策略是 61 维。
- 动作:网络输出的关节目标;本项目的步态策略输出 14 个数。
- 推理:使用已经训练好的 ONNX;不等于重新训练神经网络。
- sim2real:把仿真里的策略迁移到真机;仿真能走不代表真机一定能走。
最重要的区分是:PWM 和总线不是“便宜版与贵版”的区别,而是系统接口不同。没有
反馈的 PWM 舵机不能直接满足当前 61→14 的闭环假设;它仍然非常适合拿来学供电、脉冲和
机械负载。
4. 控制代码如何对应硬件
打开 duck-control/src/model.rs,你会看到当前运行时的硬件契约:
左腿:ID 20 21 22 23 24
颈/头/嘴:ID 30 31 32 33 34
右腿:ID 10 11 12 13 14
IMU 转接板:ID 200
这不是建议值,而是代码查找设备时使用的地址。舵机顺序也不能随意交换,因为数组下标
同时决定了关节名字、观测位置和写入目标。
这里显示的是原版 XL330/Dynamixel 路线的 ID。你现在使用 HL-2915-C001 时,现场台架和
HL 后端暂时采用另一套更容易管理的编号:第一只设为 ID=1,第二只设为 ID=2,完整 15 只
时再按关节顺序使用 ID=1..15,IMU 仍保留 ID=200。不要把上面的 10/20/30 直接写给
HL-2915;也不要在只有两只舵机时启动要求 15 只设备的 robotd。
duck-control/src/bus.rs 展示了一次控制周期做什么:
一次 sync_read:读 IMU + 15 只舵机
一次策略推理:观测 → ONNX → 14 个动作
一次 sync_write:写 15 个目标(嘴巴位置单独处理)
每秒一次:读电压和温度
robotd 还规定了三个很重要的安全行为:
- 启动不会自动让机器人突然运动;
- 只有安全层持有真正的电机写入句柄;
- NaN/无穷值会被拒绝,目标会被限制在执行器范围内。
这就是为什么你的 ESP32、手柄、浏览器和语音程序都应该发高层意图,而不是自己向
串口写舵机包。阅读顺序建议是:
duck-control/src/model.rs:设备、ID、HOME 姿态;duck-control/src/bus.rs:总线读写;robotd/src/control.rs:观测、策略、目标;duck-control/src/safety.rs:最后一道安全边界;docs/design/robotd-design.md:把上述文件串成一张图。
5. 小白如何看懂电路图
5.1 先接受当前仓库的限制
当前仓库没有 Microduck 完整的原理图 PDF。你能可靠读取的是软件对硬件的接口假设:
Radxa UART (/dev/ttyS2)
│ 1 Mbps,Dynamixel Protocol V2
▼
单线 TTL 半双工总线
├─ IMU 板,ID 200
└─ 15 个总线舵机,ID 10–14 / 20–24 / 30–34
供电部分不能从 Rust 代码“脑补”出来。代码能读到舵机报告的总线电压,但电池、保险丝、
降压器、插座和 PCB 具体怎么连,必须以你手里真实的板卡和舵机数据手册为准。
5.2 原理图与 PCB 图的区别
- 原理图回答“哪些引脚电气相连”;
- PCB 布局图回答“这些器件在板上怎么摆、线怎么走”;
- 3D 图回答“装进去会不会碰撞”;
- 接线表回答“线从哪个连接器的哪个脚到哪个脚”。
不要把原理图里的线条位置当成真实物理走线;同名网络(例如 GND、SDA、SCL、
UART_TX)才是电气连接的关键。
5.3 通用五步读图法
拿到任何一张图,按这个顺序:
- 找电源入口:输入电压是多少,正负极在哪里;
- 找 GND:所有模块是否有共同参考地;
- 找主控:哪颗 MCU/SoC,电源脚是否有去耦电容;
- 沿信号走:UART、I²C、SPI、PWM 分别连到谁;
- 看保护:保险丝、反接保护、TVS、限流和急停在哪里。
对每个连接器写一张小卡片:
连接器 J?
1: GND
2: 电源(多少伏,谁提供)
3: DATA / TX / SDA(方向是什么)
4: 未使用或保留
这样比一上来认电阻、电容的符号更有效。先知道“电从哪来、数据往哪走”,再研究元件值。
5.4 你第一次该画的草图
先不要画 PCB,只用纸画四个框:
[电池/电源] ──> [舵机供电总线] ──> [15 个舵机]
▲
│ DATA(半双工)
[Radxa UART] ──────────┘
│
├─ [IMU 总线设备 ID 200]
└─ [上层软件、网络、语音命令]
在图旁边标出三个“未知项”:舵机额定电压、总线转接/方向切换电路、Radxa 与电源的共地
方式。未知项没有数据手册前不要填数字;这正是工程记录的一部分。
深入阅读顺序:
这些是解释性笔记,不是你当前硬件的接线批准书。真正上电仍以实物手册和万用表测量为准。
6. 小白如何看懂和设计结构
6.1 先看运动链,再看外壳
打开 robot_walk.xml,先只找 body、joint、
inertial 三类标签:
trunk_base
├─ 左腿:left_hip_yaw → left_hip_roll → left_hip_pitch → left_knee → left_ankle
├─ 颈头:neck_pitch → head_pitch → head_yaw → head_roll
└─ 右腿:right_hip_yaw → right_hip_roll → right_hip_pitch → right_knee → right_ankle
body是刚体层级:谁挂在谁上面;joint是相对运动:绕哪根轴、允许转多少;inertial是质量和转动惯量:零件多重、重心在哪里;site是传感器或脚等参考点。
这份 MJCF 是仿真模型,不是可直接打印的 CAD。它能告诉你运动链、坐标系、质量和关节
范围,不能告诉你螺丝怎么拧、打印件能否承受冲击。
6.2 结构设计的最小方法
每做一个零件,按这七问检查:
- 它固定谁、允许谁动?
- 旋转轴线在哪里?左右是否对称?
- 舵机输出轴和外壳是否有硬限位?
- 螺丝受的是拉力、剪切还是反复振动?
- 轴承是否承担了侧向载荷,而不是让舵机输出轴硬扛?
- 电线有没有弯折半径、夹线和可拆空间?
- 维护时能不能只拆一层,而不是拆完整只鸭子?
6.3 你的打印件验收流程
不要直接打印或装完整机器。先做一个“最小闭环”:
量舵机 → 量打印腔体 → 空装 → 单关节手动活动 → 单舵机低负载 → 再扩大
验收记录至少包括:
| 项目 | 记录什么 |
|---|---|
| 外形 | 长、宽、高,是否翘曲 |
| 孔位 | 螺丝能否顺利穿过,是否需要修孔 |
| 轴线 | 两个关节轴是否平行/垂直 |
| 刚度 | 手捏、轻推时是否明显变形 |
| 走线 | 线会不会碰转动件或被夹住 |
| 维护 | 能否取出舵机、电池和控制板 |
打印公差没有一个对所有打印机都正确的数字。先打测试片,再根据测量结果调整;不要把
网上的“统一补偿 0.2 mm”直接套用。
6.4 换舵机为什么会牵动结构和训练
舵机变化会同时影响:
- 安装孔和外壳尺寸;
- 质量、重心和腿部惯量;
- 电压、电流、齿隙和控制增益;
- 仿真的执行器模型和最终 ONNX 策略。
所以机器狗舵机最多先用来学台架。不要期待“把同样数量的舵机塞进去”就能直接运行官方
步态策略。
7. 现在就能做的学习路线
第 0 阶段:不通电,建立地图
按下面顺序读,每篇只写三句话笔记:它解决什么问题、输入是什么、输出是什么。
验收标准:你能不看文档解释“摇杆为什么不是直接控制某一只腿”。
第 1 阶段:在电脑上验证软件
先确认 Rust 版本满足仓库的 rust-version = "1.89",再在开发机上运行:
cargo test
cargo test -p kinematics
如果报 requires rustc 1.89,不是项目代码坏了,而是本机工具链太旧;先用 rustup
安装 1.89 或更新版本,再重跑。
这两步不需要 Radxa、不需要舵机,也不需要电池。然后阅读 测试和仿真部署说明。
如果想观察运行时而不接总线,可以编译后使用 robotd --fake;它的意义是“没有总线、
没有真实机器人”,不是模拟一个完整的物理世界。命令帮助以当前代码为准:
cargo run -p robotd -- --help
验收标准:测试通过,并能说清“假总线测试”和“MuJoCo 物理仿真”的区别。
第 2 阶段:用 Pi 2 学一只 PWM 舵机
只有在你确认舵机型号和额定电压后再做:
- Pi 2 刷 Raspberry Pi OS,插网线,先只练 SSH;
- 准备独立的、带限流的 5–6 V 电源;
- 信号线接一个 GPIO,电源正负接外部电源,Pi 与外部电源共地;
- 只接一只、只做小角度动作;
- 观察堵转、电压下跌、重启和发热。
这阶段的学习目标不是做鸭子,而是亲手体会:PWM 舵机通常没有真实位置反馈,外力把轴
掰走后,程序并不知道。
验收标准:能安全地让一只舵机来回小角度运动,能解释为什么电源不能取自 Pi 的 5 V 脚。
第 3 阶段:让 Radxa 只跑软件
在 Radxa 上按 install-dev.md 做系统安装,重点观察:
- 开发机负责编译,板子负责运行;
/dev/ttyS2是项目默认电机 UART;serial-getty@ttyS2不能占着电机串口;- 设备树 overlay 和 ONNX Runtime 属于板级前置条件;
- 任何脚本都要看清“在开发机执行”还是“在 Radxa 执行”。
没有总线硬件时,先不要追求 robotd 健康通过;使用 --fake 和单元测试学习软件路径。
第 4 阶段:一只总线舵机的实验
如果你的机器狗舵机经确认是 Dynamixel/Feetech 一类总线舵机,再购买或借一个匹配的 USB
调试器,并且只接一只。验证顺序:
- 查数据手册的额定电压、协议、电平和默认波特率;
- 独立给舵机供电,调试器只负责通信;
- 万用表测电源正负和空载电压;
- 扫描、读取位置、电压、温度;
- 只有确认通信稳定后,才改 ID;
- 改 ID 后断电、贴标签、回读确认。
对于当前项目,代码使用 1 Mbps、Dynamixel Protocol V2 和分段 ID。Feetech 或其它协议
需要适配层,不能只改一个 ID 就当成兼容。
第 5 阶段:整机前的硬件门槛
满足以下条件前,不要上官方步态:
- 15 个执行器的型号、电压、通信协议和安装孔都已确认;
- 有可靠的电源、保险/限流、急断电和共同地;
- 有 IMU 总线设备或明确的替代方案;
- 结构干装配无卡滞,线不会被夹断;
- 已完成单舵机、少量舵机、悬空整机的逐级测试;
- 你知道当前 ONNX 是为哪一组执行器和哪一套关节顺序训练的。
8. 第一个月计划
第 1 周:只学习和盘点
- [ ] 读完本指南第 1–5 节;
- [ ] 给所有舵机拍照、称重、记录型号和线序;
- [ ] 列出打印件清单并给每个零件编号;
- [ ] 浏览器跑一次官方仿真;
- [ ] 在开发机运行
cargo test; - [ ] 用纸画出“Radxa → 总线 → 舵机 + IMU”的框图。
第 2 周:Pi 2 和结构干装
- [ ] 如果是 PWM 舵机,完成单舵机安全台架;
- [ ] 用卡尺测打印件和舵机腔体;
- [ ] 不通电完成一条腿或一个关节的干装;
- [ ] 记录一个明确问题,不同时改十个变量。
第 3 周:Radxa 软件
- [ ] 刷系统并 SSH 登录;
- [ ] 阅读
provision-board.sh和setup-board.sh的执行位置; - [ ] 运行开发板上的
robotd --fake或在开发机上运行帮助/测试; - [ ] 能查看 systemd 状态和 journal 日志。
第 4 周:决定是否进入总线阶段
- [ ] 确认机器狗舵机究竟是不是总线舵机;
- [ ] 只为一只样品准备匹配调试器和电源;
- [ ] 写一页“协议、电压、尺寸、重量、反馈、风险”对照表;
- [ ] 如果无法确认,停在这里,不要批量采购。
9. 上电和调试安全卡
每次上电前逐项打勾:
- [ ] 已知道舵机的型号和额定电压;
- [ ] 电源正负没有接反;
- [ ] 电源对地没有短路;
- [ ] 舵机电源没有取自 Radxa、Pi 或 USB;
- [ ] 调试器和舵机电源已经共地;
- [ ] 结构没有把输出轴顶死;
- [ ] 伸手能立即切断电源;
- [ ] 第一次测试在软垫上、低负载、远离桌边;
- [ ] 修改线缆前已断电;
- [ ] 总线只由一个程序拥有。
出现以下任意现象,立刻断电:异常嗡鸣、快速发热、反复重启、冒烟、明显卡死、电源压降
过大。先断电,再查线;不要带电“试一下”。
robotd 正在运行时,不要同时用另一个程序或 USB 调试器打开同一条电机总线。需要做底层
扫描时,先停掉占用总线的服务,并确认没有 serial-getty 抢占 /dev/ttyS2。
10. 常见误区
| 误区 | 正确理解 |
|---|---|
| “Radxa 有 GPIO,所以能直接带舵机” | GPIO 只表示信号能力,不代表电源、电平、协议和保护都匹配 |
| “舵机能转,就能跑官方模型” | 还要匹配反馈、协议、尺寸、质量、齿隙、增益和电压 |
| “3D 打印件外形一样就能装” | 轴线、孔位、限位、刚度和走线空间都要实测 |
| “先把 15 只都接上,再慢慢改 ID” | 出厂同 ID 的总线设备会互相抢答;总线阶段一次只接一只未配置设备 |
| “把 ESP32 直接接到舵机总线更简单” | 会破坏单一总线所有者和安全层;ESP32 应发高层命令 |
| “仿真里能走,真机只要调个速度” | 真机还会遇到电压、延迟、摩擦、回差、装配误差和跌倒 |
| “先买齐再研究” | 先做便宜、可逆的验证;每个采购都由上一个门槛解锁 |
11. 下一步该读什么
| 目的 | 当前仓库里的文件 |
|---|---|
| 看全局 | README、architecture.md |
| 学控制闭环 | robotd-design.md、第 04 课 |
| 学电路思路 | 电控架构、电源树、半双工总线 |
| 学协议和 ID | 舵机协议、ID 与模式 |
| 学结构 | MJCF 模型、kinematics/src/ |
| 学 Radxa | 开发板安装、手工安装 |
| 学日常命令 | robotctl cheat sheet |
| 学仿真/训练 | 进阶学习文档、学习工具(工作区文件) |
| 评估更便宜舵机 | 低成本舵机替换决策表(工作区文件) |
| 学排错 | 第 07 课、testbench 验证 |
读代码时的一条捷径
遇到一个新模块,不要从第一行顺读。先回答四个问题:
- 它读什么输入?
- 它输出给谁?
- 它是否能直接写电机?
- 出错时是停、保持、降级,还是继续运行?
能回答这四个问题,就已经是在读机器人系统,而不只是读 Rust 语法。
最后记住:你现在不需要同时学会电路、机械、Rust、Linux 和强化学习。每次只验证一个小
闭环,并记录“接了什么、测到了什么、下一步是什么”。这比一次打印整机、一次接满 15
只舵机更快,也更安全。
12. 已确定使用 HL-2915-C001 时的复刻路线
这一节专门针对飞特 HL-2915-C001。它不是 XL330 的直接替换件,而是一套新的执行器适配。
装机主线更新:当前 15 只装机舵机是 4–8.4 V 的
HD-1910-C001(2S 母线友好),不是
本节的 12 V HL-2915。接线、只读探针、官方关节 ID 表与标定门控见
URT2 + HD-1910 接线、组装与测试指南;
仿真侧的参数迁移与训练见HD1910 仿真迁移与 PPO 训练教程。
本节的"协议适配层 + 逐任务验收"方法两者通用,但电压、线序、模式和寄存器不能互套。
12.1 先把型号资料钉死
下面是根据飞特 HL-2915-C001 官方产品页、2026-01-18 规格书和磁编码内存表整理的工作表。
实物标签和随货最新版手册仍然优先;同系列其他型号不能直接替代 C001 的电压、电流或寄存器单位。
官方 HLS 产品列表把 C001 的默认 Mode 0 列为 0–360°绝对位置控制,因此它不是普通的连续旋转
PWM 舵机;但本项目仍需要以随货手册确认位置模式、回读单位和目标位置地址。确认前只运行
Ping/只读命令,不要运行 --move-center 或摆锤记录器。如果实物固件与资料不一致,先停在协议
适配层,不能靠软件把它伪装成位置舵机。
| 项目 | HL-2915-C001 |
|---|---|
| 工作电压 | 9–14 V,典型 12 V |
| 堵转扭矩 | 14.2 kg·cm @ 12 V |
| 空载电流 | 160 mA @ 12 V |
| 堵转电流 | 1.5 A @ 12 V |
| 额定电流 | 500 mA @ 12 V |
| 官方过热保护 | 规格书写 80 °C;内存表的默认温度限制可能不同,第一次台架仍采用更保守的软件门槛 |
| 外形 | 34 × 20 × 23 mm |
| 重量 | 27.8 ± 2 g |
| 输出轴 | 25T,外径 4.95 mm |
| 位置 | 0–4095,中心 2048,0.088°/步 |
| 接头 | PH1.25-3P:1=GND,2=Vcc,3=Signal/TTL |
| 默认 ID | 1 |
| 默认波特率 | 1 Mbps |
| 信号电平 | 高电平 2–5 V,低电平 0–0.45 V |
资料入口:
- HL-2915-C001 产品页
- 飞特 HLS 串行舵机列表(含 Mode 0 说明)
- 官方规格书 PDF
- 磁编码版本协议手册
- 磁编码版本内存表
- Pollen Robotics 官方 Robot HAT 工程
先分清两颗 IMU:官方 Robot HAT 上的 BMI088 走 I²C,当前步态不用它;控制闭环使用另一块
imu_to_dxl 板,通过 Dynamixel Protocol v2 占用 ID 200。看到 BMI088 不代表步态 IMU 已通过。
如果暂时只有 imu_to_dxl、还没有 15 只舵机,可先用仓库里的 imu_probe 单独验收 ID=200:
cargo run -p duck-control --bin imu_probe -- /dev/ttyUSB0 --watch-seconds 10
它只读取 IMU,不启动 robotd,也不会给舵机上扭矩。
两只 HL-2915 和 IMU 已经接到同一个半双工串口后,用混合探针验证协议切换:
cargo run -p duck-control --bin hl2915_mixed_probe -- /dev/ttyUSB0 1 2 --watch-seconds 60
最后一行必须同时满足 samples>=25、errors=0、imu_ready=true、
0 <= max_stale_run <= stale_imu < samples、max_stale_run < 25,以及四项舵机故障计数都是 0;
旧日志没有 max_stale_run 时必须用当前探针重跑,不能人工补字段;
只要出现欠压、过热、接近堵转或舵机状态故障,混合探针也会返回失败,不可继续启动整机。
这仍然是只读台架程序;完整 robotd 需要 15 只 HL-2915 和完成关节标定。
第一次接线应以 HL-2915-C001 的产品参数表、实物标签和卖家确认结果为准,先用 12 V 限流电源,
不要照抄通用接口图,也不要因为同系列型号写了其他电压就擅自放宽保护范围。仓库探针里的
9–14 V、55 °C、1.4 A 是保守的项目台架门槛:55 °C 低于官方过热保护值,1.4 A 低于约 1.5 A
堵转电流,目的是在第一次空载测试时宁可误停也不把舵机推到保护边缘。确认到实物固件和测试数据后,
再单独修改门槛和测试。
12.2 通信寄存器速查
飞特协议包格式是:
FF FF | ID | Length | Instruction | Parameters... | Checksum
校验:Checksum = ~(ID + Length + Instruction + Parameters) & 0xFF。
HL-2915-C001 磁编码内存表中,复刻最先需要这些地址:
| 地址(十进制) | 含义 | 长度 | 用途 |
|---|---|---|---|
| 5 | ID | 1 | 逐只设置唯一 ID |
| 6 | Baud Rate | 1 | 0=1 Mbps,其余值按内存表映射 |
| 40 | Torque Enable | 1 | 0=关闭,1=打开,128=当前位置设为 2048 |
| 42 | Goal Position | 2 | 目标位置 |
| 46 | Goal Speed | 2 | 目标速度 |
| 48 | Goal Torque | 2 | 目标扭矩 |
| 56 | Present Position | 2 | 实际位置 |
| 58 | Present Speed | 2 | 实际速度;HLS 内存表按约 0.732 RPM/计数换算,收到的型号内存表优先 |
| 60 | Present Load | 2 | 实际负载;HLS 磁编码表通常用 bit10 表示方向、bit0..9 表示幅值,原始值不要直接当百分比 |
| 62 | Present Voltage | 1 | 单位 0.1 V |
| 63 | Present Temperature | 1 | 单位 °C |
| 65 | Status | 1 | 过载、温度、电压、舵机异常 |
| 66 | Moving | 1 | 是否运动 |
| 69 | Present Current | 2 | 单位约 6.5 mA/计数 |
磁编码协议支持:PING=0x01、READ=0x02、WRITE=0x03、SYNC_READ=0x82、
SYNC_WRITE=0x83。协议示例用从地址 56 读取 8 字节,一次拿到位置、速度、负载、电压、
温度。这正好可以替代当前项目 XL330 的连续寄存器读取,但地址和数据单位不能照搬。
12.3 复刻任务清单
第一次实际通电前,先完整阅读URT2 + HL-2915 接线、组装与测试指南,
实际操作时使用两只舵机现场验收表(工作区文件),边操作边记录电源、ID、
温升、通信错误和 CSV 路径;不要只保存终端里最后一行输出。
Task HL2915-001:单舵机资料确认
- Goal:确定电压、插头、默认 ID、波特率、协议和寄存器表。
- Files:本节资料链接;不改代码。
- Action:保存官方规格书、协议手册、内存表;给舵机和插头拍照。
- Why:接错 PH1.25-3P 的电源脚会损坏舵机或调试器。
- Verification:能写出
1=GND, 2=Vcc, 3=Signal,并能指出地址 42、56、62、63、69。 - Expected result:只买 1 只样品,不批量采购。
Task HL2915-002:单舵机台架通信
- Goal:证明一只舵机可稳定读写。
- Files:新增测试脚本或临时工具,不碰行走策略。
- Action:用 FE-URT-2 或兼容半双工 TTL 调试器;URT2 用 USB-C 通信、舵机用独立 12 V 限流
电源;完成 PING、读位置、
写目标位置、读电压和温度。 - Why:先排除供电、接线、协议问题。
- Verification:连续读写 10 分钟无随机丢包;低速小角度移动;扭矩可关闭。
- Expected result:保存一份原始收发日志。
Task HL2915-003:替换底层总线驱动
- Goal:让项目的上层控制循环能使用 HL-2915-C001。
- Files:保留 RobotIo 接口,使用
Hl2915RobotIo;不要修改
Xl330Controller来冒充 HL-2915。 - Action:实现读写、扭矩、批量读写、位置单位转换、温度/电压/电流解析、错误状态。
- Why:当前 bus.rs 按 Dynamixel XL330 地址和协议实现。
- Verification:1 只 → 3 只 → 15 只,逐级通过 PING、SYNC_READ、SYNC_WRITE。
- Expected result:50 Hz 控制循环可以稳定运行,只有一个程序占用串口。
Task HL2915-004:重做供电和线束
- Goal:提供安全的 12 V 舵机电源和 5 V Radxa 电源。
- Files:电源树、线束表;暂不改策略代码。
- Action:12 V 电池/电源 → 保险丝/急停 → 舵机总线;另一路 12 V → 5 V 降压 → Radxa。
15 只舵机的理论堵转峰值按15 × 1.5 A = 22.5 A估算,连续电流不能按这个数硬灌。 - Why:原项目的 2S 6.6–8.2 V 电池假设不适用于 C001。
- Verification:空载、单腿和整机分别测电压下陷、线缆温升、舵机温度。
- Expected result:不再使用原 XL330 的电池阈值和直连方式。
Task HL2915-005:打印一个关节适配件
- Goal:验证一只 HL-2915 能安全安装。
- Files:原始 MJCF 只作为关节位置和轴线参考。
- Action:按官方外形图重新画支架;保留输出轴中心和原关节轴线;使用 25T/4.95 mm 的匹配舵盘;
给线缆留弯曲空间;增加硬限位。 - Why:舵机外形接近 XL330,但安装孔、输出轴、侧向载荷和线缆位置不能想当然。
- Verification:手动全行程不干涉;输出轴不承受不必要的弯矩;支架无明显变形。
- Expected result:单关节可低速往复,不碰壳、不卡死。
Task HL2915-006:一条腿和动力学辨识
- Goal:测量真实的速度、延迟、回差、电流和温升。
- Files:台架日志、MJCF/BAM 执行器参数。
- Action:先做单关节,再做 3 只舵机的一条腿;记录目标位置、实际位置、速度、电流、温度、
电压;重新填写质量、惯量、摩擦、回差、延迟和电压范围。 - Why:HL-2915-C001 每只约 27.8 g,15 只约 417 g,仅舵机就比原 15×18 g 多约 147 g。
- Verification:仿真阶跃响应和实物阶跃响应量级接近;一条腿能稳定保持站立位置。
- Expected result:形成 HL-2915 专用执行器参数,不能继续使用 XL330 的 BAM/ONNX 假设。
Task HL2915-007:整机、悬空、落地
- Goal:安全地从整机通信走到行走。
- Files:策略元数据中的
robot.servos、供电阈值、训练参数。 - Action:15 只无负载总线测试 → 悬空开扭矩 → 软垫上静态站立 → 手工小步态 → 重新训练后的策略。
- Why:换舵机会同时改变重量、扭矩、速度、回差、延迟和电压模型。
- Verification:每一步都能断电、回读状态、查最高温度和最高电流。
- Expected result:只使用重新辨识和重新训练过的 HL-2915 模型。
12.4 现有硬件的分工
- Radxa Zero 3W:唯一的实时主控,运行总线驱动、IMU、控制循环和策略。
- 小智 ESP32:语音、按钮、联网和高层命令,不直接控制舵机。
- 树莓派 Pi 2:日志、网页、远程调试,可暂时不用。
- 机器狗舵机:只用于练习和单独台架测试,不与 HL-2915-C001 混接。
第一步只做 HL2915-001:拿到官方内存表,买一只舵机和调试器,完成单舵机 PING/读写。
没有这个结果,不进入打印整机、批量买舵机和训练策略。
13. 两只 HL-2915-C001 的实际落地步骤(代码已放入仓库)
本仓库现在已经有一个“只做台架验证”的最小程序:
- HL-2915 驱动封装(工作区文件):复用
rustypot已验证的 Feetech 协议 v1,
按 HL-2915 的寄存器地址读写;这里没有把它伪装成 XL330。 - 台架探测器(工作区文件):默认只 Ping 和读取状态,不会主动运动。
- IMU 探测器(工作区文件):只读 ID=200 的协议 v2 IMU。
- 混合协议探测器(工作区文件):只读两只 HL-2915 + IMU,验证同一串口的协议切换。
- 原始数据记录器(工作区文件):只读采集 CSV,给后续标定和 BAM 参数辨识留证据。
- BAM 摆锤记录器(工作区文件):在独立摆锤台架上,以受限幅度采集可直接交给 BAM 的 JSON;它会开扭矩,不能当作只读工具。
13.1 先准备硬件
你至少需要:两只 HL-2915-C001、一个支持单线半双工 TTL 的 Feetech 调试器(本项目使用官方 FE-URT-2/FE-URT2-C001)、
一个可限流的 12 V 电源、万用表和一根 USB 线。Radxa 的 5 V 电源不能直接接到舵机 Vcc,
树莓派和小智 ESP32 也先不要接舵机总线。
URT2 的 USB-C 只负责给调试器逻辑供电并建立 COM 口;舵机电源接 TTL 侧 G/V1,HL-2915
接 TTL-Bus,不要接 RS485 侧 V2。完整接线和 FD 首次调试顺序见
两只舵机现场验收表(工作区文件)。
舵机 PH1.25-3P 的线序按官方资料核对:
1 = GND(电源负极、调试器 GND、Radxa GND 共地)
2 = Vcc(先用 12 V,限流)
3 = Signal/TTL(调试器的半双工数据线)
两只新舵机通常都为 ID=1。因此,第一次不能把两只同时接上,否则它们会同时回答同一个
ID,通信必然冲突。
13.2 在电脑上先测第一只
在仓库根目录打开 PowerShell。把 COM3 换成调试器在设备管理器显示的端口:
Get-CimInstance Win32_SerialPort | Format-Table DeviceID,Caption
cargo test -p duck-control hl2915
cargo check -p duck-control --bin hl2915_probe
cargo run -p duck-control --bin hl2915_probe -- COM3 1
最后一条命令的默认行为是:打开 1 Mbps、Ping ID 1、读取位置/速度/负载/状态/运动标志/电流/电压/温度,然后退出。
看到 响应=[1] 才算通信链路成立。若报“没有响应”,先断电,再按 GND/Vcc/Signal、12 V、ID、
半双工转接器顺序排查;不要先改程序。
13.3 给第二只改成 ID=2
只接第二只舵机(第一只必须断开),仍然使用它出厂的 ID=1:
cargo run -p duck-control --bin hl2915_probe -- COM3 1 --set-id 2
程序只在显式写出 --set-id 时改 EEPROM。看到成功提示后,给舵机断电再上电,然后验证:
cargo run -p duck-control --bin hl2915_probe -- COM3 2
必须看到 响应=[2]。如果没有,停止继续接线,重新只接这一只并检查供电;不要用广播命令“碰运气”。
13.4 两只一起做只读验证
确认一只 ID=1、另一只 ID=2 后,才把两只并联到同一条 12 V/GND/Signal 总线:
cargo run -p duck-control --bin hl2915_probe -- COM3 1 2
预期输出中 响应=[1, 2],并各有一行状态。这个步骤只读,不会让两只舵机转动;建议先连续运行
几次并记录电压和温度。
要做第一轮稳定性验收,可以让程序连续只读 10 分钟:
cargo run -p duck-control --bin hl2915_probe -- COM3 1 2 --watch-seconds 600
它每 100 ms 读一次,遇到一次读错误会记录并继续,结束时以非零状态退出;因此可以把它当作
“两只舵机通信是否稳定”的自动门槛。没有错误时应看到 errors=0,并记录 min_voltage 和
max_temperature;如果出现非零 status、电压不在 9–14 V、温度达到 55°C 或电流达到约
1.4 A,程序也会以非零状态退出。这样“能通信”不会被误判成“舵机健康”。
如果要保存后续标定/重训用的原始数据,使用只读记录器:
New-Item -ItemType Directory -Force .\artifacts | Out-Null
cargo run -p duck-control --bin hl2915_record -- COM3 1 2 `
--seconds 600 --output .\artifacts\hl2915-bench.csv --hz 50
CSV 每个采样点为每只舵机写一行,字段包括时间、位置、速度、负载、状态、运动标志、电流、电压和温度。
它不会写寄存器、不会开扭矩、不会主动运动;出现任何通信错误时以非零状态退出,
不能把不完整的日志当成辨识数据。
13.5 第一次运动只做“回中”
先把舵盘拆下或让输出轴完全悬空,确认周围没有夹手和撞壳风险。然后才执行:
cargo run -p duck-control --bin hl2915_probe -- COM3 1 2 --move-center
程序会打开扭矩、给两只写入原始位置 2048、等待 1 秒、读取状态、关闭扭矩。位置 2048 是协议定义的
中心,不代表已经对齐你的机械零位;机械装配完成后还要单独记录“舵机中心 ↔ 关节零位”的偏移。
13.6 再装到打印件,顺序不要跳
- 不通电,把一只舵机放进打印支架,确认 34×20×23 mm 外形、安装孔、线缆弯曲半径和 25T 舵盘都不干涉。
- 手动转动关节全行程,确认先碰到机械硬限位,而不是舵机齿轮或线缆先受力。
- 只装一只,悬空运行
--move-center,观察支架变形、异响和线缆拉扯。 - 两只装好后仍悬空测试;再放到软垫上,只给静态小角度目标。
- 在这五步都通过前,不接 Radxa 控制循环,不写行走策略。
13.7 这次代码验证了什么、没有验证什么
已经在无硬件环境自动验证:8 字节状态的小端解析、短报文拒绝、角度和原始位置换算、ID 唯一性、
以及二进制能编译。每次改代码后重复:
cargo test -p duck-control hl2915
cargo check -p duck-control --bin hl2915_probe
真实舵机的供电压降、丢包率、温升、回差、安装强度和“是否真的转到正确机械角度”,只能按 13.2–13.6
的台架顺序现场验证。仓库现在已有显式选择的 HL-2915 RobotIo:它用协议 v1 访问舵机,用协议 v2
访问 ID=200 的 IMU;原 bus.rs 仍只负责 XL330。混合后端尚未经过实体 HAT/IMU
验证,而且默认零位 2048、方向 +1 只是台架起点,因此现在仍不能运行行走策略。
13.8 通过后再搬到 Radxa Zero 3W
电脑上的 COM3 只是第一次调试用的端口。Radxa 上通常会显示成 /dev/ttyUSB0 或 /dev/ttyACM0,
程序本身不需要改:
sudo apt update
sudo apt install -y build-essential pkg-config
# 按仓库要求准备 Rust 1.89;然后把仓库放到 Radxa,例如 ~/microduck
cd ~/microduck
cargo test -p duck-control hl2915
cargo build --release -p duck-control --bin hl2915_probe
ls /dev/ttyUSB* /dev/ttyACM*
./target/release/hl2915_probe /dev/ttyUSB0 1
第一次在 Radxa 上仍然只接一只、只读。等 1 和 2 都能独立 Ping,再做两只并联验证;小智 ESP32、
Pi 2 和行走策略继续保持断开,避免多个程序同时抢同一条半双工总线。
Radxa、官方 Robot HAT 和相机到位后,依次生成三份互不替代的证据:
python tools/microduck_learning/board_readonly_report.py --json-out artifacts/board-readonly-report.json
python tools/microduck_learning/hat_smoke.py --run --confirm-official-hat --json-out artifacts/hat-smoke-first.json
python tools/microduck_learning/media_smoke.py --run --frames 60 --json-out artifacts/media-smoke.json
HAT 命令会录两秒临时音频并播放低音量提示音,退出后删除音频内容。确认第一次确实听到声音,
才重跑并加 --confirm-audible --json-out artifacts/hat-smoke.json。三个 JSON 缺任何一个,S6 都不会通过。
13.9 为 HL-2915 重新辨识 BAM 执行器
只读 CSV 只能回答“舵机现在是否健康”,不能得到执行器的电机常数、等效惯量、摩擦和延迟。
这些参数必须在独立摆锤台架上重新采集;不能把 XL330 的 BAM M6 参数直接套给 HL-2915。
台架要求:舵机刚性固定、摆臂和配重质量用秤测量、舵机轴到配重质心距离用卡尺测量,摆臂竖直向下
作为零位,四周无遮挡,手边有断电开关。第一次只用 ±10°、P=16;没有通过小幅度测试前不要增大幅度。
程序会显式写入 P/I/D、打开扭矩、采集轨迹,结束时自动关闭扭矩;它不是 hl2915_record 那种只读程序。
New-Item -ItemType Directory -Force .\artifacts\bam\raw | Out-Null
cargo +1.89.0 run -p duck-control --bin hl2915_bam_record -- `
COM3 1 `
--mass-kg 0.050 `
--arm-mass-kg 0.010 `
--arm-length-m 0.100 `
--center-raw 2048 `
--direction 1 `
--kp 16 `
--vin 12 `
--amplitude-deg 10 `
--duration-seconds 6 `
--hz 100 `
--output .\artifacts\bam\raw\kp16-a10.json `
--confirm-motion
先分别用 --kp 8、--kp 16、--kp 32 采集至少三份小幅度日志;每次改变 P 值都要在文件名和记录表中写清楚。
如果要做更可靠的拟合,再重复 --amplitude-deg 20,但只有摆锤不撞任何物体、温度和电流都正常时才允许。
在 Linux/WSL2 的 microduck_rl 固定 commit 中处理日志。bam.process 会把不规则采样插值到固定时间步,
HL-2915 需要本仓库的轻量 BAM 适配入口;先用少量 trial 验证流程,再做正式拟合:
validate_bam_log.py 会拒绝 motor 不是 hl2915 的日志;其他候选舵机必须单独建立型号记录和拟合流程,不能混入 C001 数据。
python tools/microduck_learning/validate_bam_log.py \
artifacts/bam/raw/kp16-a10.json
cd ~/microduck_rl
# 基础 uv sync 不装 BAM 拟合器的可选依赖;只需在最终 sync 后补装一次
uv pip install --python .venv/bin/python "optuna>=4,<5" "wandb>=0.24,<0.25" cmaes
uv run python -m bam.process \
--raw /mnt/f/microduck/artifacts/bam/raw \
--logdir /mnt/f/microduck/artifacts/bam/processed \
--dt 0.01
uv run python /mnt/f/microduck/tools/microduck_learning/fit_hl2915_bam.py \
--error-gain <实测值> \
--logdir /mnt/f/microduck/artifacts/bam/processed \
--output /mnt/f/microduck/artifacts/bam/hl2915-m6.json \
--method cmaes --model m6 \
--trials 2000 --workers 1
uv run python /mnt/f/microduck/tools/microduck_learning/check_bam_model.py \
/mnt/f/microduck/artifacts/bam/hl2915-m6.json \
--json-out /mnt/f/microduck/artifacts/bam-model-hl2915-m6.json
uv run python -c "from bam.model import load_model; print(load_model('/mnt/f/microduck/artifacts/bam/hl2915-m6.json').get_parameters())"
--error-gain 是 HL-2915 固件中“位置误差 × P 增益 → PWM 占空比”的换算,必须来自示波器实测
或飞特书面资料;不能抄 STS3215 的数值。适配入口以 C001 的 110 RPM、9.3 kgf·cm/A 作为可优化
起点,不把它们当成拟合结果。不要手改上游训练源码;本仓库的入口会注入 fitted JSON 和
HL-2915 的 12V/增益参数:
export MICRODUCK_RL_DIR=/home/<user>/microduck_rl
export MICRODUCK_BAM_JSON=/mnt/f/microduck/artifacts/bam/hl2915-m6.json
bash /mnt/f/microduck/tools/microduck_learning/run_5_iteration_smoke.sh
5 轮结束后会生成 BAM 合同、ONNX 合同和 training-lineage-lesson-01-repro.json。
其中 purpose=smoke 的意思只是“管线能跑”,不能证明会走。等阶跃记录测出端到端延迟和电压
下陷后,再逐步调整训练参数,完成正式训练、仿真回放和最终 ONNX 导出。随后封存候选模型:
python /mnt/f/microduck/tools/microduck_learning/check_training_lineage.py \
--bam-contract /mnt/f/microduck/artifacts/bam-model-hl2915-m6.json \
--onnx-contract /mnt/f/microduck/artifacts/onnx-contract-hl2915-candidate.json \
--training-repo /home/<user>/microduck_rl \
--purpose candidate \
--json-out /mnt/f/microduck/artifacts/training-lineage-hl2915-candidate.json
它会拒绝脏训练仓库、被替换的 BAM/ONNX 文件和错误维度。通过后仍不能直接落地行走:先仿真回放,
再三只舵机单腿、15 只只读、整机悬空、软垫静态站立,最后才做手扶小步态。