Skip to main content

创建自定义 Microduck 动作

本章介绍构建新动作的项目工作流。示例使用基于阶段的**鞠躬(Bow)**行为,但相同流程也适用于点头、下蹲、伸展、恢复技能以及其他机器人动作。

理解策略约定

所有可热插拔的 Microduck 策略共享相同的接口:

  • 61 维 actor 观测:48 个本体感知值加上 13 维命令块 [twist(3), head_pose(4), body_pose(6)]
  • 14 维动作输出,对应激活的舵机关节。
  • 未使用的命令槽仍然存在,并用零填充。
  • 被动轮子和间隙关节使用 passive_* 命名约定,且不得被选为驱动关节。
  • 关节 ID 应由项目辅助函数解析,而不是硬编码。
  • ONNX 导出必须通过 scripts/export.py,以便包含观测归一化器。

破坏这一约定可能会产生只在某个查看器中可用、但无法正确切换或部署的策略。

选择最接近的模板

期望动作推荐模板
连续速度动作microduck_velocity_env_cfg.py
从特定状态恢复microduck_standup_env_cfg.py
两状态命令切换microduck_sitstand_env_cfg.py
缓慢的分阶段动作microduck_ground_pick_env_cfg.py
快速动态机动动作microduck_roulade_env_cfg.py
滚轮动作microduck_velocity_rollers_env_cfg.py

对于鞠躬,ground-pick 任务是一个有用的起点,因为它已经实现了阶段命令、下降、保持、上升、姿态跟踪和恢复。

复制模板

cd ~/microduck-jetson/microduck_rl

cp src/mjlab_microduck/tasks/microduck_ground_pick_env_cfg.py \
src/mjlab_microduck/tasks/microduck_bow_env_cfg.py

在编辑前备份任务注册表和共享 MDP 函数:

cp src/mjlab_microduck/tasks/__init__.py \
src/mjlab_microduck/tasks/__init__.py.bak

cp src/mjlab_microduck/tasks/mdp.py \
src/mjlab_microduck/tasks/mdp.py.bak

设计动作时间线

一个简单的鞠躬可以使用从 0.01.0 的归一化阶段:

阶段行为
0.00–0.25向鞠躬姿态下沉
0.25–0.55保持鞠躬
0.55–0.85返回到初始姿态
0.85–1.00稳定直立

使用平滑插值,而不是在两个姿态之间直接切换。目标的剧烈变化往往会导致高动作率、冲击或不稳定的奖励梯度。

定义目标姿态

microduck_bow_env_cfg.py 中创建关节名称映射。先从保守的角度值开始,并在训练前使用 Viewer 检查它们。

BOW_POSE = {
"left_hip_pitch": -0.20,
"left_knee": 0.30,
"left_ankle": -0.10,
"neck_pitch": 0.35,
"head_pitch": 0.20,
"right_hip_pitch": -0.20,
"right_knee": 0.30,
"right_ankle": -0.10,
}

上面的数值只是起点。请在机器人配置中确认实际的关节名称和符号方向。

构建奖励

一个有用的自定义动作奖励通常组合以下内容:

  • 基于阶段的目标姿态跟踪。
  • 任务结果奖励,例如在鞠躬时降低头部。
  • 序列末尾附近的直立和恢复奖励。
  • 足部接触和横向稳定性项。
  • 关节极限、碰撞、动作速率和冲击惩罚。

尽可能复用模板奖励以及 src/mjlab_microduck/tasks/mdp.py 中的共享函数。只有在所需测量尚不存在时才添加新函数。

warning

在分配权重前检查符号约定。一个已经返回负惩罚的函数,通常只在与项目约定一致时才使用正权重。检查附近的任务配置,并在 TensorBoard 中确认加权后的度量。

注册新任务

src/mjlab_microduck/tasks/__init__.py 中导入新的配置,然后按照现有条目注册一个新的 ID:

register_mjlab_task(
task_id="Mjlab-Bow-Flat-MicroDuck",
env_cfg=microduck_bow_env_cfg,
play_env_cfg=microduck_bow_play_env_cfg,
rl_cfg=microduck_bow_rl_cfg,
)

使用在新模块中实现的精确可调用名称,并镜像当前注册表的签名。

确认注册:

uv run --no-sync list-envs | grep Mjlab-Bow

训练前检查

启动一个随机策略,以检查模型、重置状态、传感器、命令管理器和终止项配置:

export DISPLAY=:0
export MUJOCO_GL=glfw

uv run --no-sync play Mjlab-Bow-Flat-MicroDuck \
--agent random \
--num-envs 1 \
--viewer native

留意无效接触、生成时的相互穿透、关节方向错误、立即终止、NaN 值以及不可能的目标姿态。

运行冒烟测试

export MUJOCO_GL=egl

uv run --no-sync train Mjlab-Bow-Flat-MicroDuck \
--env.scene.num-envs 64 \
--agent.logger tensorboard \
--agent.max_iterations 5

只有在该过程无异常或 NaN 完成后,才开始长时间训练。

分阶段训练

一个实用的课程安排是:

  1. 动作探索:简单的生成状态、宽松的姿态奖励、最小扰动。
  2. 动作完成:加强保持和恢复项;添加基于结果的奖励。
  3. 鲁棒性:增加生成多样性、摩擦随机化、外部推力和间隙变体。

示例长跑训练:

uv run --no-sync train Mjlab-Bow-Flat-MicroDuck \
--env.scene.num-envs 2048 \
--agent.logger tensorboard \
--agent.max_iterations 2000

关注主要任务奖励,而不是只看总奖励。策略可能在正则化指标上有所提升,却从未完成预期动作。

可视化与导出

export DISPLAY=:0
export MUJOCO_GL=glfw

uv run --no-sync play Mjlab-Bow-Flat-MicroDuck \
--checkpoint-file /absolute/path/to/model_XXXX.pt \
--num-envs 1 \
--viewer native

导出通过验证的 checkpoint:

uv run --no-sync python3 scripts/export.py \
Mjlab-Bow-Flat-MicroDuck \
--checkpoint-file /absolute/path/to/model_XXXX.pt \
--onnx-file bow.onnx

若要添加键盘触发,请扩展 scripts/infer_policy.py,复用现有的坐/站、ground-pick、roulade 和踢腿策略切换模式。写入新策略所期望的命令槽,并保持 61 维观测布局不变。

已验证示例:单腿平衡

以下自定义任务已在 Jetson 参考系统上实现并通过冒烟测试。该动作将机器人的重量转移到左脚,抬起右脚,保持平衡姿态,然后返回到正常的双脚站立姿态。

注册的任务 ID 为:

Mjlab-OneLegBalance-Flat-MicroDuck

动作时间线

该任务使用一个六秒的循环阶段命令:

归一化阶段行为
0.00–0.30将重量转移到左脚并抬起右腿
0.30–0.58保持单腿平衡姿态
0.58–0.78放下右脚并回到站立姿态
0.78–1.00在双脚初始姿态下稳定

这些边界在 microduck_one_leg_balance_env_cfg.py 中定义:

BALANCE_PERIOD = 6.0
LIFT_END = 0.30
HOLD_END = 0.58
RETURN_END = 0.78

定义目标姿态

目标使用关节名称而不是原始 MuJoCo 关节索引来表达。这样可以保持意图可读,并避免在机器人模型变化时发生索引意外偏移。

ONE_LEG_POSE = {
"left_hip_roll": -0.25,
"left_hip_pitch": -0.40,
"left_knee": -0.05,
"left_ankle": 0.45,
"right_hip_roll": -0.10,
"right_hip_pitch": 0.95,
"right_knee": -1.25,
"right_ankle": 0.30,
"neck_pitch": 0.30,
"head_pitch": 0.30,
"head_roll": -0.10,
}

左腿保持接近其站立配置。右髋和右膝将摆动腿向前折起,而轻微的头部滚转有助于传达预期的支撑侧。

构建平衡奖励

该示例组合了五个任务特定目标:

奖励目的
one_leg_pose跟踪从站立到平衡的插值关节姿态
support_foot_grounded保持左支撑脚与地形接触
swing_foot_airborne防止右脚在保持阶段仍停留在地面上
swing_foot_height跟踪右脚相对于地形的期望离地高度
com_over_support将水平质心移动到左支撑脚上方

该任务还保留了 Microduck 训练环境继承的关节极限、自碰撞、角速度、动作速率、执行器、编码器、摩擦、质量、惯量以及质心随机化项。

src/mjlab_microduck/tasks/mdp.py 中添加了两个小型可复用测量:

  • phase_single_foot_airborne_reward() 将右脚腾空奖励限制在当前激活的平衡相位内。
  • phase_site_height_track() 在站立和抬起状态之间插值右脚的高度目标。

现有的 phase_pose_track(), phase_pose_track_l1(), single_foot_grounded_reward(), 和 com_over_support_foot() 函数被直接复用。

注册任务

Mjlab-OneLegBalance-Flat-MicroDuckMJLab 任务注册表使用的任务 ID。它不是文件名,也不会作为函数参数传递给 make_microduck_one_leg_balance_env_cfg()。命令行启动器使用该字符串查找在 src/mjlab_microduck/tasks/__init__.py 中注册的环境、play 配置、RL 配置和运行器。

定义和注册路径为:

项目位置目的
环境配置src/mjlab_microduck/tasks/microduck_one_leg_balance_env_cfg.py定义单腿姿态、相位时序、奖励、场景以及 make_microduck_one_leg_balance_env_cfg()
RL 配置src/mjlab_microduck/tasks/microduck_one_leg_balance_env_cfg.py定义 MicroduckOneLegBalanceRlCfg 和训练超参数
任务注册src/mjlab_microduck/tasks/__init__.py将任务 ID 绑定到环境和 RL 配置
CLI 入口uv run --no-sync train <task-id>查找已注册任务并启动训练

其关系为:

Mjlab-OneLegBalance-Flat-MicroDuck
↓ task_id lookup
register_mjlab_task(...)

make_microduck_one_leg_balance_env_cfg()
+ MicroduckOneLegBalanceRlCfg
+ MicroduckOnPolicyRunner

因此,用于选择自定义任务的完整命令为:

cd ~/microduck-jetson/microduck_rl
uv run --no-sync train Mjlab-OneLegBalance-Flat-MicroDuck \
--env.scene.num-envs 64 \
--agent.logger tensorboard \
--agent.max_iterations 5

如果 list-envs 没有显示该任务,请检查新的配置文件是否存在,并且其 import 和 register_mjlab_task() 调用都已添加到 src/mjlab_microduck/tasks/__init__.py 中。命令中的任务 ID 必须与 task_id 字符串完全一致,包括大小写和连字符。

将任务配置的 import 和注册添加到 src/mjlab_microduck/tasks/__init__.py

from .microduck_one_leg_balance_env_cfg import (
make_microduck_one_leg_balance_env_cfg,
MicroduckOneLegBalanceRlCfg,
)

register_mjlab_task(
task_id="Mjlab-OneLegBalance-Flat-MicroDuck",
env_cfg=make_microduck_one_leg_balance_env_cfg(),
play_env_cfg=make_microduck_one_leg_balance_env_cfg(play=True),
rl_cfg=MicroduckOneLegBalanceRlCfg,
runner_cls=MicroduckOnPolicyRunner,
)

确认 MJLab 能发现新任务:

cd ~/microduck-jetson/microduck_rl
uv run --no-sync list-envs | grep OneLegBalance

预期输出:

Mjlab-OneLegBalance-Flat-MicroDuck

在 MuJoCo 中编辑并捕获姿态

示例包含 scripts/one_leg_pose_editor.py。它会禁用重力并固定浮动基座,以便在训练前可以安全地调整各个关节目标。

在 Jetson 桌面上的终端中直接运行:

cd ~/microduck-jetson/microduck_rl
uv run --no-sync python scripts/one_leg_pose_editor.py

在 MuJoCo 窗口右侧展开 Control 面板并调整关节滑块。关闭窗口会在终端中打印最终命名的 ONE_LEG_POSE 字典。MuJoCo 的 Save XMLSave MJB 按钮用于保存模型文件;它们不会保存此任务使用的 Python 目标姿态字典。

Interactive MuJoCo pose editor showing the Microduck one-leg balance target pose

如果通过 SSH 启动编辑器并希望其显示在 Jetson 本地连接的显示器上,请先导出活动桌面会话。已验证的 Jetson 会话使用 DISPLAY=:1

cd ~/microduck-jetson/microduck_rl

export DISPLAY=:1
export XAUTHORITY=/run/user/1000/gdm/Xauthority
export XDG_RUNTIME_DIR=/run/user/1000
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

~/.local/bin/uv run --no-sync python scripts/one_leg_pose_editor.py
note

显示编号在重启或桌面会话变化后可能会改变。在直接从 Jetson 桌面打开的终端中,echo $DISPLAY 会显示当前活动值。

运行已验证的冒烟测试

从 64 个环境和 5 次迭代开始:

cd ~/microduck-jetson/microduck_rl

export MUJOCO_GL=egl

uv run --no-sync train Mjlab-OneLegBalance-Flat-MicroDuck \
--env.scene.num-envs 64 \
--agent.logger tensorboard \
--agent.max_iterations 5

该任务还在一台 16 GB Jetson 上使用 4096 个并行环境进行了测试:

uv run --no-sync train Mjlab-OneLegBalance-Flat-MicroDuck \
--env.scene.num-envs 4096 \
--agent.logger tensorboard \
--agent.max_iterations 5

4096 环境的冒烟测试在没有出现内存不足错误或 NaN 终止的情况下完成,并达到了约 4.6k steps/s。Actor 观测维度保持为 61,动作输出维度保持为 14。

tip

在 8 GB 的 Jetson Orin NX 或 Jetson Orin Nano 上,请从 --env.scene.num-envs 1024 开始。仅在使用 jtop 检查可用内存后再增加该值。

打开训练查看器

要在自定义任务训练时可视化一个环境,请在 Jetson 桌面上运行以下命令:

cd ~/microduck-jetson/microduck_rl

uv run --no-sync train Mjlab-OneLegBalance-Flat-MicroDuck \
--env.scene.num-envs 1 \
--agent.logger tensorboard \
--agent.max_iterations 1000 \
--env.viewer.distance 0.55 \
--env.viewer.azimuth 145 \
--env.viewer.elevation -12

姿态编辑器会立即显示预期目标。训练查看器最初显示的是未训练策略,因此只有在策略学会转移、抬脚、保持和恢复序列后,稳定的单腿行为才会出现。

启动完整训练运行

对于 16 GB 参考系统,请使用以下起点:

uv run --no-sync train Mjlab-OneLegBalance-Flat-MicroDuck \
--env.scene.num-envs 4096 \
--agent.logger tensorboard \
--agent.max_iterations 20000

冒烟测试确认任务配置、奖励项、传感器、CUDA 后端以及大量并行环境数量均能正常工作。但它们本身并不能证明策略收敛。请在 MuJoCo 中评估保存的检查点,并在机器人在未转移质心的情况下抬脚、跳跃或无法恢复到站立时,调整姿态、奖励权重、相位时序或课程。

开发检查清单

  • 观测布局保持为 61 维。
  • 策略输出保持为 14 维。
  • 被动关节从动作和舵机观测中排除。
  • BAM 启动事件和域随机化在需要的地方保持激活。
  • 任务出现在 list-envs 中。
  • Random-policy Viewer 检查通过。
  • 64 环境冒烟测试通过。
  • 主要任务指标在 TensorBoard 中得到改善。
  • 最终 PT 检查点在 MuJoCo 中表现正确。
  • 使用项目脚本导出 ONNX,并在机器人部署前进行演练。
Loading Comments...