教程#

SO-101 机械臂拾取样品瓶并将其放入支架。

备注

本教程与 NVIDIA Sim-to-Real SO-101 学习课程 及其 工作坊仓库 相衔接。课程使用 SO-101、Isaac Lab 和 NVIDIA Isaac GR00T,介绍更完整的端到端物理 AI 工作流程。

本教程围绕 SO-101 机械臂 拾取样品瓶并放入支架的任务,构建完整的机器人学习流程。你将使用一个接近实际项目组织方式的下游项目: IsaacLabTutorial 的 main 分支 ,而不是拼接彼此独立的示例。项目包含机器人和工作坊资源、基于管理器的强化学习环境、状态与腕部相机观测、RSL-RL 智能体配置、测试、状态策略训练,以及从状态策略到视觉策略的蒸馏。

完成本教程后,你将了解下游 Isaac Lab 任务如何打包、被发现、验证、训练和评估,也会知道如何修改机器人、场景、MDP 和学习配置,以实现自己的任务。

1. 配置项目#

你需要 Python 3.12、 uv 、Git 和 NVIDIA GPU。本教程使用 Newton 的 MJWarp 求解器,主要流程无需 Isaac Sim 应用程序。开始前,请检查 系统要求 。

克隆教程的 main 分支并创建环境:

git clone https://github.com/isaac-sim/IsaacLabTutorial.git
cd IsaacLabTutorial
uv sync

项目通过 pyproject.toml 固定使用 Isaac Lab 的 develop 分支,因此无需在旁边克隆 Isaac Lab 仓库。 uv sync 会创建环境,并安装教程项目、Isaac Lab 及其运行时依赖。

此仓库也是 Isaac Lab 模板生成器 所生成下游项目的完整示例。创建自己的项目时,可使用模板生成器,再沿用此处的包布局和任务发现方式。

确认统一 CLI 能发现下游软件包:

uv run isaaclab --help
uv run python -c 'import importlib.metadata; print([e.name for e in importlib.metadata.entry_points(group="isaaclab.tasks")])'

第二条命令的输出应包含 so101-vial-place 。项目通过发布 isaaclab.tasks 入口点实现任务发现:

pyproject.toml#
[project.entry-points."isaaclab.tasks"]
so101-vial-place = "isaaclab_tutorial.tasks"

导入该软件包时,会注册三个 Gymnasium 任务 ID:

任务 ID

策略观测

IsaacTutorial-Place-Vial-SO101

机器人、样品瓶、支架、放置情况和任务进度的状态

IsaacTutorial-Place-Vial-SO101-Camera

使用 64 × 48 腕部 RGB 图像和本体感知信息,从头进行 PPO 训练

IsaacTutorial-Place-Vial-SO101-Camera-Distillation

从状态策略蒸馏视觉策略,使用与部署时相同的相机观测

小技巧

后续命令均在 IsaacLabTutorial 目录中运行。先训练基于状态的任务:它既是基线,也为蒸馏任务提供教师检查点。

2. 浏览项目#

项目将可复用的任务逻辑与 SO-101 专用配置分开:

IsaacLabTutorial/
|-- pyproject.toml                     package metadata and task-discovery entry point
|-- media/                              reference rollout
|-- src/isaaclab_tutorial/
|   |-- assets/                        workshop and reset-pose data
|   |-- tasks/place_vial/
|   |   |-- mdp/                       actions, events, observations, rewards, and progress logic
|   |   |-- reset/                     reset dataset, curriculum, and generation logic
|   |   `-- config/so101/
|   |       |-- __init__.py            Gymnasium task registration
|   |       |-- env_cfg.py             scene, MDP, and physics configuration
|   |       |-- camera_env_cfg.py      wrist-camera task variant
|   |       `-- agents/                PPO and distillation configurations and models
|   `-- utils/                         exact rollout evaluation helpers
`-- tests/                              behavioral and configuration contracts

这样的划分是有意设计的。添加新机器人时,创建与 config/so101 并列的目录,并复用样品瓶放置任务的 MDP;添加不同的操作任务时,创建与 tasks/place_vial 并列的目录,由新任务管理自己的任务项。

注册将任务 ID 与通用的基于管理器环境、任务配置和默认 RSL-RL 智能体连接起来:

src/isaaclab_tutorial/tasks/place_vial/config/so101/__init__.py#
gym.register(
    id="IsaacTutorial-Place-Vial-SO101",
    entry_point="isaaclab.envs:ManagerBasedRLEnv",
    disable_env_checker=True,
    kwargs={
        "env_cfg_entry_point": f"{_PACKAGE}.env_cfg:SO101VialEnvCfg",
        "rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:SO101StatePPORunnerCfg",
        "default_agent": "rsl_rl",
    },
)

因此,无需项目专用的启动脚本,常规 isaaclab train 、 play 和 benchmark 命令就能运行这些任务。

3. 理解任务#

环境通过 ManagerBasedRLEnvCfg 以声明式方式组装。主配置关联一个场景配置,以及各个 MDP 管理器的配置:

src/isaaclab_tutorial/tasks/place_vial/config/so101/env_cfg.py#
@configclass
class SO101VialEnvCfg(ManagerBasedRLEnvCfg):
    scene = SO101SceneCfg(num_envs=4096, env_spacing=0.9, replicate_physics=True)
    actions = ActionsCfg()
    observations = ObservationsCfg()
    events = DatasetEventsCfg()
    rewards = RewardsCfg()
    terminations = TerminationsCfg()

    def __post_init__(self):
        self.decimation = 4
        self.episode_length_s = 20.0
        self.is_finite_horizon = False
        self.sim.dt = 1.0 / 120.0
        self.sim.physics = PhysicsCfg()

仿真频率为 120 Hz,控制降采样倍数为 4,因此策略控制频率为 30 Hz。 replicate_physics=True 使相同场景能够扩展到数千个环境。

场景与控制#

SO101SceneCfg 包含固定基座的 SO-101、自由运动的 20 g 样品瓶、支架、碰撞垫、两个夹爪指和样品瓶上的接触传感器,以及穹顶光源。机器人配置、经过辨识的执行器动力学及限制均来自 Isaac Lab 的 SO101_CFG 。

六维策略动作包含五个有界的机械臂关节相对位置增量,以及一个有界的夹爪相对增量。任务不会将样品瓶附着到夹爪上,也不会在重置后直接写入样品瓶位姿。因此,抓取、搬运、插入和松开都必须通过仿真的接触作用完成。

MDP 概览#

组件

约定

动作

五个机械臂关节增量,每个控制步按 0.033 rad 缩放,以及一个夹爪增量。

基于状态的 Actor

关节状态与目标、上一动作、末端执行器状态、样品瓶状态、相对支架的目标、放置特征,以及不可逆的进度标志。

基于相机的 Actor

不包含物体状态:使用经过随机化的 64 × 48 腕部 RGB 图像,以及含噪声的关节状态、目标和上一动作。

Critic

特权状态观测和物理接触状态。

事件

采样重置位姿,并对样品瓶质量和摩擦进行小幅随机化。

奖励

少量物体到目标的奖励塑形项、物理进度节点奖励、成功奖励、丢失惩罚,以及较小的动作变化率和关节速度代价。

终止条件

放置成功、样品瓶丢失、机器人状态不稳定,或达到 20 s 时间上限。

物理进度与重置#

仅从桌面初始位姿开始,长时程操作任务很难学会。因此,项目在八个阶段中复用经过物理验证的重置位姿:

home -> pregrasp -> grasp -> lift -> reorient -> transport -> insert -> release

训练时,将这些阶段作为重置课程进行采样。每个阶段仍属于同一个任务,观测、动作、奖励和终止条件保持不变。只有出现物理证据时,进度标志才会推进,例如在预期抓取点附近检测到两侧夹爪接触,并测得能够承载样品瓶的抬升。交互式策略运行会回到第零阶段的起始状态,因此最终策略必须完成整个任务。

实际启用的奖励项刻意保持精简。大多数候选塑形项仍保留在配置中,但权重设为零,便于复现实验,避免将行为隐藏在临时代码里。物理判定条件见 mdp/terms.py ,重置分布见 reset/curriculum.py 。

状态策略与相机策略#

SO101VialEnvCfg 是完全可观测的基线。 SO101VialCameraEnvCfg 继承该配置,添加腕部相机,并仅替换 Actor 的观测;其非对称 Critic 在直接 PPO 训练期间仍保留完整状态。 SO101VialCameraDistillationEnvCfg 还提供基于状态的教师策略和仅用于训练的几何目标;部署时的学生策略仍只接收腕部 RGB 图像和本体感知信息。

4. 训练前验证#

先运行快速检查,在长时间 GPU 训练之前发现资源、注册、几何、奖励、重置数据和配置约定中的问题:

uv run pytest -q
uv run ruff check .

接着,构建一个小规模向量化环境,施加零动作并执行步进:

uv run isaaclab zero_agent \
  --task IsaacTutorial-Place-Vial-SO101 \
  --num_envs 8 --visualizer none presets=newton_mjwarp

如果检查失败,请先修复任务发现、资源加载或仿真稳定性问题,再调整强化学习。如果检查通过,则独立于学习算法测量环境性能:

uv run isaaclab benchmark runtime \
  --task IsaacTutorial-Place-Vial-SO101 \
  --num_envs 4096 --num_steps 1000 --warmup_steps 50 \
  --visualizer none presets=newton_mjwarp

如果当前 GPU 无法容纳该批次,请减小 --num_envs 。对于相机任务,添加 Newton 渲染器预设,并从较小批次开始:

uv run isaaclab benchmark runtime \
  --task IsaacTutorial-Place-Vial-SO101-Camera \
  --num_envs 1024 --num_steps 1000 --warmup_steps 50 \
  --visualizer none presets=newton_mjwarp,newton_renderer

5. 训练与评估#

使用 RSL-RL 训练基于状态的教师策略。任务的默认智能体配置运行 800 次迭代:

CUDA_VISIBLE_DEVICES=0 uv run isaaclab train --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101 \
  --num_envs 4096 --max_iterations 800 --seed 42 \
  --run_name so101_vial_seed42 --device cuda:0 \
  --visualizer none presets=newton_mjwarp

检查点和 TensorBoard 事件写入 logs/rsl_rl/so101_vial_state/<run> 下,最终检查点为 model_799.pt 。训练期间,可在另一个终端中查看学习曲线:

uv run tensorboard --logdir logs/rsl_rl/so101_vial_state

除了奖励,还要关注回合完成指标是否上升。奖励塑形可能使回报增加,却未必提高样品瓶成功松开放置的比例。

运行状态教师策略#

从标准初始阶段运行已训练的教师策略:

uv run isaaclab play --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101 \
  --num_envs 1 --checkpoint /path/to/state_model.pt --deterministic \
  --visualizer newton_gl presets=newton_mjwarp

策略轨迹应从标准初始阶段开始,拾取横放的样品瓶,将其转为竖直,移到目标孔上方,插入孔中,最后打开夹爪,让样品瓶在重力作用下落座到支架中。

蒸馏腕部相机策略#

将训练完成的教师策略传入专门的蒸馏任务。学生策略使用腕部 RGB 观测,因此需要添加渲染器预设:

CUDA_VISIBLE_DEVICES=0 uv run isaaclab train --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101-Camera-Distillation \
  --num_envs 1024 --max_iterations 800 --seed 42 \
  --checkpoint /path/to/state_teacher.pt \
  --run_name wrist_distillation_seed42 --device cuda:0 \
  --visualizer none presets=newton_mjwarp,newton_renderer

蒸馏使用单 GPU。有界回放 DAgger 运行器从教师轨迹开始,逐步加入学生策略的恢复状态,并始终保持至少 25% 的教师动作比例。仅用于训练的几何预测头提供密集的定位目标,稀疏随机权重平均则提高最终检查点的稳定性。输出写入 logs/rsl_rl/so101_vial_camera_distillation/<run> 下。

使用与训练时相同的任务 ID 运行蒸馏后的学生策略:

uv run isaaclab play --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101-Camera-Distillation \
  --num_envs 1 --checkpoint /path/to/distilled_model.pt --deterministic \
  --visualizer newton_gl presets=newton_mjwarp,newton_renderer

评估策略#

一段看起来成功的运行轨迹不能代替评估。通过项目的外部回调,以无界面方式运行已记录的第零阶段起始状态集合:

uv run isaaclab play --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101 \
  --num_envs 1024 --checkpoint /path/to/state_model.pt --deterministic \
  --external_callback isaaclab_tutorial.utils.evaluation.install_episode_counter \
  --visualizer none presets=newton_mjwarp

对蒸馏后的策略使用相同的 1024 个起始状态评估约定:

uv run isaaclab play --rl_library rsl_rl \
  --task IsaacTutorial-Place-Vial-SO101-Camera-Distillation \
  --num_envs 1024 --checkpoint /path/to/distilled_model.pt --deterministic \
  --external_callback isaaclab_tutorial.utils.evaluation.install_episode_counter \
  --visualizer none presets=newton_mjwarp,newton_renderer

回调会对每个已记录的起始状态运行一次,并输出一条 SO101_EVAL_RESULT JSON 记录。比较实验时,请保存此记录、检查点、随机种子、任务 ID 和解析后的配置。作为参考,教程 main 分支报告的状态教师策略成功率为 99.4%;对蒸馏策略重复验证时,成功率为 67.6%–72.9%,且没有不安全的支架接触。

维护重置数据集#

仓库中的重置数据集可直接用于训练。可以另行生成或检查候选数据集,而不覆盖现有数据:

uv run generate-so101-resets \
  --output checkpoints/reset_poses.pt --device cuda:0 \
  --visualizer none presets=newton_mjwarp

uv run view-so101-resets \
  --dataset checkpoints/reset_poses.pt --device cuda:0 \
  --visualizer newton_gl presets=newton_mjwarp

6. 改造为自己的任务#

每次只修改一个模块边界,并在训练前重新运行测试、零动作智能体检查和性能测试:

目标

修改位置

修改场景或 SO-101

config/so101/env_cfg.py 和 assets/

修改 Actor 输入

env_cfg.py 或 camera_env_cfg.py 中的观测组

修改任务行为

mdp/ 中的可复用函数和管理器项

修改重置覆盖范围

reset/curriculum.py 和经过验证的重置数据集

修改 PPO 或蒸馏

config/so101/agents/rsl_rl_ppo_cfg.py 、 rsl_rl_distillation_cfg.py 和 distillation.py

添加其他机器人

添加 config/<robot_name>/ ,在其中注册新的任务 ID;共享的 MDP 应保持与具体机器人无关。

添加其他操作任务

创建与 tasks/place_vial 并列的目录,包含新任务自己的 MDP 和机器人配置。

任务演进过程中,应保持以下约定:

  • 任务 ID 通过软件包入口点解析,不要复制 Isaac Lab 的启动脚本。

  • 策略动作的顺序和缩放比例与机器人命令约定一致。

  • 物理量和四元数遵循 Isaac Lab 当前的约定;Isaac Lab 3 使用 XYZW 四元数顺序。

  • 重置生成有效的物理状态,重置后的任务代码不直接瞬移被操作物体。

  • 成功条件要求样品瓶已经松开并在支架中正确落座,不能仅以靠近支架作为成功。

  • 测试应覆盖可观测的任务约定,性能测试则检查改动是否将高开销操作移入了每个环境的步进循环。

接下来,可通过 任务设计流程 了解管理器式与直接式架构,通过 强化学习 了解框架细节,通过 Hydra 配置系统 了解命令行覆盖配置的方法。