Isaac Lab 机器人强化学习实战:配置架构、添加流程与调参技巧
Isaac Lab 框架下 Robot Lab 库的强化学习配置体系。涵盖配置继承机制、新机器人添加五步流程(资产、Agent、环境配置、注册)及调参策略。重点解析四足、人形、轮式机器人的奖励函数设计差异,如人形需禁用地形课程并强化腾空时间奖励。提供训练测试命令及 TensorBoard 监控方法,帮助开发者快速构建稳定高效的机器人运动控制策略。

Isaac Lab 框架下 Robot Lab 库的强化学习配置体系。涵盖配置继承机制、新机器人添加五步流程(资产、Agent、环境配置、注册)及调参策略。重点解析四足、人形、轮式机器人的奖励函数设计差异,如人形需禁用地形课程并强化腾空时间奖励。提供训练测试命令及 TensorBoard 监控方法,帮助开发者快速构建稳定高效的机器人运动控制策略。

Robot Lab 是基于 NVIDIA Isaac Lab 构建的机器人强化学习扩展库,专注于足式机器人的运动控制任务。该项目目前已支持包括 Unitree Go2、G1、H1 在内的十余款主流机器人平台。与原生 Isaac Lab 相比,Robot Lab 提供了更加完善的奖励函数库、域随机化配置以及针对不同机器人形态优化的训练参数。
在深入技术细节之前,有必要先理解 Isaac Lab 的基本架构。Isaac Lab 构建于 Isaac Sim 之上,采用分层设计:最底层是 Omniverse 渲染引擎与 PhysX 物理引擎,中间层是 Isaac Sim 提供的机器人仿真接口,最上层则是 Isaac Lab 封装的强化学习环境。Robot Lab 在此基础上进一步抽象,将运动控制任务的通用配置提取为基类,使得添加新机器人变得简单高效。
Robot Lab 的环境配置采用面向对象的继承体系,这一设计决策源于对机器人强化学习任务共性的深刻理解。无论是四足机器人、人形机器人还是轮式机器人,其速度跟踪任务都包含相似的核心组件:观测空间定义、动作空间设计、奖励函数构建等。将这些共性抽象为基类,可以显著减少重复代码,同时保持各机器人配置的独立性与可维护性。
继承链从 Isaac Lab 的 ManagerBasedRLEnvCfg 基类开始,该类定义了强化学习环境的基本框架。Robot Lab 在此基础上派生出 LocomotionVelocityRoughEnvCfg,封装了运动控制任务的通用配置。针对具体机器人,如 G1,则进一步派生出粗糙地形配置 UnitreeG1RoughEnvCfg,最后是针对平地训练的简化配置 UnitreeG1FlatEnvCfg。
这种多层继承结构带来三个核心优势。首先是代码复用:基类中定义的 30 余个奖励项、8 种域随机化事件、多组传感器配置等均可被所有子类继承,无需重复编写。其次是灵活定制:每个机器人可以通过 __post_init__ 方法选择性地覆盖父类参数,例如 G1 需要启用摔倒惩罚而四足机器人可能不需要。最后是易于维护:当基类的奖励函数实现优化后,所有子类自动受益,无需逐一修改。
LocomotionVelocityRoughEnvCfg 是 Robot Lab 运动控制任务的核心基类,位于 velocity_env_cfg.py 文件中。该类定义了构成马尔可夫决策过程(MDP)的全部要素,包括状态空间、动作空间、奖励函数、状态转移规则等。理解这个基类的设计,是掌握整个 Robot Lab 配置体系的关键。
基类的核心结构如下,包含 8 个配置模块:
@configclass
class LocomotionVelocityRoughEnvCfg(ManagerBasedRLEnvCfg):
"""运动速度跟踪环境配置基类"""
# 场景配置:定义物理世界
scene: MySceneCfg = MySceneCfg(num_envs=4096, env_spacing=2.5)
# MDP 输入配置
observations: ObservationsCfg = ObservationsCfg()
actions: ActionsCfg = ActionsCfg()
commands: CommandsCfg = CommandsCfg()
# MDP 训练配置
rewards: RewardsCfg = RewardsCfg()
terminations: TerminationsCfg = TerminationsCfg()
events: EventCfg = EventCfg()
curriculum: CurriculumCfg = CurriculumCfg()
这 8 个模块可以分为两类:输入配置(Scene、Commands、Actions、Observations)定义了智能体与环境的交互接口;训练配置(Rewards、Terminations、Events、Curriculum)则控制训练过程的行为。以下逐一详解各模块的设计原理与关键参数。
场景配置定义了仿真环境中的物理世界,包括地形、机器人模型以及各类传感器。在 Isaac Lab 的架构中,场景是所有物理实体的容器,其配置直接影响仿真的物理真实性与计算效率。
@configclass
class MySceneCfg(InteractiveSceneCfg):
"""场景配置:定义地形、机器人、传感器"""
# 地形配置
terrain = TerrainImporterCfg(
prim_path="/World/ground",
terrain_type="generator",
terrain_generator=ROUGH_TERRAINS_CFG,
max_init_terrain_level=5,
collision_group=-1,
physics_material=sim_utils.RigidBodyMaterialCfg(
friction_combine_mode="multiply",
static_friction=1.0,
dynamic_friction=1.0,
),
)
# 机器人配置(由子类具体指定)
robot: ArticulationCfg = MISSING
# 高度扫描传感器:用于感知前方地形起伏
height_scanner = RayCasterCfg(
prim_path="{ENV_REGEX_NS}/Robot/base",
offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)),
pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]),
mesh_prim_paths=["/World/ground"],
)
# 接触力传感器:检测机器人与环境的接触
contact_forces = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/.*",
history_length=3,
track_air_time=True,
)
这里有几个关键设计值得深入理解。首先是 {ENV_REGEX_NS} 占位符,这是 Isaac Lab 实现大规模并行仿真的核心机制。当设置 num_envs=4096 时,Isaac Lab 会自动将场景中的机器人克隆 4096 份,每份位于独立的命名空间中。{ENV_REGEX_NS} 在运行时会被替换为 /World/envs/env_0、/World/envs/env_1 等具体路径,从而实现单个配置支持大规模并行训练。
其次是高度扫描传感器的设计。该传感器模拟了真实机器人上常见的激光雷达或深度相机,通过向下发射射线网格来感知前方地形。默认配置采用 0.1m 分辨率、1.6m×1.0m 范围的网格,这一参数需要根据机器人的尺寸和任务需求进行调整。
命令配置定义了策略需要跟踪的目标速度。在速度跟踪任务中,命令生成器会周期性地产生新的目标速度,策略的目标是使机器人的实际速度尽可能接近这些命令值。
@configclass
class CommandsCfg:
"""命令配置:定义目标速度的采样范围与重采样策略"""
base_velocity = mdp.UniformThresholdVelocityCommandCfg(
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,
ranges=mdp.UniformThresholdVelocityCommandCfg.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),
),
)
rel_standing_envs=0.02 这个参数蕴含重要的训练技巧。在强化学习训练过程中,如果所有环境都持续发送非零速度命令,策略可能学不会站立不动。通过让 2% 的环境持续发送零速度命令,可以确保策略具备稳定站立的能力。
动作配置定义了策略网络输出如何转换为机器人的控制指令。Robot Lab 主要采用关节位置控制模式,即策略输出目标关节角度,底层 PD 控制器负责跟踪这些目标角度。
@configclass
class ActionsCfg:
"""动作配置:定义策略输出到关节控制的映射"""
joint_pos = mdp.JointPositionActionCfg(
asset_name="robot",
joint_names=[".*"],
scale=0.5,
use_default_offset=True,
clip=None,
preserve_order=True,
)
scale 参数是动作配置中最关键的超参数之一。策略网络通常输出 [-1, 1] 范围内的归一化动作值,scale=0.5 意味着将其映射为 [-0.5, 0.5] 弧度的关节角度偏移。
对于轮式机器人如 Go2W,动作配置需要更复杂的设计,因为腿部关节和轮子关节需要不同的控制模式:
# 轮式机器人的混合动作配置
@configclass
class UnitreeGo2WActionsCfg(ActionsCfg):
# 腿部关节:位置控制
joint_pos = mdp.JointPositionActionCfg(
joint_names=[".*_hip_joint", ".*_thigh_joint", ".*_calf_joint"],
scale=0.25,
)
# 轮子关节:速度控制
joint_vel = mdp.JointVelocityActionCfg(
joint_names=[".*_foot_joint"],
scale=5.0,
)
观测配置是连接环境状态与策略输入的桥梁。Robot Lab 采用了非对称 Actor-Critic 架构的观测设计:策略网络(Actor)接收带噪声的观测,模拟真实传感器的测量误差;评论家网络(Critic)则接收无噪声的"特权信息"。
@configclass
class ObservationsCfg:
"""观测配置:定义策略和评论家的输入"""
@configclass
class PolicyCfg(ObsGroup):
"""策略网络观测组 - 带噪声以模拟真实传感器"""
base_lin_vel = ObsTerm(
func=mdp.base_lin_vel,
noise=Unoise(n_min=-0.1, n_max=0.1),
clip=(-100.0, 100.0),
scale=1.0,
)
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)
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, noise=Unoise(n_min=-0.1, n_max=0.1))
def __post_init__(self):
self.enable_corruption = True
self.concatenate_terms = True
@configclass
class CriticCfg(ObsGroup):
"""评论家网络观测组 - 无噪声的特权信息"""
# 与 PolicyCfg 相同的观测项,但不添加噪声
def __post_init__(self):
self.enable_corruption =
policy: PolicyCfg = PolicyCfg()
critic: CriticCfg = CriticCfg()
观测设计中有几个值得关注的细节。首先,projected_gravity 提供了机器人姿态的关键信息。其次,last_action 的加入为策略提供了时序连续性。噪声的设置也有讲究,关节位置的噪声相对较小,关节速度的噪声则较大。
域随机化(Domain Randomization)是弥合仿真与现实差距的核心技术。其基本思想是:如果策略能够在具有广泛物理参数变化的仿真环境中稳定工作,那么它很可能也能在真实世界中表现良好。
@configclass
class EventCfg:
"""事件配置:定义域随机化策略"""
# ========== startup 事件:每个仿真会话执行一次 ==========
randomize_rigid_body_material = EventTerm(
func=mdp.randomize_rigid_body_material,
mode="startup",
params={
"asset_cfg": SceneEntityCfg("robot", body_names=".*"),
"static_friction_range": (0.3, 1.0),
"dynamic_friction_range": (0.3, 0.8),
"restitution_range": (0.0, 0.5),
"num_buckets": 64,
},
)
randomize_rigid_body_mass_base = EventTerm(
func=mdp.randomize_rigid_body_mass,
mode="startup",
params={
"asset_cfg": SceneEntityCfg("robot", body_names="base"),
"mass_distribution_params": (-1.0, 3.0),
"operation": "add",
"recompute_inertia": True,
},
)
# ========== reset 事件:每个 episode 开始时执行 ==========
randomize_actuator_gains = EventTerm(
func=mdp.randomize_actuator_gains,
mode="reset",
params={
"asset_cfg": SceneEntityCfg("robot", joint_names=".*"),
"stiffness_distribution_params": (0.5, 2.0),
"damping_distribution_params": (0.5, 2.0),
: ,
},
)
randomize_reset_base = EventTerm(
func=mdp.reset_root_state_uniform,
mode=,
params={
: {: (-, ), : (-, ), : (-, )},
: {: (-, ), : (-, )},
},
)
randomize_push_robot = EventTerm(
func=mdp.push_by_setting_velocity,
mode=,
interval_range_s=(, ),
params={: {: (-, ), : (-, )}},
)
三种事件模式的设计体现了对真实世界不确定性来源的深刻理解。Startup 事件模拟的是制造公差,Reset 事件模拟的是使用场景的多样性,Interval 事件则模拟运行时的外部干扰。
奖励函数是强化学习的核心,它定义了我们希望智能体学习的行为。Robot Lab 提供了超过 30 个预定义的奖励项。
@configclass
class RewardsCfg:
"""奖励配置:定义强化学习的目标函数"""
# ==================== 核心任务奖励 ====================
track_lin_vel_xy_exp = RewTerm(
func=mdp.track_lin_vel_xy_exp,
weight=0.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.0,
params={"command_name": "base_velocity", "std": math.sqrt(0.25)},
)
# ==================== 基座稳定性惩罚 ====================
lin_vel_z_l2 = RewTerm(func=mdp.lin_vel_z_l2, weight=0.0)
ang_vel_xy_l2 = RewTerm(func=mdp.ang_vel_xy_l2, weight=0.0)
flat_orientation_l2 = RewTerm(func=mdp.flat_orientation_l2, weight=0.0)
# ==================== 能耗与平滑性惩罚 ====================
joint_torques_l2 = RewTerm(func=mdp.joint_torques_l2, weight=0.0)
joint_acc_l2 = RewTerm(func=mdp.joint_acc_l2, weight=0.0)
action_rate_l2 = RewTerm(func=mdp.action_rate_l2, weight=0.0)
joint_power = RewTerm(func=mdp.joint_power, weight=0.0)
# ==================== 步态相关奖励 ====================
feet_air_time = RewTerm(func=mdp.feet_air_time, weight=0.0)
feet_gait = RewTerm(func=mdp.GaitReward, weight=0.0)
feet_slide = RewTerm(func=mdp.feet_slide, weight=0.0)
feet_stumble = RewTerm(func=mdp.feet_stumble, weight=0.0)
# ==================== 安全与约束 ====================
joint_pos_limits = RewTerm(func=mdp.joint_pos_limits, weight=0.0)
undesired_contacts = RewTerm(func=mdp.undesired_contacts, weight=0.0)
is_terminated = RewTerm(func=mdp.is_terminated, weight=0.0)
奖励函数的设计遵循几个核心原则。第一是稀疏与稠密的平衡,第二是正负奖励的平衡,第三是物理意义的清晰性。基类中所有奖励项的默认权重都是 0,这意味着它们默认处于禁用状态。
终止条件定义了 episode 何时结束。合理的终止条件对训练效率至关重要。
@configclass
class TerminationsCfg:
"""终止条件配置"""
time_out = DoneTerm(func=mdp.time_out, time_out=True)
terrain_out_of_bounds = DoneTerm(
func=mdp.terrain_out_of_bounds,
params={"asset_cfg": SceneEntityCfg("robot"), "distance_buffer": 3.0},
time_out=True,
)
illegal_contact = DoneTerm(
func=mdp.illegal_contact,
params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names=""), "threshold": 1.0},
)
time_out=True 参数区分了两类终止:超时终止和失败终止。这一区分在 PPO 等算法中用于正确估计价值函数。
课程学习是一种渐进式训练策略,通过逐步增加任务难度来提高学习效率。
@configclass
class CurriculumCfg:
"""课程学习配置"""
terrain_levels = CurrTerm(func=mdp.terrain_levels_vel)
command_levels_lin_vel = CurrTerm(
func=mdp.command_levels_lin_vel,
params={"reward_term_name": "track_lin_vel_xy_exp", "range_multiplier": (0.1, 1.0)},
)
command_levels_ang_vel = CurrTerm(
func=mdp.command_levels_ang_vel,
params={"reward_term_name": "track_ang_vel_z_exp", "range_multiplier": (0.1, 1.0)},
)
range_multiplier=(0.1, 1.0) 意味着训练初期只使用目标范围的 10%,随着策略改进逐步增加到 100%。
理解了基类的设计之后,我们来看如何通过子类实现机器人特定的配置。
@configclass
class UnitreeG1RoughEnvCfg(LocomotionVelocityRoughEnvCfg):
"""Unitree G1 人形机器人粗糙地形环境配置"""
base_link_name = "torso_link"
foot_link_name = ".*_ankle_roll_link"
def __post_init__(self):
super().__post_init__()
# ==================== 场景配置 ====================
self.scene.robot = UNITREE_G1_29DOF_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/" + self.base_link_name
# ==================== 观测配置 ====================
self.observations.policy.base_lin_vel.scale = 2.0
self.observations.policy.base_ang_vel.scale = 0.25
self.observations.policy.joint_vel.scale = 0.05
self.observations.policy.base_lin_vel = None
self.observations.policy.height_scan = None
# ==================== 动作配置 ====================
self.actions.joint_pos.scale = UNITREE_G1_29DOF_ACTION_SCALE
# ==================== 奖励配置(核心定制部分)====================
self.rewards.is_terminated.weight = -200.0
self.rewards.track_lin_vel_xy_exp.weight = 3.0
self.rewards.track_lin_vel_xy_exp.func = mdp.track_lin_vel_xy_yaw_frame_exp
self.rewards.track_ang_vel_z_exp.weight = 3.0
self.rewards.ang_vel_xy_l2.weight = -
.rewards.flat_orientation_l2.weight = -
.rewards.joint_torques_l2.weight = -
.rewards.joint_acc_l2.weight = -
.rewards.action_rate_l2.weight = -
.rewards.feet_air_time.weight =
.rewards.feet_air_time.func = mdp.feet_air_time_positive_biped
.rewards.feet_slide.weight = -
.rewards.upward.weight =
.__class__.__name__ == :
.disable_zero_weight_rewards()
.curriculum.terrain_levels =
.curriculum.command_levels_lin_vel =
.curriculum.command_levels_ang_vel =
这段配置代码展示了几个重要的定制点。首先,is_terminated.weight = -200.0 的设置反映了人形机器人与四足机器人的本质差异。其次,观测缩放因子的调整体现了对不同机器人动力学特性的适配。最后,课程学习的禁用是一个实践经验的体现。
在完成粗糙地形配置之后,Robot Lab 通常还会提供一个平地配置作为训练的入门版本。
@configclass
class UnitreeG1FlatEnvCfg(UnitreeG1RoughEnvCfg):
def __post_init__(self):
super().__post_init__()
self.scene.terrain.terrain_type = "plane"
self.scene.terrain.terrain_generator = None
self.scene.height_scanner = None
self.observations.policy.height_scan = None
self.curriculum.terrain_levels = None
self.rewards.track_ang_vel_z_exp.weight = 1.0
平地配置的核心修改可以归纳为三个方面。第一是地形简化,第二是传感器简化,第三是课程禁用。
Robot Lab 支持多种强化学习框架,其中 RSL-RL 是最常用的选择。Agent 配置定义了强化学习算法的超参数,包括网络架构、优化器设置、PPO 特定参数等。
RL Agent 配置位于各机器人目录下的 agents/rsl_rl_ppo_cfg.py 文件中。
@configclass
class UnitreeG1RoughPPORunnerCfg(RslRlOnPolicyRunnerCfg):
# ===== 训练控制参数 =====
num_steps_per_env = 24
max_iterations = 20000
save_interval = 200
experiment_name = "unitree_g1_rough"
# ===== 网络架构配置 =====
policy = RslRlPpoActorCriticCfg(
init_noise_std=1.0,
actor_obs_normalization=False,
critic_obs_normalization=False,
actor_hidden_dims=[512, 256, 128],
critic_hidden_dims=[512, 256, 128],
activation="elu",
)
# ===== PPO 算法超参数 =====
algorithm = RslRlPpoAlgorithmCfg(
value_loss_coef=1.0,
use_clipped_value_loss=True,
clip_param=0.2,
entropy_coef=0.008,
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,
)
| 参数 | 默认值 | 说明 |
|---|---|---|
num_steps_per_env | 24 | 每个环境在一次更新中采样的步数 |
actor_hidden_dims | [512, 256, 128] | Actor 网络架构 |
clip_param | 0.2 | PPO 裁剪范围,防止策略更新过大 |
entropy_coef | 0.008-0.01 | 熵系数,控制探索程度 |
gamma | 0.99 | 折扣因子,决定对未来奖励的重视程度 |
lam | 0.95 | GAE 参数,平衡偏差和方差 |
desired_kl | 0.01 | 目标 KL 散度,用于自适应学习率 |
num_steps_per_env:决定了在每次策略更新前,每个并行环境需要收集多少步的经验数据。对于运动控制任务,24 是一个经过验证的合理默认值。
clip_param:这是 PPO 算法的核心超参数,用于限制策略更新的幅度。0.2 是论文推荐的默认值。
entropy_coef:熵正则化用于鼓励策略保持一定程度的随机性。Robot Lab 中人形机器人使用 0.008,四足机器人使用 0.01。
schedule="adaptive":RSL-RL 支持自适应学习率调整,当策略更新的 KL 散度超过 desired_kl 时自动降低学习率。
| 参数 | G1 (人形) | GO2 (四足) | Agibot D1 |
|---|---|---|---|
max_iterations | 20000 | 20000 | 20000 |
entropy_coef | 0.008 | 0.01 | 0.01 |
save_interval | 200 | 100 | 100 |
从表中可以看出,人形机器人的熵系数略低于四足机器人。这是因为人形机器人的平衡更加困难,需要策略输出更加确定的动作来维持稳定。
将新机器人集成到 Robot Lab 是一个结构化的过程,需要按照特定的步骤创建配置文件并注册环境。
添加新机器人涉及 5 个核心步骤,需要在两个目录下创建相应的文件。assets/ 目录存放机器人资产配置,定义模型文件路径、关节参数、执行器特性等;tasks/.../config/ 目录存放任务配置。
robot_lab/
├── assets/
│ └── agibot.py
└── tasks/manager_based/locomotion/velocity/config/quadruped/agibot_d1/
├── __init__.py
├── rough_env_cfg.py
├── flat_env_cfg.py
└── agents/
├── __init__.py
├── rsl_rl_ppo_cfg.py
└── cusrl_ppo_cfg.py
资产配置是添加新机器人的第一步,它定义了机器人的物理模型如何在仿真环境中加载和初始化。
import isaaclab.sim as sim_utils
from isaaclab.actuators import DCMotorCfg
from isaaclab.assets.articulation import ArticulationCfg
from robot_lab.assets import ISAACLAB_ASSETS_DATA_DIR
AGIBOT_D1_CFG = ArticulationCfg(
spawn=sim_utils.UrdfFileCfg(
fix_base=False,
merge_fixed_joints=True,
asset_path=f"{ISAACLAB_ASSETS_DATA_DIR}/Robots/agibot/d1/urdf/edu.urdf",
activate_contact_sensors=True,
rigid_props=sim_utils.RigidBodyPropertiesCfg(
disable_gravity=False,
max_linear_velocity=1000.0,
max_angular_velocity=1000.0,
),
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
enabled_self_collisions=False,
solver_position_iteration_count=4,
),
),
init_state=ArticulationCfg.InitialStateCfg(
pos=(0.0, 0.0, 0.42),
joint_pos={
".*L_ABAD_JOINT": 0.0,
".*R_ABAD_JOINT": 0.0,
"F.*_HIP_JOINT": 0.8,
"R.*_HIP_JOINT": 0.8,
".*_KNEE_JOINT": -1.5,
},
joint_vel={".*": 0.0},
),
actuators={"legs": DCMotorCfg(
joint_names_expr=[".*_(ABAD|HIP|KNEE)_JOINT"],
effort_limit=33.5,
saturation_effort=33.5,
velocity_limit=21.0,
stiffness=20.0,
damping=,
),},
)
资产配置的核心包含三个部分。首先是 spawn 配置,指定了机器人模型的加载方式。其次是 init_state 配置,定义了机器人的初始姿态。最后是 actuators 配置,定义了执行器的物理特性。
在定义好机器人资产之后,下一步是配置强化学习训练的超参数。
from isaaclab.utils import configclass
from isaaclab_rl.rsl_rl import RslRlOnPolicyRunnerCfg, RslRlPpoActorCriticCfg, RslRlPpoAlgorithmCfg
@configclass
class AgibotD1RoughPPORunnerCfg(RslRlOnPolicyRunnerCfg):
num_steps_per_env = 24
max_iterations = 20000
save_interval = 100
experiment_name = "agibot_d1_rough"
policy = RslRlPpoActorCriticCfg(
init_noise_std=1.0,
actor_hidden_dims=[512, 256, 128],
critic_hidden_dims=[512, 256, 128],
activation="elu",
)
algorithm = RslRlPpoAlgorithmCfg(
clip_param=0.2,
entropy_coef=0.01,
learning_rate=1.0e-3,
gamma=0.99,
lam=0.95,
)
@configclass
class AgibotD1FlatPPORunnerCfg(AgibotD1RoughPPORunnerCfg):
def __post_init__(self):
super().__post_init__()
self.max_iterations = 5000
self.experiment_name = "agibot_d1_flat"
Agent 配置采用了与环境配置类似的继承模式。网络架构 [512, 256, 128] 是一个递减的三层 MLP 结构。
环境配置是添加新机器人最核心的部分。
from isaaclab.utils import configclass
from robot_lab.tasks.manager_based.locomotion.velocity.velocity_env_cfg import LocomotionVelocityRoughEnvCfg
from robot_lab.assets.agibot import AGIBOT_D1_CFG
@configclass
class AgibotD1RoughEnvCfg(LocomotionVelocityRoughEnvCfg):
base_link_name = "BASE_LINK"
foot_link_name = ".*_FOOT_LINK"
joint_names = [
"FR_ABAD_JOINT", "FR_HIP_JOINT", "FR_KNEE_JOINT",
"FL_ABAD_JOINT", "FL_HIP_JOINT", "FL_KNEE_JOINT",
"RR_ABAD_JOINT", "RR_HIP_JOINT", "RR_KNEE_JOINT",
"RL_ABAD_JOINT", "RL_HIP_JOINT", "RL_KNEE_JOINT",
]
def __post_init__(self):
super().__post_init__()
# === 场景配置 ===
self.scene.robot = AGIBOT_D1_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/" + self.base_link_name
# === 观测配置 ===
self.observations.policy.base_lin_vel.scale = 2.0
self.observations.policy.base_ang_vel.scale = 0.25
self.observations.policy.base_lin_vel = None
self.observations.policy.height_scan = None
.observations.policy.joint_pos.params[].joint_names = .joint_names
.actions.joint_pos.scale = {
: ,
:
}
.actions.joint_pos.joint_names = .joint_names
.rewards.lin_vel_z_l2.weight = -
.rewards.ang_vel_xy_l2.weight = -
.rewards.joint_torques_l2.weight = -
.rewards.joint_acc_l2.weight = -
.rewards.track_lin_vel_xy_exp.weight =
.rewards.track_ang_vel_z_exp.weight =
.rewards.action_rate_l2.weight = -
.rewards.feet_height_body.weight = -
.rewards.upward.weight =
.rewards.feet_gait.params[] = (
(, ),
(, ),
)
.terminations.illegal_contact =
.__class__.__name__ == :
.disable_zero_weight_rewards()
这段配置代码展示了几个重要的定制技巧。首先是动作缩放的差异化设置。步态配置中的 synced_feet_pair_names 定义了对角步态的足部配对。
平地配置是粗糙地形配置的简化版本。
from isaaclab.utils import configclass
from .rough_env_cfg import AgibotD1RoughEnvCfg
@configclass
class AgibotD1FlatEnvCfg(AgibotD1RoughEnvCfg):
def __post_init__(self):
super().__post_init__()
self.scene.terrain.terrain_type = "plane"
self.scene.terrain.terrain_generator = None
self.scene.height_scanner = None
self.observations.policy.height_scan = None
self.curriculum.terrain_levels = None
if self.__class__.__name__ == "AgibotD1FlatEnvCfg":
self.disable_zero_weight_rewards()
平地配置的代码非常简洁,只需要覆盖与地形相关的几个参数。
最后一步是将配置好的环境注册到 Gymnasium 框架中。
import gymnasium as gym
from . import agents
gym.register(
id="RobotLab-Isaac-Velocity-Flat-Agibot-D1-v0",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
disable_env_checker=True,
kwargs={
"env_cfg_entry_point": f"{__name__}.flat_env_cfg:AgibotD1FlatEnvCfg",
"rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:AgibotD1FlatPPORunnerCfg",
},
)
gym.register(
id="RobotLab-Isaac-Velocity-Rough-Agibot-D1-v0",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
disable_env_checker=True,
kwargs={
"env_cfg_entry_point": f"{__name__}.rough_env_cfg:AgibotD1RoughEnvCfg",
"rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:AgibotD1RoughPPORunnerCfg",
},
)
完成以上五个步骤后,新机器人就成功集成到 Robot Lab 中了。
奖励函数的调优是强化学习训练成功的关键因素之一。不同类型的机器人由于其物理结构、动力学特性和任务需求的差异,需要针对性地设置奖励权重。
四足机器人是 Robot Lab 中支持最完善的机器人类型。
| 奖励项 | 推荐值 | 作用 |
|---|---|---|
track_lin_vel_xy_exp | 3.0 | 线速度跟踪(核心目标) |
track_ang_vel_z_exp | 1.5 | 角速度跟踪 |
lin_vel_z_l2 | -2.0 | 抑制垂直跳动 |
ang_vel_xy_l2 | -0.05 | 抑制翻滚 |
joint_torques_l2 | -2.5e-5 | 能耗惩罚 |
joint_acc_l2 | -2.5e-7 | 动作平滑 |
action_rate_l2 | -0.01 | 动作变化率 |
feet_air_time | 0.1 | 腾空时间奖励 |
feet_gait | 0.5 | 步态同步 |
feet_slide | -0.1 | 滑动惩罚 |
upward | 1.0 | 保持直立 |
问题 1:速度跟踪不收敛 解决方法是增大速度跟踪奖励或减小其他惩罚项的权重。
问题 2:步态不稳定
需要加强步态相关的奖励。feet_gait 奖励鼓励对角腿同步运动。
问题 3:能耗过高 通过增大力矩和功率相关的惩罚可以引导策略学习更加节能的运动方式。
人形机器人的调参与四足有着本质的不同。由于只有两条腿支撑,人形机器人的平衡余量极小,一旦失去平衡很难恢复。
下表对比了 Robot Lab 中支持的主要人形机器人的奖励权重配置:
| 奖励项 | G1 | H1 | GR1T2 | XBot | 说明 |
|---|---|---|---|---|---|
track_lin_vel_xy_exp | 3.0 | 3.0 | 5.0 | 2.0 | 核心任务奖励 |
track_ang_vel_z_exp | 3.0 | 3.0 | 5.0 | 2.0 | 角速度跟踪 |
feet_air_time | 0.25 | 1.0 | 1.0 | 2.0 | 迈腿奖励(关键) |
upward | 1.0 | 1.0 | 1.0 | 0.2 | 站立奖励(关键) |
is_terminated | -200 | -200 | -200 | -200 | 摔倒惩罚 |
flat_orientation_l2 | -0.2 | -0.2 | -0.5 | 0 | 姿态惩罚 |
joint_torques_l2 | -1.5e-7 | -1.0e-8 | -2.5e-5 | -2.5e-5 | 能耗惩罚 |
joint_acc_l2 | -1.25e-7 | -2.5e-7 | -2.5e-7 | -2.5e-7 | 动作平滑 |
action_rate_l2 | -0.005 | -0.01 | -0.005 | -0.01 | 动作变化率 |
feet_slide | -0.2 | -0.4 | -0.2 | -0.2 | 滑动惩罚 |
关键发现:feet_air_time(腾空时间奖励)和 upward(站立奖励)是人形机器人学会行走的关键。
典型症状:训练 10 万步后,平均 reward 到达 15-25,但机器人保持蹲坐姿态不迈腿。
根本原因是策略发现'不动'是获取奖励的局部最优解。
解决方案:
self.rewards.feet_air_time.weight = 1.0。self.rewards.upward.weight = 2.0。self.rewards.track_lin_vel_xy_exp.weight = 5.0。self.rewards.joint_pos_penalty.weight = -0.5。人形机器人需要一些四足机器人不需要的特殊配置,包括双足专用的腾空时间函数和关节偏差惩罚。
# 使用双足专用腾空时间函数(关键配置!)
self.rewards.feet_air_time.func = mdp.feet_air_time_positive_biped
self.rewards.feet_air_time.params["threshold"] = 0.4
# 使用偏航坐标系速度跟踪(适应身体朝向变化)
self.rewards.track_lin_vel_xy_exp.func = mdp.track_lin_vel_xy_yaw_frame_exp
# 关节偏差惩罚(保持自然姿态,但不要太大)
self.rewards.create_joint_deviation_l1_rewterm("joint_deviation_hip_l1", -0.1, [".*hip_yaw.*", ".*hip_roll.*"])
问题 1:机器人坐着不走。详见 4.2.2 节。 问题 2:容易摔倒。需要进一步强化防摔倒的惩罚。 问题 3:姿态不稳/身体晃动。增大直立奖励和角速度惩罚。 问题 4:迈腿幅度太小/原地踏步。增大速度跟踪奖励和腾空时间奖励。 问题 5:训练初期不稳定。必须禁用地形课程学习。
轮式机器人结合了腿式和轮式运动的优点,但也带来了独特的控制挑战。最大的区别在于需要同时处理两种不同类型的关节。
# 分离腿部和轮子控制
self.actions.joint_pos.joint_names = self.leg_joint_names
self.actions.joint_vel.joint_names = self.wheel_joint_names
# 分离腿部和轮子惩罚
self.rewards.joint_torques_l2.params["asset_cfg"].joint_names = self.leg_joint_names
self.rewards.joint_acc_wheel_l2.weight = -2.5e-9
| 配置项 | GO2W (轮式) | GO2 (四足) |
|---|---|---|
feet_air_time | 0 (禁用) | 0.1 |
feet_gait | 0 (禁用) | 0.5 |
feet_slide | 0 (禁用) | -0.1 |
base_height_l2.target_height | 0.40 | 0.33 |
joint_acc_wheel_l2 | -2.5e-9 | N/A |
轮式机器人禁用了所有与步态相关的奖励,因为轮子始终接触地面。
Robot Lab 基类 LocomotionVelocityRoughEnvCfg 定义了 40+ 个奖励项。
核心任务奖励:track_lin_vel_xy_exp, track_ang_vel_z_exp, feet_air_time, feet_gait, upward。
基座稳定性惩罚:lin_vel_z_l2, ang_vel_xy_l2, flat_orientation_l2, base_height_l2。
能耗与平滑性惩罚:joint_torques_l2, joint_acc_l2, action_rate_l2, joint_power。
足部行为惩罚:feet_slide, feet_stumble, feet_height, feet_height_body。
安全与约束惩罚:is_terminated, joint_pos_limits, undesired_contacts, joint_pos_penalty。
| 配置类别 | 四足机器人 | 人形机器人 | 原因 |
|---|---|---|---|
| 速度跟踪 | 3.0 | 3.0-5.0 | 人形需要更强激励 |
| 腾空时间 | 0.1 | 0.25-2.0 | 人形步态关键 |
| 腾空函数 | feet_air_time | feet_air_time_positive_biped | 双足专用 |
| 步态同步 | 0.5 | 0(禁用) | 人形无对角步态 |
| 直立奖励 | 1.0 | 1.0-2.0 | 人形平衡困难 |
| 终止惩罚 | 0 | -200 | 人形摔倒不可恢复 |
| 力矩惩罚 | -2.5e-5 | -1.5e-7 | 人形需要更大力矩 |
| 地形课程 | 启用 | 禁用 | 人形初期无法应对复杂地形 |
| 训练步数 | 200k | 500k-1M | 人形收敛慢 |
人形机器人快速起步配置:
def __post_init__(self):
super().__post_init__()
# ===== 核心奖励(让机器人动起来)=====
self.rewards.track_lin_vel_xy_exp.weight = 3.0
self.rewards.track_lin_vel_xy_exp.func = mdp.track_lin_vel_xy_yaw_frame_exp
self.rewards.track_ang_vel_z_exp.weight = 3.0
# ===== 关键:腾空时间奖励(让机器人迈腿)=====
self.rewards.feet_air_time.weight = 1.0
self.rewards.feet_air_time.func = mdp.feet_air_time_positive_biped
self.rewards.feet_air_time.params["threshold"] = 0.4
# ===== 直立奖励(让机器人站起来)=====
self.rewards.upward.weight = 1.0
# ===== 摔倒惩罚 =====
self.rewards.is_terminated.weight = -200.0
# ===== 稳定性惩罚 =====
self.rewards.flat_orientation_l2.weight = -0.2
self.rewards.ang_vel_xy_l2.weight = -0.1
# ===== 能耗惩罚(人形用较小值)=====
self.rewards.joint_torques_l2.weight = -1.5e-7
self.rewards.joint_acc_l2.weight = -1.25e-7
self.rewards.action_rate_l2.weight = -0.005
# ===== 足部惩罚 =====
self.rewards.feet_slide.weight = -0.2
# ===== 关键:禁用地形课程 =====
self.curriculum.terrain_levels = None
self.curriculum.command_levels_lin_vel = None
.curriculum.command_levels_ang_vel =
四足机器人快速起步配置:
def __post_init__(self):
super().__post_init__()
# ===== 核心奖励 =====
self.rewards.track_lin_vel_xy_exp.weight = 3.0
self.rewards.track_ang_vel_z_exp.weight = 1.5
# ===== 步态奖励 =====
self.rewards.feet_air_time.weight = 0.1
self.rewards.feet_gait.weight = 0.5
# ===== 直立奖励 =====
self.rewards.upward.weight = 1.0
# ===== 稳定性惩罚 =====
self.rewards.lin_vel_z_l2.weight = -2.0
self.rewards.ang_vel_xy_l2.weight = -0.05
# ===== 能耗惩罚 =====
self.rewards.joint_torques_l2.weight = -2.5e-5
self.rewards.joint_acc_l2.weight = -2.5e-7
self.rewards.action_rate_l2.weight = -0.01
# ===== 足部惩罚 =====
self.rewards.feet_slide.weight = -0.1
self.rewards.feet_height_body.weight = -5.0
完成配置后,就可以开始训练和测试了。
训练脚本位于 scripts/reinforcement_learning/rsl_rl/train.py。
# RSL-RL 训练 - 粗糙地形
python scripts/reinforcement_learning/rsl_rl/train.py \
--task=RobotLab-Isaac-Velocity-Rough-Unitree-G1-v0 \
--headless \
--num_envs 4096
# RSL-RL 训练 - 平地
python scripts/reinforcement_learning/rsl_rl/train.py \
--task=RobotLab-Isaac-Velocity-Flat-Unitree-G1-v0 \
--headless \
--num_envs 4096
# 从检查点继续训练
python scripts/reinforcement_learning/rsl_rl/train.py \
--task=RobotLab-Isaac-Velocity-Rough-Unitree-G1-v0 \
--resume \
--load_run="2024-01-01_12-00-00"
--headless 参数禁用图形渲染,可以显著提高训练速度。
训练完成后,可以使用测试脚本加载模型并可视化机器人的行为。
# 加载训练好的模型进行测试
python scripts/reinforcement_learning/rsl_rl/play.py \
--task=RobotLab-Isaac-Velocity-Rough-Unitree-G1-v0 \
--num_envs 16
# 录制视频
python scripts/reinforcement_learning/rsl_rl/play.py \
--task=RobotLab-Isaac-Velocity-Rough-Unitree-G1-v0 \
--video \
--video_length 200
TensorBoard 是监控训练过程的重要工具。
tensorboard --logdir=logs/rsl_rl
在 TensorBoard 中,重点关注 Mean Reward、Episode Length、Policy Loss / Value Loss 等指标。
本文系统性地介绍了 Robot Lab 强化学习项目的核心设计理念与实现细节。通过对配置继承体系、机器人添加流程和调参策略的深入剖析,读者应该能够:
ManagerBasedRLEnvCfg 基类到机器人特定配置的完整继承链。Robot Lab 的设计体现了软件工程中'开放封闭原则'的精髓——对扩展开放(轻松添加新机器人),对修改封闭(无需修改基类即可定制行为)。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online