MANUAL 03 · 训练篇 · LEARN NOTES

收进学习手册 · 2026-09-10 · duck.whatled.com

Microduck 训练参数调整与新动作开发指南

给第一次接触机器人强化学习的人:先学会运行和观察,再改一个参数;先让仿真可靠,再谈新动作;先辨识一只舵机,再训练整机。

本文按本地源码逐项核对。训练仓基线为 microduck_rl 的 develop@29e887e。当前工作区另有一处本地实验改动:走路任务的 air_time.threshold_min 从上游值 0.125 s 改为 0.04 s。本文会同时标出二者,不把本地实验值冒充上游默认值。


1. 新手应该分哪些阶段

不要从“写一个跳舞奖励函数”开始。推荐按下面六级推进。每一级都以前一级的产物为输入。

阶段 建议时间 只做什么 交付物 通过标准 暂时不要碰
0. 建立地图 半天 看懂三个仓库、任务列表和训练命令 一张自己的文件地图 能说清训练、部署、舵机模型各在哪 奖励权重、PPO 参数
1. 跑通现有策略 1 天 列任务、5 次迭代冒烟、回放已有 checkpoint 命令和回放录像 能稳定复现,不出现 NaN/维度错误 新动作、真机上电
2. 看懂一次决策 1~2 天 理解 61 维观测、14 维动作、50 Hz 控制 手写一张输入输出表 能解释一个动作怎样变成关节目标 改观测维度
3. 单变量实验 2~4 天 每次只改一个命令、奖励或随机化参数 A/B 实验记录 能从曲线和回放解释因果 同时改五六个参数
4. 新动作 1~2 周 从最接近的现有任务复制,先做走快,再做舞蹈 独立任务、测试、checkpoint 冒烟、训练、回放、导出均通过 直接上真机
5. 换舵机 1~3 周 单舵机台架、BAM 拟合、协议适配、重训 参数 JSON、总线后端、新 ONNX 仿真与台架响应接近 买齐 15 只后才第一次测
6. 真机闭环 持续 吊装、软垫、低增益、逐技能验收 测试记录与安全边界 温度、电流、时序、动作均达标 无保护直接落地跑

1.1 你现在最适合做什么

你已经有 Radxa Zero 3W,但还不需要让它承担训练。近期按这个顺序最稳:

  1. 在 Mac 上跑通任务列表、短训练和浏览器回放;
  2. 用现有走路任务做一次“只改一个参数”的 A/B;
  3. 学会读 observation、reward、curriculum 三张表;
  4. 做一个仿真专用的“走快”任务;
  5. 再做有节拍的摇摆/踏步舞蹈;
  6. Radxa 先用于 Linux、串口和单舵机台架,最后才加载 ONNX 控制整机。

阶段 3 以前,完全不需要买齐舵机,也不需要修改 Rust 总线代码。


2. 三个代码层分别负责什么

本项目不是一个仓库包办所有事情。

microduck_rl(训练)
  机器人 MJCF + BAM 执行器 + 任务/奖励/PPO
                    │ 导出 ONNX
                    ▼
microduck(运行时)
  61 维观测 → ONNX → 14 维动作 → 安全处理 → 舵机总线
                    ▲
                    │ 自定义舵机参数 JSON
bam(执行器辨识)
  单舵机实测日志 → 拟合电机、摩擦、惯量、回差相关参数

2.1 训练仓 upstream/microduck_rl

位置 中文含义 什么时候看
src/mjlab_microduck/tasks/microduck_*_env_cfg.py 每个技能的“实验配方” 改命令、奖励、随机化、课程、PPO
src/mjlab_microduck/tasks/mdp.py 自定义观测、命令、奖励、事件、课程函数 新增行为逻辑
src/mjlab_microduck/tasks/__init__.py 任务注册表 新增任务 ID
src/mjlab_microduck/robot/microduck_constants.py HOME 姿态、BAM 舵机、机器人变体 换舵机、改站姿、选模型
src/mjlab_microduck/robot/microduck/ MJCF、网格、关节和碰撞 改机械结构、质量、惯量、限位
src/mjlab_microduck/actuator/friction_dr_bam.py BAM 摩擦随机化和回差编码器 理解执行器,不是普通 PD
tests/test_*_cfg.py 配方不变量测试 每次新增任务都应照着写
scripts/export.py checkpoint → ONNX 正式导出,带上观测归一化
scripts/infer_policy.py CPU MuJoCo 部署预演 上真机前复核

2.2 真机运行时仓库根目录

位置 中文含义 换舵机时的作用
duck-control/src/io.rs 硬件抽象接口 RobotIo 新协议后端应实现这个接口
duck-control/src/bus.rs 当前 Dynamixel XL330 总线实现 飞特等协议需要替换/新增实现
duck-control/src/model.rs 15 个 ID、HOME、波特率、寄存器 ID、零位、协议参数来源
duck-control/src/obs.rs 61 维观测和 14→15 动作映射 训练与真机的最高风险契约
robotd/src/control.rs 推理、动作缩放、低通、技能切换 部署动作处理必须与训练匹配
deploy/robotd.toml 每台机器的运行参数模板 增益、动作尺度、安全阈值

2.3 BAM 仓库 bam

BAM 不是“给 MuJoCo 填一个最大扭矩”。它从位置误差经过固件位置环、电压、电流、反电动势,再计算力矩和摩擦。换舵机时,真正应该替换的是实测拟合出的 BAM 参数。


3. 先理解这些强化学习术语

源码名 新手解释 本项目例子
Environment / EnvCfg 训练世界的完整规则 地面、机器人、传感器、奖励、终止
Observation 策略能看到的信息 IMU、关节角、关节速度、上一动作、命令
Action 策略每 20 ms 输出的数字 14 个相对 HOME 的关节位置偏移
Command 人希望机器人完成什么 前进速度、转速、头部姿态、身体姿态
Reward 告诉策略什么行为更好 速度跟踪、直立、抬脚、平滑
Penalty 对坏行为扣分 滑脚、碰撞、动作突变
Termination 何时结束并重置当前 episode NaN、超时、摔倒或动作完成
Event 启动、重置或定时发生的变化 随机质心、推一下机器人
Domain randomization / DR 让每个仿真世界略有不同 电压、摩擦、质量、编码器偏差
Curriculum 先易后难地调整训练规则 逐渐加大扰动、扩大头部命令
PPO 更新策略网络的方法 当前所有任务使用的算法
Checkpoint 可继续训练的 .pt 快照 model_12500.pt
ONNX 真机只负责推理的模型文件 输入 61,输出 14
Sim-to-real 仿真策略迁移到真机 参数、时序、接口必须尽量一致

奖励不是动作脚本。你没有告诉鸭子“先抬左脚再抬右脚”,而是告诉它“跟上目标速度、别倒、脚别拖地、动作别太抖”,PPO 自己搜索出动作。


4. 61 维输入与 14 维输出是不能随便动的契约

当前所有 alpha 策略使用同一个布局:

索引 宽度 内容
0~2 3 躯干坐标系角速度
3~5 3 躯干坐标系投影重力
6~19 14 相对 HOME 的关节角,嘴巴除外
20~33 14 关节速度,嘴巴除外
34~47 14 上一次策略原始动作
48~50 3 vx, vy, yaw_rate
51~54 4 neck_pitch, head_pitch, head_yaw, head_roll
55~60 6 身体 x, y, z, roll, pitch, yaw 命令槽

动作顺序是:

0..4   左腿:hip_yaw, hip_roll, hip_pitch, knee, ankle
5..8   颈头:neck_pitch, head_pitch, head_yaw, head_roll
9..13  右腿:hip_yaw, hip_roll, hip_pitch, knee, ankle

真机有 15 只舵机;第 10 个物理槽位是嘴巴,策略不会输出它。duck-control/src/obs.rs 使用同一个映射完成读取和回填。

新技能如果暂时用不到某个命令槽,应保留并填零或极小“存活范围”,不要删除它。否则新 ONNX 不能与现有运行时热切换。


5. 第一次跑通:Mac 上只做这四件事

进入训练仓:

cd /Volumes/dev/dev/microduck/microduck-replica/upstream/microduck_rl
uv sync
uv run list-envs | rg MicroDuck

先做 5 次迭代的配置冒烟:

CUDA_VISIBLE_DEVICES="" uv run train Mjlab-Velocity-Flat-MicroDuck \
  --env.scene.num-envs 64 \
  --agent.max_iterations 5

已有 checkpoint 可用浏览器 viewer 回放:

CUDA_VISIBLE_DEVICES="" uv run play Mjlab-Velocity-Flat-MicroDuck \
  --checkpoint-file logs/rsl_rl/velocity/2026-09-08_22-55-20_expE-gait-ramp/model_12500.pt \
  --viewer viser \
  --num-envs 1

macOS 上优先用 --viewer viser。正式的 4096 并行环境训练应使用 NVIDIA CUDA 机器;Radxa Zero 3W 用来推理,不适合承担 PPO 正式训练。

当前注册表里最值得新手先认识的任务:

Task ID 它实际训练什么 适合什么时候学
Mjlab-Velocity-Flat-MicroDuck 平地速度跟踪和站立 第一个任务
Mjlab-Velocity-Rough-MicroDuck 小台阶、网格和缓坡行走 平地稳定以后
Mjlab-VelStand-Flat-MicroDuck 行走加跌倒恢复 想做统一走/起身策略时
Mjlab-StandUp-Flat-MicroDuck 从坐姿温和站起,并控制身体姿态 学单次目标动作
Mjlab-SitStand-Flat-MicroDuck 一个策略在坐姿和站姿间切换 学离散命令
Mjlab-GroundPick-Flat-MicroDuck 分阶段低头触地再恢复 学周期相位动作
Mjlab-BallKick-Flat-MicroDuck 保持支撑并踢球 学物体交互和不对称动作
Mjlab-Roulade-Flat-MicroDuck 前滚、落地、再站稳 学动态动作和状态门控
Mjlab-Spin-Flat-MicroDuck 穿轮滑鞋按相位旋转 学角速度目标和相位包络

带 -Backlash- 的任务用于测试串联齿轮间隙;-Rollers 和 Swizzle 属于轮滑模型。它们不是更高级的“升级版走路”,而是不同物理结构或鲁棒性变体。

阶段 1 验收


6. 参数在哪里改:按目标查文件

6.1 想改站立姿态或零位

文件:src/mjlab_microduck/robot/microduck_constants.py

搜索:HOME_FRAME

当前关键值包括左右腿镜像的髋、膝、踝,以及颈部和头部。真机侧必须同步核对 duck-control/src/model.rs 的 DEFAULT_POSITION。两边不一致时,关节位置观测会永久带一个偏差,表现很像舵机不准或策略不稳。

原则:

6.2 想改关节行程、质量、惯量、碰撞或脚底摩擦

文件:

注意三种参数不要混淆:

机械关节 limit        = 结构允许到哪里
soft limit factor 0.9 = 训练提前保留安全余量
action scale           = 网络输出换算成多大角度偏移

换外形和质量后,应重新导出/计算质量与惯量。只换 STL 视觉网格但保留旧质量,画面会像新机器,动力学仍是旧机器。

6.3 想改舵机动力学

文件:src/mjlab_microduck/robot/microduck_constants.py

搜索:_BAM_ACTUATOR_KWARGS

当前训练配置:

参数 当前值 含义
motor_name xl330 使用 BAM 内置 XL330 参数族
model m6 使用含复杂摩擦项的 M6 模型
kp_fw 200 模拟舵机固件位置 P 增益
vin_range 6.5~8.2 V 每个环境的电池电压
vin_drop_gain_range 0.0~0.2 多舵机出力造成的压降
vin_min 6.0 V 压降后的下限
delay_min_lag/max_lag 3~6 仿真步 命令延迟范围
target_names_expr 排除 passive_* 只驱动 14 个主动关节

kp_fw=200 与 XML 里的 kp=0.55 不是同一层,不能直接互换。当前实体由 BAM 接管;XML 中历史原生 PD 参数主要用于无 BAM 对照。

6.4 想改走路/跑步目标速度

文件:tasks/microduck_velocity_env_cfg.py

搜索:command.ranges

当前范围:

lin_vel_x = (-0.4, 0.4)   # 前后 m/s
lin_vel_y = (-0.3, 0.3)   # 横向 m/s
ang_vel_z = (-1.0, 1.0)   # 转向 rad/s

TURN_IN_PLACE_FRACTION=0.15 会专门抽取原地转向样本。只扩大最大速度并不自动得到“跑步”:策略可能用更快的小碎步、拖脚或倾倒来换速度分。

推荐一次只把前进上限从 0.4 提到 0.5,保留后退范围不变,观察速度误差、摔倒率、腾空时间和脚高。确认稳定后再到 0.6。超过真实执行器能力的命令只会训练出奖励妥协,不会创造额外力矩。

6.5 想让脚抬高或步子更明显

同一走路配置中搜索:

当前 checkout 的脚高目标均为 0.02 m。air_time.threshold_min 的上游值是 0.125 s,你当前工作区的实验值是 0.04 s。后者意图是先奖励任何真实抬脚,等 Metrics/air_time_mean > 0.10 后再逐步收紧。

典型因果关系:

调整 可能得到 常见副作用
增大 air_time.weight 更愿意迈步 跳步、站立时乱抬脚
降低 threshold_min 更早获得学习信号 小碎步也能得分
增大 target_height 脚抬得更高 耗能、落地冲击、步频下降
放宽腿部 std_walking 更大动作空间 姿态怪、关节撞限位
强化 action_rate_l2 更平滑 太早强化会压死探索

6.6 想让动作更稳、更平滑

搜索:

走路任务不是一开始就把动作变化惩罚设为 -1.0,而是从 -0.1 分阶段收紧,到约 1500 次 PPO 迭代达到 -1.0。原因是早期需要探索,过早抑制动作会学成“站着最安全”。

6.7 想提高 sim-to-real 鲁棒性

走路配置顶部的开关与范围是第一入口:

随机项 当前状态 当前起始范围/设置
躯干质心 开 ±3 mm,课程扩到 ±15 mm
头部组件质心 开 ±3 mm,课程扩到 ±10 mm
质量+惯量 开 0.95~1.05 倍,一起缩放
BAM 摩擦 开 0.9~1.1 倍
armature 开 0.9~1.1 倍
速度冲击 开 每 3~6 s,±0.3 m/s
IMU 安装误差 开 随机轴最大 6°
编码器偏置 开 ±0.015 rad
kP / kD 关 范围存在但目前不生效
关节 damping 关 BAM 下这条路径本来也不是主要入口
初始机身倾斜 关 pitch ±10°、roll ±5° 仅为预设

源码顶部 COM_RANDOMIZATION_RANGE 后的旧注释仍写“课程扩到 ±8 mm”,但本版本实际 com_range 课程的最后一档是 0.015 m,即 ±15 mm。训练行为由课程表决定,本文采用实际执行值;读参数时应检查定义和后续覆盖,不能只读顶部注释。

原则不是“随机越大越好”。DR 应覆盖实测误差,而不是覆盖想象中的最坏情况。随机范围过大时,策略会为了所有虚构机器人都不倒,学成紧张、保守、难以行走的折中动作。

6.8 想改传感器噪声和延迟

在走路配置的 Observations 段搜索 Unoise 和 delay_*:

观测 当前噪声 当前延迟
躯干角速度 ±0.03 0~1 控制步
投影重力 ±0.01 0~1 控制步
关节位置 ±0.001 rad 编码器偏置另算
关节速度 ±0.25 rad/s 固定 1 控制步

固定 IMU 安装偏角应在运行时标定并纠正;训练中的随机轴 6° 用来增强容忍度,不能代替已知偏差的校准。

6.9 想改课程学习节奏

文件还是任务配置,搜索 cfg.curriculum。

课程的 step 是环境步,不是 PPO 迭代号。当前每次迭代每环境采样 24 步,因此:

第 N 次 PPO 迭代对应 step = N × 24

课程函数位于 tasks/mdp.py,常用入口:

不要从 env.cfg 临时读写当前课程状态;项目约定由 manager 和事件参数维护。

6.10 想改 PPO 网络和训练超参数

每个任务文件最底部都有独立的 *RlCfg。走路是 MicroduckRlCfg:

参数 当前值 新手建议
actor/critic 隐层 512, 256, 128 前四个阶段不要改
激活 ELU 不改
observation normalization 开 必须保留并正确导出
PPO clip 0.2 不改
entropy 0.01 探索不足/过强时才研究
epochs / mini-batches 5 / 4 不改
learning rate 1e-3 adaptive 不改
gamma / lambda 0.99 / 0.95 不改
desired KL 0.01 不改
rollout steps 24 课程换算依赖它
save interval 250 可按磁盘和观察频率改
max iterations 50,000 是上限,不代表一定要跑满

新手最常见误区是行为不好就先调学习率。多数情况下,问题其实在目标不可达、奖励漏洞、重置分布或仿真物理。


7. 怎样做第一个单变量 A/B 实验

以“鸭子只会贴地碎步”为例。

7.1 写下假设

现象:air_time_mean 长期约 0.04 s,air_time reward 近零。
假设:0.125 s 的奖励门槛太高,策略从未收到抬脚正反馈。
只改:threshold_min 0.125 → 0.04。
不改:速度范围、脚高目标、PPO、DR、随机种子策略。

7.2 每个实验必须记录

复制 rl-series/experiments/TEMPLATE.md,至少填:

7.3 优先观察的指标

指标 说明 期望趋势
episode length 是否经常早早摔倒 上升后稳定
velocity tracking reward/error 是否真跟上命令 reward 上升、error 下降
air_time_mean 是否真的迈步 脱离零附近,但不是越大越好
foot height/clearance 是否拖脚 接近目标,不持续过冲
upright / tilt 躯干是否稳定 稳定,不靠大幅前倾作弊
action std / entropy 是否仍在探索 逐步下降,不能突然塌缩
penalty reward 惩罚符号是否正确 所有 penalty 贡献应 ≤ 0

最后一条非常重要:项目里有两类惩罚函数。基础 cost 常返回正数,需要负权重;名字含 *_penalty、*_l1 的自取负函数可能返回负数,需要正权重。最可靠的检查不是看名字,而是看日志中每个惩罚贡献是否始终不大于零。


8. 从走路一步一步做出跑步

当前任务列表没有独立的 Running 环境。microduck_velocity_env_cfg.py 虽然给 std_running 赋值,但它目前等于 std_walking,不能把这理解为已有成熟跑步策略。

8.1 第一阶段:先做“走快”而不是“跑”

以 make_microduck_velocity_env_cfg 为模板,建立独立任务,保持 61/14 契约和全部 DR/观测设置。

只调整:

  1. lin_vel_x 正向上限:0.4 → 0.5 m/s;
  2. 训练样本增加中高速 bucket,避免均匀采样导致高速样本稀少;
  3. 回放固定测 0、0.2、0.4、0.5 m/s;
  4. 保持脚高、air time、平滑项不变,先测策略自然反应。

通过标准:0.5 m/s 跟踪误差下降,同时低速和站立能力没有明显退化。

8.2 第二阶段:让“跑态”有可辨认的物理定义

跑步不只是速度更大。需要先决定你接受哪一种定义:

Microduck 尺寸小、舵机和落地冲击敏感,建议先做快速步行,再谨慎开放短腾空。

可能需要的奖励变化:

不要直接删除 upright 或大幅减弱动作正则。先在小幅变化中确认机器的可实现上限。

8.3 第三阶段:做课程

推荐课程:

0~500 iter     主要训练 0~0.4 m/s,复制已验证步态
500~1200       加入 0.4~0.5 m/s
1200~2500      加入 0.5~0.6 m/s,并加强脚高/离地目标
2500 以后       加强摩擦、电压、推扰动与动作平滑

数字只是实验起点,不是已验证的官方跑步配方。是否推进下一阶段,应由速度误差、摔倒率和回放共同决定。

8.4 为什么建议单独任务

对新手,先用独立 microduck_running_env_cfg.py 更容易解释因果:日志目录独立、速度分布明确、不会破坏已经能走的基线。等走和跑都稳定后,再研究一个由速度命令自动切换步态的统一策略。


9. 从简单舞蹈一步一步做复杂动作

舞蹈有两条路线。

9.1 路线 A:关键帧播放,不用 RL

如果动作完全固定、地面和负载也固定,先用关键帧插值。这是验证机械限位、舵机方向和节拍的最快方法。强化学习只在需要平衡、抗扰、落地或适应误差时增加价值。

9.2 路线 B:节拍/相位命令 + RL 平衡

这是推荐路线:人定义舞蹈节奏和目标姿态,RL 学习怎样在真实动力学下跟随目标而不摔倒。

现有项目已有可借用的结构:

9.3 第一个舞蹈只做四拍

建议动作:站稳 → 左摆 → 右摆 → 回中,同时轻微点头。

  1. 用相位 φ∈[0,1) 表示一个周期;
  2. 使用 sin(2πφ), cos(2πφ) 两个槽表达相位,避免 0.99→0.00 的不连续;
  3. 定义 4~8 个关键帧,再做平滑插值;
  4. 奖励目标关节姿态、直立和双脚接地;
  5. 惩罚滑脚、自碰撞、动作突变和过大力矩;
  6. 先固定慢节拍,再随机节拍;
  7. 最后再加外力和物理随机化。

若要保持现有 61 维接口,可像 ground-pick/spin 一样复用某两个命令槽编码相位,但真机运行时必须用完全相同的编码。不要在仿真里用真实 phase,部署时却只给一个按钮状态。

9.4 舞蹈课程建议

阶段 A  固定 6 s 周期,只跟踪腿部小幅摆动
阶段 B  加头部关键帧,保持双脚着地
阶段 C  周期随机到 4~8 s
阶段 D  扩大摆幅,加入踏步
阶段 E  加电压、摩擦、质量和轻微推扰动
阶段 F  随机起始相位,测试中途接管和循环衔接

9.5 舞蹈的常见奖励漏洞

解决方式是连续相位、状态门控、一次性或限速的成功奖励,以及给平衡修正保留自由度。


10. 新动作应该复制哪个模板

新动作 最接近模板 原因
走快、跑、横移 microduck_velocity_env_cfg.py 连续速度命令和成熟步态 DR
蹲下再站起、两种舞姿切换 microduck_sitstand_env_cfg.py 一个策略处理两种离散状态
固定起点到固定终点的鞠躬 microduck_standup_env_cfg.py 单次动作、终点姿态清晰
踢球 microduck_ball_kick_env_cfg.py 物体交互、支撑脚与目标速度
连续旋转 microduck_spin_env_cfg.py 相位包络和角速度目标
翻滚、跳起、落地动作 microduck_roulade_env_cfg.py 连续进度、阶段门控、落地奖励
轮滑动作 microduck_velocity_rollers_env_cfg.py 被动轮关节和轮地摩擦

新增任务的源码工作流是:

  1. 复制最接近的 cfg,而不是从空文件写;
  2. 在文件顶部集中放 ENABLE_* 和行为常量;
  3. 保留 61 维观测、14 维动作、BAM 和 NaN 防护;
  4. 只留下与动作目标不冲突的基础奖励;
  5. 在 tasks/mdp.py 添加必要的纯函数和有状态门控;
  6. 在 tasks/__init__.py 注册新的 task ID;
  7. 给新任务单独的 experiment_name;
  8. 在 tests/ 添加配置和函数测试;
  9. 64 环境 × 5 迭代冒烟;
  10. 回放确认物理和奖励,再跑正式训练。

对不对称动作,例如只踢右脚、只向右旋转,默认不要启用左右镜像 symmetry。对称动作也应先关闭,行为稳定后再做有对照的开启实验。


11. 换成其他厂家舵机:完整参数传播链

其他厂家和类型当然可以用来学习和调试,但分两种目标:

换舵机应按四层处理。

11.1 机械层

记录:尺寸、重量、安装孔、输出轴、舵盘、可用角度、零位方向。

要影响:

11.2 电气层

记录:额定/允许电压、空载/堵转电流、线序、总线电平、温度保护。

要影响:

11.3 通信层

当前 duck-control/src/bus.rs 明确使用 rustypot::servo::dynamixel::xl330::Xl330Controller,协议 V2、1 Mbps,并读取 XL330 的寄存器地址。换成飞特等协议时,不能只改型号字符串。

推荐保留上层 RobotIo:

RobotIo::read()         → positions / velocities / currents / IMU
RobotIo::write()        → 15 个位置目标
RobotIo::set_gain()     → 全关节增益
RobotIo::set_torque()   → 扭矩开关
RobotIo::slow_sensors() → 电压与每舵机温度

为新协议写一个新的后端,实现同样的单位和顺序。需要逐项解决:

若新舵机协议无法与当前 Dynamixel IMU 板共总线,就要分总线或改 imu_to_dxl 固件。这是系统结构变化,不是一个配置项。

11.4 动力学层:先辨识一只,再买齐

当前 BAM 参数库有 XL330 和若干其他型号,但没有本项目计划使用的 HL-1910 参数。正确路径是实测拟合一个自定义 JSON。

台架至少记录:

BAM 仓库给出的流程是:

# 1. 用对应厂家的 record 模块采集原始日志
uv run python -m bam.<manufacturer>.all_record \
  --port <串口> --motor <型号> \
  --mass <负载kg> --arm-mass <摆臂kg> --length <臂长m> \
  --vin <电压> --logdir data_raw

# 2. 重采样/清洗为 5 ms 时间步
uv run python -m bam.process --raw data_raw --logdir data_processed --dt 0.005

# 3. 拟合;建议 m1~m6 都做并留一个 kP 作验证集
uv run python -m bam.fit \
  --actuator <型号名> --model m6 \
  --logdir data_processed --validation_kp <留出的kP> \
  --output params/<型号名>/m6.json

# 4. 对比实测与仿真
uv run python -m bam.plot \
  --actuator <型号名> --logdir data_processed --sim \
  --params params/<型号名>/m6.json

若 BAM 没有该厂家的采集模块,要先照已有 manufacturer 包增加协议读写和轨迹记录器。不要拿另一款舵机的 JSON 改个文件名。

11.5 把自定义舵机模型接到 Microduck

固定版本的 BamActuatorCfg 支持 json_path。未来修改训练配置时,概念上从:

motor_name="xl330",
model="m6",

换成:

json_path="/绝对路径/params/hl1910/m6.json",

json_path 与 motor_name + model 二选一,不能同时填写。其余这些仍需按实测决定:

11.6 为什么换舵机后要重训

策略学到的是“给出一个关节偏移后,这台具体机器会怎样动”。速度、摩擦、延迟、回差和电压响应一变,同一动作会产生不同的落脚时间和姿态。旧 ONNX 可以用作仿真退化基线,但不能默认直接上新硬件。

推荐顺序:走路 flat → 站立/恢复 → 坐站 → 其他技能 → rough/backlash。没有必要第一天重训全部策略。


12. 仿真参数、运行时参数必须成套记录

运行时 deploy/robotd.toml 的关键默认/说明值:

参数 当前值/默认 用途
bus.port /dev/ttyS2 Radxa 舵机/IMU 总线
control.hz 50 Hz 必须与训练时间尺度一致
policy.action_scale walk 0.9 原始动作 → 关节偏移
policy.standing_action_scale 1.0 站立策略动作尺度
policy.gain 200 真机位置 P 增益
standing_gain_ratio 0.8 站立相对增益
head_lowpass 0.5 头部目标低通默认
legs_lowpass 0.7 腿部目标低通默认
voltage_adapt false 可选电压动作补偿
deadman_ms 500 ms 命令失联后停止速度
gain_limp 50 摔倒软化增益
battery_empty_shutdown true 低电自动坐下/关机

12.1 当前低通配置存在版本冲突

这是不能省略的事实:

因此不能笼统写“必须开”或“必须关”。正确做法是把以下三件东西视为一个版本集合:

训练 commit + checkpoint/ONNX + runtime 动作处理配置

对自己新训练的策略,先在 CPU 部署预演和吊装真机上做四组 A/B:无低通、仅头部、仅腿部、0.5/0.7;记录速度误差、相位延迟、跌倒、峰值电流和抖动,再锁定配置。


13. 训练、导出和部署的质量门

13.1 每次配置改动

uv run --with pytest pytest tests/
CUDA_VISIBLE_DEVICES="" uv run train <TASK_ID> \
  --env.scene.num-envs 64 \
  --agent.max_iterations 5

检查:task 能创建、61/14 不变、奖励均为有限值、无 NaN、课程键名存在。

13.2 正式训练

uv run train <TASK_ID> --env.scene.num-envs 4096

简单单次动作通常先预留约 1000 次迭代看能否发现;步态和恢复通常需要 4000~6000 甚至更多。max_iterations 是停止上限,不能代替收敛判断。

13.3 回放

uv run play <TASK_ID> \
  --checkpoint-file <model_N.pt> \
  --viewer viser --num-envs 1

不要只挑最好看的命令。固定测试矩阵至少包括:零命令、低速、最高训练速度、转向、命令突变、不同随机种子、低电压、摩擦上下界。

13.4 正式导出

uv run scripts/export.py <TASK_ID> \
  --checkpoint-file <model_N.pt> \
  --onnx-file <out.onnx> \
  --viewer viser

必须走项目导出脚本,因为 actor 开启了 observation normalization,导出脚本会把归一化器烘进 ONNX。手工只导网络时,仿真 play 可能正常,真机却会收到未归一化输入。

13.5 CPU 部署预演

uv run scripts/infer_policy.py --walking <out.onnx>

它用 50 Hz 控制、BAM 执行器复演部署路径。还应分别测试 --no-bam、电压、增益、延迟和 action scale 参数,确认模型不是只在单一设定下碰巧工作。

13.6 真机测试金字塔

L1 单舵机台架
L2 15 舵机总线但不装负载
L3 整机悬空、低增益、人工急停
L4 吊装带少量负载
L5 软垫地面、零命令站立
L6 低速直行和停止
L7 转向、最大训练速度
L8 单次技能和连续动作

任何一级出现方向错误、撞限位、过流、过热、通信丢包或异常振荡,都回到前一级,不靠安全代码硬扛。


14. 出现问题时先查哪里

现象 优先检查 不要先做什么
训练完全不动 目标是否可达、正奖励是否有梯度、平滑惩罚是否过强 调大学习率
站着刷分不走 速度奖励/命令采样、高速样本占比、奖励门控 再加强站立奖励
只贴地碎步 air time 门槛、脚高、摆动奖励是否能收到 同时改所有步态项
越训越抖 action/torque rate 课程、奖励 jackpot、观测延迟 只在部署端加很重滤波
仿真很好,真机摔 HOME、关节顺序、方向、动作尺度、BAM、电压、时延、低通 继续训练更多迭代
一换电池状态就变 vin_range、压降、运行时电压补偿 固定成满电仿真
个别舵机总跑偏 零点、方向、编码器偏置、回差、ID 映射 放大整体 DR 掩盖坏舵机
动作撞限位 XML range、soft limit、HOME、action scale 只靠真机裁剪
reward 数值很好但动作怪 奖励漏洞、重复发成功奖、缺少状态门控 相信总 reward 一个数
导出后才坏 ONNX 是否含 normalizer、输入 61/输出 14 手写 checkpoint 转 ONNX

15. 推荐的新手七次实验

每次只改一个变量,并保留 baseline。

  1. 原配置 64 环境 × 5 iter:学会启动和找日志;
  2. 原配置 64 环境 × 100 iter:看 reward、entropy 和 episode length;
  3. 固定 checkpoint 回放多组速度:学会行为评估;
  4. A/B 一个 air_time.threshold_min:学会从现象提出假设;
  5. A/B 一个前进速度上限:理解命令分布与能力边界;
  6. 建立“走快”独立任务:学会复制模板、注册和写测试;
  7. 建立四拍左右摇摆任务:学会相位、姿态跟踪和稳定门控。

完成第 7 项以后,再开始 HL-1910 单舵机辨识。这样你已经知道拟合出的电压、延迟、摩擦和回差最终会进入哪里,不会把台架实验做成一堆无法用于训练的数据。


16. 一页参数索引

我想改…… 文件 搜索词
初始站姿/零位 robot/microduck_constants.py HOME_FRAME
真机零位与 ID duck-control/src/model.rs DEFAULT_POSITION, JOINT_IDS
舵机模型 robot/microduck_constants.py _BAM_ACTUATOR_KWARGS
自定义舵机 JSON 同上 json_path(替代 motor_name/model)
关节限位/原生 PD robot/microduck/joints_properties.xml range, chosen_actuator
质量、惯量、几何 robot/microduck/robot_*.xml mass, inertia, geom
走路速度 tasks/microduck_velocity_env_cfg.py command.ranges
抬脚 同上 air_time, foot_clearance, foot_swing_height
稳定和平滑 同上 upright, action_rate_l2, angular_momentum
DR 开关与范围 同上顶部和 Events 段 ENABLE_, RANDOMIZATION_RANGE
传感器噪声 同上 Observations 段 Unoise, delay_min_lag
课程 同上末段 cfg.curriculum
PPO 任务文件最底部 *RlCfg
奖励/事件实现 tasks/mdp.py 函数名
新任务注册 tasks/__init__.py register_mjlab_task
真机协议 duck-control/src/bus.rs Xl330Controller, RobotIo
61/14 布局 duck-control/src/obs.rs OBS_LEN, ACTION_LEN
真机动作尺度/低通 deploy/robotd.toml action_scale, lowpass, gain
真机安全 同上 [safety]

常用搜索命令:

rg -n 'HOME_FRAME|_BAM_ACTUATOR_KWARGS' src/mjlab_microduck/robot
rg -n 'command.ranges|cfg.rewards|cfg.curriculum' src/mjlab_microduck/tasks
rg -n 'OBS_LEN|ACTION_LEN|DEFAULT_POSITION|JOINT_IDS' /Volumes/dev/dev/microduck/duck-control/src
rg -n 'action_scale|lowpass|gain|deadman' /Volumes/dev/dev/microduck/deploy/robotd.toml
git diff -- src/mjlab_microduck/tasks

17. 最重要的五条原则

  1. 先复现,再改动;一次只改一个变量。
  2. 先验证物理目标可达,再开始长训练。
  3. 奖励好看不等于动作正确,曲线、状态指标和回放缺一不可。
  4. 训练 commit、ONNX 和运行时处理必须作为同一个版本集合。
  5. 换舵机先测一只,真机先吊装;任何安全保护都不能替代逐级验证。

配套阅读:

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页