半小时入门具身智能:手动创建第一个 Isaac Lab 项目
具身智能零基础入门教程,从创建 IsaacSim 仿真项目、完成 MDP 配置与 Gym 环境注册,到训练、验证、可视化及奖励函数优化的完整闭环。
本文完整走一遍从创建 IsaacSim 仿真项目,到完成基本项目配置(MDP 配置、机器人模型配置、Gym 接口注册),再到训练、验证及可视化,最后完成策略优化的闭环流程。文章基于宇树 Go2 机器人,完整 Demo 已开源在 menoking/Go2-Demo。主要参考猫师傅的《米雪儿教你从零开始编写 Isaac Lab 强化学习环境》教程以及 Isaac Lab 官方 Quickstart Guide。
一、基础知识
1、强化学习扫盲
强化学习(RL):通过让智能体(Agent)与环境(Environment)交互,学习出能够最大化累积奖励(Cumulative Reward)的策略(Policy)。
核心四要素:
- 智能体 Agent
- 奖励 Reward
- 环境 Environment
- 策略 Policy
2、领域术语
机器人领域常见的文件格式:
| 格式 | 说明 |
|---|---|
| USD | 皮克斯开发的通用场景描述框架,以分层、非破坏式编辑为核心,是 Isaac Sim 的原生格式,支持复杂材质、动画和大规模场景合成 |
| URDF | 基于 XML 的机器人描述格式,定义连杆、关节、运动学和动力学属性,是 ROS 生态中机器人的标准表示 |
| SDF | Gazebo 专用的仿真描述格式,能完整描述整个世界(多机器人、地形、传感器、灯光等),比 URDF 更强大 |
| MJCF | MuJoCo 物理引擎的原生 XML 格式,描述紧凑、接触建模高效,广泛用于高频控制和足式机器人仿真 |
| XACRO | URDF 的宏语言扩展,支持参数化、模块化生成 URDF 文件,用于避免重复代码 |
| STL / OBJ / COLLADA (DAE) | 仅用于存储 3D 网格几何数据的静态格式,不包含运动学或动力学信息,常被 URDF/USD 作为视觉或碰撞网格引用 |
| GLTF / GLB | 面向实时渲染和 Web 传输的 3D 格式,集成了网格、材质、动画和皮肤,在图形交换中越来越普及 |
3、MDP 与 Isaac Lab 工作流
MDP(马尔可夫决策过程) 是强化学习问题形式化的数学基础,也是 Isaac Lab 中每个环境(Env)核心逻辑的设计依据。
- 在 Manager-based 工作流中,MDP 的各部分被拆解为独立的配置模块:
- Observation Manager:定义如何从物理状态映射到观测。
- Action Manager:定义动作空间及映射到实际控制量。
- Reward Manager:累加多个奖励项。
- Termination Manager:判断任务失败/成功条件。
- 在 Direct 工作流中,直接覆写
_get_observations()、_get_rewards()、_get_done_terminations()等方法。
二、项目创建
1、创建项目
键入以下命令新建项目:
isaaclab.bat -n进入配置页面(上下箭头移动,空格选中,回车确认):
- 工作流:Manager-based 是官方推荐的声明式主流框架,模块化结构化,适合复杂任务、快速原型开发和团队协作;Direct 是命令式框架,灵活自由度高,适合简单精细任务。
- RL 框架:
- rsl-rl:简单、专注且高效,是足式机器人任务快速验证的首选方案,由 ETH Zurich 研发,核心理念是”提供紧凑且易于修改的代码库”。
- SKRL(Skrl):灵活多样的”瑞士军刀”,提供 PPO、SAC 等丰富算法库,适合快速横向对比研究。
- RL Games:工业级”性能猛兽”,训练效率和稳定性极佳,适合超长时间大规模训练任务。
创建成功后,安装项目扩展:
python -m pip install -e source/<given-project-name>这条命令的作用:
- 安装基础环境,确保 Python 环境能够识别和导入 Isaac Lab 的核心功能。
- 以”可编辑”模式安装项目扩展,代码的任何修改都能立即生效,无需重新安装,便于开发。
用 VS Code 打开项目后,定位到 Manager-based 的配置文件 go2_demo_env_cfg.py,并在同目录下新建自己的配置文件(这里命名为 go2_demo_velocity.py)。
2、官方示例与仓库
以下两个官方源可以提前打开,其中机器人文件来源于 unitreerobotics/unitree_rl_lab 项目,官方模板参考的是 IsaacLab 中的 velocity_env_cfg.py 文件。
- IsaacLab 官方示例:velocity_env_cfg.py,一个基于 Manager-based 工作流的四足机器人速度追踪训练环境完整配置文件,定义了宇树 Go2 机器人在复杂地形上学习奔跑的强化学习任务。
- Unitree 宇树官方仓库:unitreerobotics/unitree_rl_lab,宇树机器人的强化学习专用环境仓库。
官方示例代码中,各代码块对应的 MDP 要素:
| 代码块 | 对应 MDP 要素 | 具体内容与作用 |
|---|---|---|
MySceneCfg | 场景与环境 | 包含带纹理的粗糙地形、Go2 机器人、射线高度扫描传感器(感知地形)、接触传感器(检测脚掌/大腿触地)以及天空光照 |
CommandsCfg | 高层指令(任务目标) | 生成随机线速度命令 (vx, vy) 和朝向角速度命令 (ang_vel_z),机器人需要追踪这个动态变化的指令,即”速度追踪任务”的核心 |
ActionsCfg | 动作空间 | 输出目标关节位置(JointPositionActionCfg),范围缩放 0.5,使用默认偏移量(机器人站立时的关节角度) |
ObservationsCfg | 观测状态 (S) | 定义策略网络输入,共 7 项:机体线速度/角速度、投影重力、速度命令、关节相对位置/速度、上一次动作、地形高度扫描,并对每项添加均匀噪声 |
EventCfg | 域随机化与初始化 | 分三类:startup(随机化物理材质、增加机身质量、改变质心位置)、reset(随机重置机器人根部位姿、关节位置/速度)、interval(随机时间间隔用力推机器人,提高抗干扰能力) |
RewardsCfg | 奖励函数 (R) | 速度追踪误差的指数奖励(线速度权重 1.0,角速度权重 0.5)+ 多项惩罚(竖向线速度、横向/俯仰角速度、关节力矩/加速度、动作变化率),奖励脚掌离地时间,惩罚大腿非预期触地 |
TerminationsCfg | 终止条件 | 超时(步数达到 episode_length_s / dt)和机身触地(base_contact) |
CurriculumCfg | 课程学习 | 根据机器人追踪速度的表现,自动提升地形难度等级 |
LocomotionVelocityRoughEnvCfg | 总配置类 | 组合上述所有模块,decimation=4(动作每 4 个仿真步执行一次,即控制频率 50Hz,仿真频率 200Hz),episode_length_s=20.0 |
三、项目配置
1、基本配置
新建 py 配置文件,导入所需包,并复制 LocomotionVelocityRoughEnvCfg 总配置类到自定义文件中,将类名修改为自定义名称,这里改为 GO2RobotDemoEnv。
2、MDP 类配置
以下所配置的 MDP 要素的每个参数都能在 IsaacLab 官方文档中搜索到释义与用法。
2.1 场景配置类 scene
构建包含地形、机器人和传感器的虚拟环境:
# 环境配置@configclassclass RobotSceneCfg(InteractiveSceneCfg): # 超平坦地形 terrain = TerrainImporterCfg( prim_path="/World/ground", terrain_type="plane", collision_group=-1, physics_material=sim_utils.RigidBodyMaterialCfg( friction_combine_mode="multiply", restitution_combine_mode="multiply", static_friction=1.0, dynamic_friction=1.0, ), visual_material=sim_utils.MdlFileCfg( mdl_path=f"{ISAACLAB_NUCLEUS_DIR}/Materials/TilesMarbleSpiderWhiteBrickBondHoned/TilesMarbleSpiderWhiteBrickBondHoned.mdl", project_uvw=True, texture_scale=(0.25, 0.25), ), debug_vis=False, )
robot: ArticulationCfg = RobotCFG.replace(prim_path="{ENV_REGEX_NS}/Robot")克隆 Go2 宇树官方 USD 文件:
git clone https://huggingface.co/datasets/unitreerobotics/unitree_model新建 assets/robot 目录(注意:assets 要和 task 同根目录),在此目录下克隆,并新建 unitree.py 文件对模型进行配置(注意脚本里路径应用正斜杠 /):
import os
import isaaclab.sim as sim_utilsfrom isaaclab.actuators import IdealPDActuatorCfg, ImplicitActuatorCfg, DCMotorCfgfrom isaaclab.assets.articulation import ArticulationCfgfrom isaaclab.utils import configclass
# 定义模型路径UNITREE_MODEL_DIR = "D:/EI/Project/go2_demo/source/go2_demo/go2_demo/assets/robot/unitree_model"
# Go2机器人配置UNITREE_GO2_CFG = ArticulationCfg( # 定义加载方式 spawn=sim_utils.UsdFileCfg( usd_path=f"{UNITREE_MODEL_DIR}/Go2/usd/go2.usd", # USD文件路径 activate_contact_sensors=True, # 读取传感器信息 rigid_props=sim_utils.RigidBodyPropertiesCfg( disable_gravity=False, retain_accelerations=False, linear_damping=0.0, angular_damping=0.0, max_linear_velocity=1000.0, max_angular_velocity=1000.0, max_depenetration_velocity=1.0, ), articulation_props=sim_utils.ArticulationRootPropertiesCfg( enabled_self_collisions=False, solver_position_iteration_count=4, solver_velocity_iteration_count=0, ), ), # 定义机器人初始状态 init_state=ArticulationCfg.InitialStateCfg( pos=(0.0, 0.0, 0.4), joint_pos={ ".*R_hip_joint": -0.1, ".*L_hip_joint": 0.1, "F[L,R]_thigh_joint": 0.8, "R[L,R]_thigh_joint": 1.0, ".*_calf_joint": -1.5, }, joint_vel={".*": 0.0}, ), # 软限位系数 soft_joint_pos_limit_factor=0.9, # 核心:执行器模型 actuators={ "legs": DCMotorCfg( joint_names_expr=[".*"], effort_limit=23.5, # 输出力矩上限 saturation_effort=23.5, velocity_limit=30.0, stiffness=25.0, # PD控制中的P damping=0.5, # PD控制中的D friction=0.01, # 执行器摩擦系数 ), },)注意:这里把宇树的子类换成对应的父类(如
IdealPDActuatorCfg→DCMotorCfg),可在 IsaacLab 中查看对应配置项的参数信息。
回到 go2_demo_velocity.py 导入自定义机器人配置,并补充传感器:
# 导入自定义机器人配置from go2_demo.assets.robot.unitree import UNITREE_GO2_CFG as RobotCFG
robot: ArticulationCfg = RobotCFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
# 传感器height_scanner = RayCasterCfg( prim_path="{ENV_REGEX_NS}/Robot/base", offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)), ray_alignment="yaw", pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]), debug_vis=False, mesh_prim_paths=["/World/ground"],)contact_forces = ContactSensorCfg(prim_path="{ENV_REGEX_NS}/Robot/.*", history_length=3, track_air_time=True)
sky_light = AssetBaseCfg( prim_path="/World/skyLight", spawn=sim_utils.DomeLightCfg( intensity=750.0, texture_file=f"{ISAAC_NUCLEUS_DIR}/Materials/Textures/Skies/PolyHaven/kloofendal_43d_clear_puresky_4k.hdr", ),)2.2 观测配置类 observations
定义策略网络可获取的状态信息(如关节角度、速度、地形扫描)。注意先导入 mdp 包,再定义策略网络和评价网络的观测项框架:
@configclassclass ObservationsCfg: # 策略网络 @configclass class PolicyCfg(ObsGroup): """Observations for policy group.""" # 机体线速度 base_lin_vel = ObsTerm(func=mdp.base_lin_vel, noise=Unoise(n_min=-0.1, n_max=0.1)) # 机体角速度 base_ang_vel = ObsTerm(func=mdp.base_ang_vel, noise=Unoise(n_min=-0.2, n_max=0.2)) # 投影重力 projected_gravity = ObsTerm( func=mdp.projected_gravity, noise=Unoise(n_min=-0.05, n_max=0.05), ) # 速度指令 velocity_commands = ObsTerm(func=mdp.generated_commands, params={"command_name": "base_velocity"}) # 关节位置 joint_pos = ObsTerm(func=mdp.joint_pos_rel, noise=Unoise(n_min=-0.01, n_max=0.01)) # 关节速度 joint_vel = ObsTerm(func=mdp.joint_vel_rel, noise=Unoise(n_min=-1.5, n_max=1.5)) # 上一次动作 actions = ObsTerm(func=mdp.last_action) # 高度扫描 height_scan = ObsTerm( func=mdp.height_scan, params={"sensor_cfg": SceneEntityCfg("height_scanner")}, noise=Unoise(n_min=-0.1, n_max=0.1), clip=(-1.0, 1.0), )
def __post_init__(self): self.enable_corruption = True self.concatenate_terms = True
# observation groups policy: PolicyCfg = PolicyCfg()
# 评价网络 @configclass class CriticCfg(ObsGroup): base_lin_vel = ObsTerm(func=mdp.base_lin_vel, noise=Unoise(n_min=-0.1, n_max=0.1)) base_ang_vel = ObsTerm(func=mdp.base_ang_vel, noise=Unoise(n_min=-0.2, n_max=0.2)) projected_gravity = ObsTerm( func=mdp.projected_gravity, noise=Unoise(n_min=-0.05, n_max=0.05), ) velocity_commands = ObsTerm(func=mdp.generated_commands, params={"command_name": "base_velocity"}) joint_pos = ObsTerm(func=mdp.joint_pos_rel, noise=Unoise(n_min=-0.01, n_max=0.01)) joint_vel = ObsTerm(func=mdp.joint_vel_rel, noise=Unoise(n_min=-1.5, n_max=1.5)) actions = ObsTerm(func=mdp.last_action) height_scan = ObsTerm( func=mdp.height_scan, params={"sensor_cfg": SceneEntityCfg("height_scanner")}, noise=Unoise(n_min=-0.1, n_max=0.1), clip=(-1.0, 1.0), )
critic: CriticCfg = CriticCfg()2.3 动作配置类 actions
指定智能体输出的控制指令类型(如关节位置、速度或力矩):
# 动作配置@configclassclass ActionsCfg: """Action specifications for the MDP."""
joint_pos = mdp.JointPositionActionCfg( asset_name="robot", joint_names=[".*"], scale=0.5, use_default_offset=True, )2.4 指令配置类 commands
生成任务目标(如期望速度或朝向),供策略追踪:
@configclassclass CommandsCfg: """Command specifications for the MDP."""
base_velocity = mdp.UniformVelocityCommandCfg( asset_name="robot", resampling_time_range=(10.0, 10.0), rel_standing_envs=0.02, rel_heading_envs=1.0, heading_command=True, heading_control_stiffness=0.5, debug_vis=True, ranges=mdp.UniformVelocityCommandCfg.Ranges( lin_vel_x=(-1.0, 1.0), lin_vel_y=(-1.0, 1.0), ang_vel_z=(-1.0, 1.0), heading=(-math.pi, math.pi), ), )2.5 奖励配置类 rewards
计算每一步的奖励信号,引导策略学习期望行为:
# 奖励函数@configclassclass RewardsCfg: track_lin_vel_xy_exp = RewTerm( func=mdp.track_lin_vel_xy_exp, weight=1.0, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}, ) track_ang_vel_z_exp = RewTerm( func=mdp.track_ang_vel_z_exp, weight=0.5, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}, )2.6 终止条件配置类 terminations
设定环境结束条件(如机器人摔倒或超时):
# 终止条件@configclassclass TerminationsCfg: # 时间终止 time_out = DoneTerm(func=mdp.time_out, time_out=True) # 机身碰撞地面 base_contact = DoneTerm( func=mdp.illegal_contact, params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names="base"), "threshold": 1.0}, ) # 倾斜角度 bad_orientation = DoneTerm(func=mdp.bad_orientation, params={"limit_angle": 0.8})2.7 事件配置类 events
配置域随机化、初始状态扰动等事件,增强策略鲁棒性:
# 事件配置@configclassclass EventCfg: reset_base = EventTerm( func=mdp.reset_root_state_uniform, # 触发函数 mode="reset", # 触发时机--复位 params={ "pose_range": {"x": (-0.5, 0.5), "y": (-0.5, 0.5), "yaw": (-3.14, 3.14)}, "velocity_range": { "x": (-0.0, 0.0), "y": (-0.0, 0.0), "z": (-0.0, 0.0), "roll": (-0.0, 0.0), "pitch": (-0.0, 0.0), "yaw": (-0.0, 0.0), }, }, )2.8 课程学习配置类 curriculum
根据智能体当前表现动态调整任务难度(如地形等级),实现渐进式训练以加速策略收敛。本次暂不对其进行配置,直接注释即可。
3、注册 Gym 环境
复制 __init__.py 文件中的注册部分代码,修改如下:
gym.register( id="Go2-velocity-v0", # 环境ID entry_point="isaaclab.envs:ManagerBasedRLEnv", disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.go2_demo_velocity:GO2RobotDemoEnv", # 环境文件名:环境类名 "rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:PPORunnerCfg", },)4、调整 PPO 网络
文件位置在 agents/rsl_rl_ppo_cfg.py,调整至以下:
@configclassclass PPORunnerCfg(RslRlOnPolicyRunnerCfg): num_steps_per_env = 124 max_iterations = 50000 save_interval = 100 experiment_name = "go2_demo" policy = RslRlPpoActorCriticCfg( init_noise_std=1.0, actor_hidden_dims=[512, 256, 128], critic_hidden_dims=[32, 32], activation="elu", ) algorithm = RslRlPpoAlgorithmCfg( value_loss_coef=1.0, use_clipped_value_loss=True, clip_param=0.2, entropy_coef=0.005, num_learning_epochs=5, num_mini_batches=4, learning_rate=1.0e-3, schedule="adaptive", gamma=0.99, lam=0.95, desired_kl=0.01, max_grad_norm=1.0, )四、验证与训练
1、验证环境
在 conda 环境下运行随机策略:
python scripts\random_agent.py --task Go2-velocity-v0 --num_envs 14跑通后机器人开始运动。再运行零策略验证(机器人静止状态):
python scripts\zero_agent.py --task Go2-velocity-v0 --num_envs 142、正式训练
无窗口渲染训练:
python scripts\rsl_rl\train.py --task Go2-velocity-v0 --num_envs=400 --max_iterations 1000 --headless3、参数可视化
TensorBoard 查看训练曲线:
tensorboard --logdir logs4、评估策略
运行下列命令,观察训练的最终模型效果并保存模型权重文件:
python scripts\rsl_rl\play.py --task Go2-velocity-v0 --num_envs 16在仿真器中可以观察到四足机器人的行走姿态。
五、优化策略
主要针对奖励函数作优化,将速度追踪权重调大,并添加了几个约束惩罚项:
# 奖励函数@configclassclass RewardsCfg: # 线速度追踪 track_lin_vel_xy_exp = RewTerm( func=mdp.track_lin_vel_xy_exp, weight=3.0, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}, ) # 角速度追踪 track_ang_vel_z_exp = RewTerm( func=mdp.track_ang_vel_z_exp, weight=1.5, params={"command_name": "base_velocity", "std": math.sqrt(0.25)}, ) # 约束姿态 flat_orientation_l2 = RewTerm(func=mdp.flat_orientation_l2, weight=-2.5) # 限制某些部位不着地 undesired_contacts = RewTerm( func=mdp.undesired_contacts, weight=-1.0, params={ "sensor_cfg": SceneEntityCfg( "contact_forces", body_names=["Head_.*", ".*_hip", ".*thigh", ".*_calf"], ), "threshold": 1.0, }, ) # 惩罚关节速度 joint_vel = RewTerm(func=mdp.joint_vel_l2, weight=-0.001) # 惩罚关节加速度 joint_acc = RewTerm(func=mdp.joint_acc_l2, weight=-2.5e-7) # 惩罚输出力矩过大 joint_torques = RewTerm(func=mdp.joint_torques_l2, weight=-2e-4) # 惩罚相邻时刻动作变化过大 action_rate = RewTerm(func=mdp.action_rate_l2, weight=-0.1)重新训练后再评估,四足机器人的姿态会明显改善。
六、总结
本文完整走了一遍 IsaacLab 中的机器人仿真训练流程,从环境搭建、MDP 配置到训练与奖励调优。主要参考 猫猫烤肉师傅的 B 站免费教程 与 Isaac Lab 官方文档,并对视频中未放出的代码和概念做了补充。如有错误,欢迎指正。


