Isaac Lab 强化学习入门指南
本文为读者提供了一个起点,使用Isaac Lab人形机器人示例项目在Isaac Lab中创建自己的项目。它将解释项目结构、模板创建器的使用,并演示一个自定义的示例策略。我们将修改原始的人形机器人项目,使用强化学习训练人形机器人移动到指定点,到达该点后停止并自我平衡。
1、安装Isaac Lab
首先,从Github文档安装Isaac Lab:
使用Isaac Sim pip安装
说明包括Isaac Sim的安装。为了入门,建议使用虚拟环境,因为你可以从干净的环境开始,无需担心依赖冲突。Isaac lab提供pip和conda安装选项。我们将使用的示例项目是IsaacLab-Humanoid-Direct-v0,它包含在Isaac Lab安装中。以下是所有可用示例环境的列表,可作为初学者的起点:
可用环境
Isaac Lab详解
Isaac Lab通过启动Isaac Sim实例来工作,该实例运行多个actor的并行模拟,actor由URDF文件定义。actor将学习一个策略,该策略最大化训练环境中奖励函数定义的奖励总和。当Isaac Lab代码执行时,Isaac Sim初始化并开始训练过程。
2、生成模板项目
理解Isaac Lab项目的一个障碍是示例项目都内置在源代码的文件结构中。这种设置使得很难跟踪Python导入并掌握工作流程。本节将介绍如何使用模板生成器创建外部Isaac Lab人形机器人项目,并修改它以满足你的目的。在本例中,我们将修改默认生成的项目,作为训练Isaac Lab人形机器人的环境。
方便的是,Isaac Lab文档有生成模板项目的说明。这允许你选择所需的工作流、RL库,并确保项目结构正确设置。
首先,激活创建的虚拟环境或conda环境。
导航到IsaacLab根文件夹。
然后,按照文档中的说明运行此shell命令创建模板项目:
./isaaclab.sh --new
按照以下方式配置项目:
选择External作为任务类型
指定项目构建的路径
将项目命名为humanoid_target_move
选择direct, single agent Isaac Lab工作流
选择rl_games作为RL库
这将在指定路径中创建模板项目。
Isaac Lab文件结构
项目文件结构由三个目录组成:
README.md scripts source
README.md将包含构建项目的自动生成说明。最重要的是,它将包含Python pip安装命令。这应该首先从顶级Isaac Lab文件夹运行。它看起来像这样:
python -m pip install -e source/humanoid_target_move
scripts包含项目的重要Python脚本:
├── list_envs.py
└── rl_games
├── play.py
└── train.py
list_envs.py: 显示项目中可用的环境。模板项目设置为自动具有初始环境,执行脚本时将显示该环境。
train.py: 启动Isaac Lab开始训练。
play.py: 启动Isaac Lab回放训练好的策略。
source包含控制环境、奖励和动作的所有代码。
我们将在本文中使用的重要文件位于tasks的子目录中:
humanoid_target_move_env.py
humanoid_target_move_env_cfg.py
rl_games_ppo_cfg.yaml
Tasks位于:
humanoid_target_move/source/humanoid_target_move/humanoid_target_move/tasks
导航到项目的此目录,将相对容易找到这些文件。
模板项目生成后,这些文件将设置为运行平衡倒立摆的强化学习训练。为确保项目正确构建,导航到scripts/rl_games并运行此命令启动默认倒立摆训练:
python train.py --task=Template-Humanoid-Target-Move-Direct-v0
这将启动一个运行RL训练的Isaac Sim实例。它将平衡杆子,看起来像这样:
如果你是RL新手,观看倒立摆随着训练的继续而缓慢改进会很有启发性。然而,为了提高训练效率,在"无头"模式下运行训练非常有效。无头模式不渲染视觉效果,但仍然执行所有训练计算和环境模拟。在无头模式下运行就像添加一个headless标志一样简单:
python train.py --task=Template-Humanoid-Target-Move-Direct-v0 --headless
在无头模式下,你的主要反馈将在终端窗口本身中。运行训练时,Isaac Lab还将显示已运行的epoch数量。每次策略改进并被评估时,该改进的策略将保存为检查点。训练将在预定数量的epoch后完成。epoch的长度和epoch的数量都可以在训练器的配置文件中自定义,在本例中是rl_games_ppo_cfg.yaml。
训练完成后,使用play.py运行策略时将使用最新的检查点。你可以在同一个rl_games文件夹中运行以下命令来播放训练好的策略:
python play.py --task=Template-Humanoid-Target-Move-Direct-v0
这将打开一个Isaac Sim实例,显示训练好的策略在运行。对于倒立摆,你将看到每个倒立摆实例调整其各自的位置以将杆子保持直立。我们将在此基础上创建Isaac人形机器人项目。
3、将倒立摆模板转换为Isaac人形机器人
如前所述,我们将修改这三个文件将项目转换为人形机器人:
rl_games_ppo_cfg.yaml
humanoid_target_move_env.py
humanoid_target_move_env_cfg.py
此外,我们将从Isaac源代码中提取locomotion_env.py并将其导入此项目。locomotion_env.py包含为Isaac人形机器人设计的环境。
3.1 将运动放入项目中
包含locomotion_env.py的文件夹位于Isaac Lab源代码中:
IsaacLab/source/isaaclab_tasks/isaaclab_tasks/direct/locomotion/
将locomotion文件夹的副本放在项目目录中:
humanoid_target_move/source/humanoid_target_move/humanoid_target_move
我们将在创建自定义RL训练时修改此文件,因此我们创建此副本以保留原始文件。
3.2 修改RL Games PPO YAML
RL Games中使用的默认RL方法是PPO(近端策略优化)。由于我们当前的rl_games_ppo_cfg.yaml是为倒立摆设置的,我们需要将其替换为Isaac Lab源代码中的PPO YAML。此YAML文件可用于修改RL Games PPO训练算法的许多方面,我们将使用人形机器人的PPO而不是倒立摆。此PPO文件位于:
IsaacLab/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid/agents
以下是PPO YAML:
params:
seed: 42
env:
clip_actions: 1.0
algo:
name: a2c_continuous
model:
name: continuous_a2c_logstd
network:
name: actor_critic
separate: False
space:
continuous:
mu_activation: None
sigma_activation: None
mu_init:
name: default
sigma_init:
name: const_initializer
val: 0
fixed_sigma: True
mlp:
units: [400, 200, 100]
activation: elu
d2rl: False
initializer:
name: default
regularizer:
name: None
load_checkpoint: False
load_path: ''
config:
name: humanoid_direct
env_name: rlgpu
device: 'cuda:0'
device_name: 'cuda:0'
multi_gpu: False
ppo: True
mixed_precision: True
normalize_input: True
normalize_value: True
value_bootstrap: True
num_actors: -1
reward_shaper:
scale_value: 0.01
normalize_advantage: True
gamma: 0.99
tau: 0.95
learning_rate: 5e-4
lr_schedule: adaptive
kl_threshold: 0.008
score_to_win: 20000
max_epochs: 1000
save_best_after: 100
save_frequency: 50
grad_norm: 1.0
entropy_coef: 0.0
truncate_grads: True
e_clip: 0.2
horizon_length: 32
minibatch_size: 32768
mini_epochs: 5
critic_coef: 4
clip_value: True
seq_length: 4
bounds_loss_coef: 0.0001
将agents目录中的rl_games_ppo_cfg.yaml内容替换为人形机器人PPO文件的内容。
以下是YAML文件最重要方面的一些解释,以及它们对PPO算法的含义。
mlp:
units: [400, 200, 100]
activation: elu
d2rl: False
units键指定神经网络中每层的神经元数量。在本例中,第1层有400个神经元,第2层有200个神经元,第3层有100个神经元。activation键指定每层的激活函数。
device: 'cuda:0'
device_name: 'cuda:0'
learning_rate: 5e-4
lr_schedule: adaptive
device和device_name键允许我们指定训练使用的GPU,learning_rate和lr_scheduler是ADAM或SGD等一阶优化器的基本超参数。
本文中的示例不需要修改PPO配置,但了解选项对于一般的RL训练很有帮助。
3.3 环境配置
剩下的两个文件humanoid_target_move_env.py和humanoid_target_move_env_cfg.py将确定奖励权重、起始位置,并加载Isaac人形机器人actor的配置。
humanoid_target_move_env.py将非常简短,只是将环境初始化为运动环境并设置配置。它应该如下所示:
from __future__ import annotations
from .humanoid_target_move_env_cfg import HumanoidTargetMoveEnvCfg
from humanoid_target_move.locomotion.locomotion_env import LocomotionEnv
class HumanoidTargetMoveEnv(LocomotionEnv):
cfg: HumanoidTargetMoveEnvCfg
def __init__(self, cfg: HumanoidTargetMoveEnvCfg, render_mode: str | None = None, **kwargs):
super().__init__(cfg, render_mode, **kwargs)
这与Isaac Lab源代码版本几乎相同,但使用匹配的项目名称,并从项目文件夹中的locomotion_env.py导入LocomotionEnv的副本。
现在我们将修改humanoid_target_move_env_cfg.py以正确配置Isaac人形机器人环境。它应该如下所示:
from __future__ import annotations
from isaaclab_assets import HUMANOID_CFG
from isaaclab.assets import ArticulationCfg
from isaaclab.envs import DirectRLEnvCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.sim import SimulationCfg
from isaaclab.utils import configclass
from isaaclab.terrains import TerrainImporterCfg
import isaaclab.sim as sim_utils
import gymnasium as gym
import numpy as np
@configclass
class HumanoidTargetMoveEnvCfg(DirectRLEnvCfg):
# env
episode_length_s = 15.0
decimation = 2
action_scale = 1.0
action_space = 21
observation_space = 75
state_space = 0
# simulation
sim: SimulationCfg = SimulationCfg(dt=1 / 120, render_interval=decimation)
terrain = TerrainImporterCfg(
prim_path="/World/ground",
terrain_type="plane",
collision_group=-1,
physics_material=sim_utils.RigidBodyMaterialCfg(
friction_combine_mode="average",
restitution_combine_mode="average",
static_friction=1.0,
dynamic_friction=1.0,
restitution=0.0,
),
debug_vis=False,
)
# scene
scene: InteractiveSceneCfg = InteractiveSceneCfg(num_envs=1024, env_spacing=4.0, replicate_physics=True)
# robot
robot: ArticulationCfg = HUMANOID_CFG.replace(prim_path="/World/envs/env_.*/Robot")
joint_gears: list = [
67.5000, # lower_waist
67.5000, # lower_waist
67.5000, # right_upper_arm
67.5000, # right_upper_arm
67.5000, # left_upper_arm
67.5000, # left_upper_arm
67.5000, # pelvis
45.0000, # right_lower_arm
45.0000, # left_lower_arm
45.0000, # right_thigh: x
135.0000, # right_thigh: y
45.0000, # right_thigh: z
45.0000, # left_thigh: x
135.0000, # left_thigh: y
45.0000, # left_thigh: z
90.0000, # right_knee
90.0000, # left_knee
22.5, # right_foot
22.5, # right_foot
22.5, # left_foot
22.5, # left_foot
]
heading_weight: float = 0.5
up_weight: float = 0.1
energy_cost_scale: float = 0.05
actions_cost_scale: float = 0.01
alive_reward_scale: float = 2.0
dof_vel_scale: float = 0.1
death_cost: float = -1.0
termination_height: float = 0.8
angular_velocity_scale: float = 0.25
contact_force_scale: float = 0.01
distance_reward_scale: float = 1.0 #<--- added for training move to point
epsilon_dist: float = 0.10 #<--- added for training move to point
此配置导入所有必要的Isaac Lab配置,为关节设置HUMANOID_CFG配置文件,并设置每个奖励的权重。这些奖励在我们之前创建副本的locomotion_env.py文件中定义。
4、训练Isaac人形机器人移动到点
要训练Isaac人形机器人移动到点并停止,我们将理解并修改locomotion_env.py文件。你可能已经注意到,在上面的代码中,两个值distance_reward_scale和epsilon_dist有注释表明它们用于本文的移动到点训练。在locomotion_env.py中,我们将定义这些,使得环境配置中给出的奖励是可实现的,并考虑到Isaac人形机器人采取的动作。我们将遍历locomotion_env.py中的每个相关部分,以实现使actor移动到点并停止所需的奖励。
首先,在文件顶部附近,注意类init中的self.targets张量。
self.targets = torch.tensor([1000,0, 0], dtype=torch.float32, device=self.sim.device).repeat(
(self.num_envs, 1)
张量可以是非常复杂的数学结构,但在本例中,我们正在查看一个表示简单3D坐标系的张量。第一个条目是X,第二个条目是Y,第三个条目是Z轴。三个一起定义空间中的一个点,更改此值允许我们为人形机器人设置目标。
将第一个条目X值设置为5,以将目标放置在仅一小段距离前方。默认设置为1000,因为库存项目不尝试使人形机器人移动到或停止在特定点。我们下面定义的奖励将允许我们按照预期使用此目标,作为空间中要到达并停止的点。这是调整后的张量版本:
self.targets = torch.tensor([5, 0, 0], dtype=torch.float32, device=self.sim.device).repeat(
(self.num_envs, 1)
4.1 计算奖励函数
接下来,我们定义一个奖励,激励人形机器人到达并保持在指定的目标点。我们将在函数compute_rewards()中定义此奖励,权重为distance_reward_scale,距离的逆计算为inv_dist_bonus。此计算将使用到目标的距离**(dist_to_goal)创建一个奖励值,该值被纳入最终计算的奖励计算中。以下是修改compute_rewards()**以实现此奖励的方法:
@torch.jit.script
def compute_rewards(
actions: torch.Tensor,
reset_terminated: torch.Tensor,
up_weight: float,
heading_weight: float,
heading_proj: torch.Tensor,
up_proj: torch.Tensor,
dof_vel: torch.Tensor,
dof_pos_scaled: torch.Tensor,
potentials: torch.Tensor,
prev_potentials: torch.Tensor,
actions_cost_scale: float,
energy_cost_scale: float,
dof_vel_scale: float,
death_cost: float,
alive_reward_scale: float,
motor_effort_ratio: torch.Tensor,
vel_loc: torch.Tensor,
dist_to_goal: torch.Tensor, #<--- added reward
distance_reward_scale: float, #<--- scale for reward
epsilon_dist: float #<--- added epsilon
):
heading_weight_tensor = torch.ones_like(heading_proj) * heading_weight
heading_reward = torch.where(heading_proj > 0.8, heading_weight_tensor, heading_weight * heading_proj / 0.8)
up_reward = torch.zeros_like(heading_reward)
up_reward = torch.where(up_proj > 0.93, up_reward + up_weight, up_reward)
actions_cost = torch.sum(actions**2, dim=-1)
electricity_cost = torch.sum(
torch.abs(actions * dof_vel * dof_vel_scale) * motor_effort_ratio.unsqueeze(0),
dim=-1,
)
dof_at_limit_cost = torch.sum(dof_pos_scaled > 0.98, dim=-1)
alive_reward = torch.ones_like(potentials) * alive_reward_scale
progress_reward = potentials - prev_potentials
# new added reward (inverse of distance based reward)
inv_dist_bonus = distance_reward_scale / (epsilon_dist + dist_to_goal)
total_reward = (
progress_reward
+ inv_dist_bonus #<--- added
+ alive_reward
+ up_reward
+ heading_reward
- actions_cost_scale * actions_cost
- energy_cost_scale * electricity_cost
- dof_at_limit_cost
)
total_reward = torch.where(reset_terminated, torch.ones_like(total_reward) * death_cost, total_reward)
return total_reward
对于**compute_rewards()**方法,环境配置中输入的权重作为参数传递,然后计算并返回总奖励。提供的奖励确保机器人节能,并确保人形机器人避免摔倒。由于人形机器人已经可以保持直立,我们只需要奖励人形机器人到达并保持在给定的目标点。
为此,我们必须为人形机器人越接近目标提供越多的奖励,并继续提供该奖励以保持接近目标。我们将使用逆距离计算,使得越接近目标产生越高的奖励:
inv_dist_bonus = distance_reward_scale / (epsilon_dist + dist_to_goal)
distance_reward_scale由环境运行时设置。数字越大,随着与目标距离缩小,总奖励越大。例如,如果distance_reward_scale为2.0,(dist_to_goal + epsilon_dist)为0.2,则添加到最终奖励计算的奖励将为10。epsilon_dist也由环境设置,但它只是为了在人形机器人直接在点上时避免除以零。在我们实现的环境代码中,epsilon为0.10。这使得最大可能的奖励为distance_reward_scale除以0.10,即distance_reward_scale定义值的10倍。
如上面的代码所示,此计算中使用的值必须添加到函数的参数中。
为了允许此奖励影响RL训练,我们将把这些值添加到locomotion_env.py文件顶部附近的**get_rewards()**函数中。
def _get_rewards(self) -> torch.Tensor:
total_reward = compute_rewards(
self.actions,
self.reset_terminated,
self.cfg.up_weight,
self.cfg.heading_weight,
self.heading_proj,
self.up_proj,
self.dof_vel,
self.dof_pos_scaled,
self.potentials,
self.prev_potentials,
self.cfg.actions_cost_scale,
self.cfg.energy_cost_scale,
self.cfg.dof_vel_scale,
self.cfg.death_cost,
self.cfg.alive_reward_scale,
self.motor_effort_ratio,
self.dist_to_goal, #<--- added calculated reward
self.cfg.distance_reward_scale, #<--- added configurable weight
self.cfg.epsilon_dist, #<--- Added configurable minimum epsilon
)
return total_reward
4.2 中间值函数
distance_reward_scale和epsilon_dist在环境中定义,但dist_to_goal不是由compute_rewards、环境或源代码内置定义的。因此,我们必须在**intermediate_values()**中实现此计算。此函数使用有关人形机器人的信息来跟踪奖励计算所需的值。以下是修改后的版本:
@torch.jit.script
def compute_intermediate_values(
targets: torch.Tensor,
torso_position: torch.Tensor,
torso_rotation: torch.Tensor,
velocity: torch.Tensor,
ang_velocity: torch.Tensor,
dof_pos: torch.Tensor,
dof_lower_limits: torch.Tensor,
dof_upper_limits: torch.Tensor,
inv_start_rot: torch.Tensor,
basis_vec0: torch.Tensor,
basis_vec1: torch.Tensor,
potentials: torch.Tensor,
prev_potentials: torch.Tensor,
dt: float,
):
to_target = targets - torso_position
to_target[:, 2] = 0.0
torso_quat, up_proj, heading_proj, up_vec, heading_vec = compute_heading_and_up(
torso_rotation, inv_start_rot, to_target, basis_vec0, basis_vec1, 2
)
vel_loc, angvel_loc, roll, pitch, yaw, angle_to_target = compute_rot(
torso_quat, velocity, ang_velocity, targets, torso_position
)
dof_pos_scaled = torch_utils.maths.unscale(dof_pos, dof_lower_limits, dof_upper_limits)
to_target = targets - torso_position
to_target[:, 2] = 0.0
prev_potentials[:] = potentials
potentials = -torch.norm(to_target, p=2, dim=-1) / dt
dist_to_goal = torch.norm(to_target[:, :2], dim=-1) #<--- scalar distance
return (
up_proj,
heading_proj,
up_vec,
heading_vec,
vel_loc,
angvel_loc,
roll,
pitch,
yaw,
angle_to_target,
dof_pos_scaled,
prev_potentials,
potentials,
dist_to_goal, #<---- calculated distance to goal must return
)
以下是代码的主要添加:
dist_to_goal = torch.norm(to_target[:, :2], dim=-1)
to_target在上面的函数中计算,是指定目标减去人形机器人的躯干位置。然而,to_target是多维张量,我们需要标量距离测量用于奖励计算。因此,我们可以使用PyTorch范数将此信息标准化为可用的1维标量。这将目标坐标转换为可在inv_dist_bonus计算中使用的单个值。我们还执行了PyTorch切片,删除了不必要的Z轴,因为所有导航都将在平坦表面上进行。此标准化值将在奖励计算中工作。
定义中间值后,我们需要更新文件顶部附近的**computer_intermediate_values(self)**以反映更改:
def _compute_intermediate_values(self):
self.torso_position, self.torso_rotation = self.robot.data.root_pos_w, self.robot.data.root_quat_w
self.velocity, self.ang_velocity = self.robot.data.root_lin_vel_w, self.robot.data.root_ang_vel_w
self.dof_pos, self.dof_vel = self.robot.data.joint_pos, self.robot.data.joint_vel
(
self.up_proj,
self.heading_proj,
self.up_vec,
self.heading_vec,
self.vel_loc,
self.angvel_loc,
self.roll,
self.pitch,
self.yaw,
self.angle_to_target,
self.dof_pos_scaled,
self.prev_potentials,
self.potentials,
self.dist_to_goal,#<--- added here
) = compute_intermediate_values(
self.targets,
self.torso_position,
self.torso_rotation,
self.velocity,
self.ang_velocity,
self.dof_pos,
self.robot.data.soft_joint_pos_limits[0, :, 0],
self.robot.data.soft_joint_pos_limits[0, :, 1],
self.inv_start_rot,
self.basis_vec0,
self.basis_vec1,
self.potentials,
self.prev_potentials,
self.cfg.sim.dt,
)
4.3 运行修改后的训练
完成所有这些步骤后,返回项目的顶级文件夹并导航到scripts/rl_games运行新训练:
python train.py --task=Template-Humanoid-Target-Move-Direct-v0 --headless
这需要的时间取决于你的硬件,但如果你满足Isaac Sim系统要求,可能少于5分钟。训练完成后,运行play命令查看结果:
python play.py --task=Template-Humanoid-Target-Move-Direct-v0
如果一切正常,你将看到人形机器人向前移动5个单位,然后停止并原地自我平衡。
此训练将使人形机器人直接向前移动,但返回并使用不同的X和Y值运行RL训练允许人形机器人导航到任何X和Y坐标。在较远距离,我们需要增加episode长度,可能还需要增加epoch数量,因为需要训练的时间跨度增加了。然而,10以下的较短距离在默认的epoch数量和episode长度下效果良好。
原文链接:Introduction to Isaac Lab Reinforcement Learning with the Isaac Humanoid
汇智网翻译整理,转载请标明出处