ISAACLAB 实战教程【搭建自己的仿真环境/实现PPO算法训练】
文章目录
ISAACLAB 实战:
基于Isaac Sim仿真平台论文代码复现过程前期的学习过程,内容参考Isaac Lab的官方文档,包括利用Isaac Lab创建自己的强化学习环境,并利用RSL_RL库中现成的PPO算法进行模型训练与评估
前置:
Isaac Lab则是一项构建在Isaac Sim上层的用于机器人学习的统一灵活的仿真技术框架。它提供了许多现成的环境、传感器和训练任务等,能够极大简化尤其是强化学习(Reinforcement Learning, RL)这样机器人领域研究的工作。
参见官方文档:官方指导
一、熟悉和创建自己的项目:
1.创建项目
先配置好环境,然后创建项目路径,在项目路径下输入命令行:
ps: issaclab命令需要自己配置sh文件
isaaclab --new

选择内部外部项目以及RL_libraries还有RL_al
这样isaaclab就帮我们创建好项目了,可以看看项目结构:
项目结构如下:

2.安装项目:
在自己项目根目录下
python -m pip install -e source/isaac_lab_tutorial #这里是自己项目名字
可以顺便查看一下项目中可用的任务:
python scripts/list_envs.py

什么是任务?
在Isaac Lab中,任务被定义为:
“特定agent(机器人)的执行动作(actions)和其特定的观测空间(observations)所构成的的环境”
这个环境给agent提供了当前的观测空间,并随时间通过更新仿真环境(simulation)来处理agent执行的动作。
3.执行任务:
python scripts/skrl/train.py --task=Template-Isaac-Lab-Tutorial-Direct-v0

二、自行设计实战:
1. 环境配置
cartpole_env_cfg.py或
isaaclab_tutorial_env_cfg.py
实现强化学习环境配置类:
@configclass
class IsaacLabTutorialEnvCfg(DirectRLEnvCfg):
作用是告诉 Isaac Lab:这个 RL 环境怎么仿真、用哪个机器人、创建多少个并行环境、物理步长是多少。
参数解读:
sim: SimulationCfg = SimulationCfg(dt=1 / 120, render_interval=2)
dt=1/120:物理仿真步长是 1/120 秒render_interval=2:每 2 个物理步渲染一次
robot_cfg: ArticulationCfg = CARTPOLE_CFG.replace(
prim_path="/World/envs/env_.*/Robot"
)
配置机器人:
CARTPOLE_CFG是 Isaac Lab 资产库里已有的 Cartpole 小车倒立摆配置.replace(...)是复制配置并修改其中的字段prim_path="/World/envs/env_.*/Robot"表示每个并行环境里的机器人路径
scene: InteractiveSceneCfg = InteractiveSceneCfg(
num_envs=4096,
env_spacing=4.0,
replicate_physics=True
)
配置场景:
num_envs=4096:一次并行创建 4096 个环境,用来加速 RL 训练env_spacing=4.0:每个环境之间间隔 4 米,避免互相干扰replicate_physics=True:复制物理场景,提高并行仿真效率
完整代码如下:
# cartpole_env_cfg.py
import math
import torch
import isaaclab.sim as sim_utils
from isaaclab.assets import Articulation, ArticulationCfg
from isaaclab.envs import DirectRLEnv, DirectRLEnvCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.sim import SimulationCfg
from isaaclab.utils import configclass
from isaaclab_assets.robots.cartpole import CARTPOLE_CFG
@configclass
class IsaacLabTutorialEnvCfg(DirectRLEnvCfg):
# RL
episode_length_s = 5.0
decimation = 2
action_space = 1
observation_space = 4
state_space = 0
# simulation
sim: SimulationCfg = SimulationCfg(
dt=1 / 120,
render_interval=decimation,
)
# robot
robot_cfg: ArticulationCfg = CARTPOLE_CFG.replace(
prim_path="/World/envs/env_.*/Robot"
)
# scene
scene: InteractiveSceneCfg = InteractiveSceneCfg(
num_envs=4096,
env_spacing=4.0,
replicate_physics=True,
)
# cartpole settings
cart_dof_name = "slider_to_cart"
pole_dof_name = "cart_to_pole"
action_scale = 100.0
max_cart_pos = 3.0
max_pole_angle = math.pi / 2
2.定义robot版环境
注意这里文件名是:
cartpole_env.py或
isaac_lab_tutorial_env.py
IsaacLabTutorialEnv 继承自Lab基类DirectRLEnv,这个环境使用 IsaacLabTutorialEnvCfg 作为配置,继而会调用父类 DirectRLEnv 的初始化逻辑,比如:
- 创建仿真上下文
- 创建场景
- 分配 buffer
- 设置环境数量
完整代码和注释如下:
# cartpole_env.py
class IsaacLabTutorialEnv(DirectRLEnv):
cfg: IsaacLabTutorialEnvCfg #这个环境使用 IsaacLabTutorialEnvCfg 作为配置
def __init__(self, cfg: IsaacLabTutorialEnvCfg, render_mode: str | None = None, **kwargs):
super().__init__(cfg, render_mode, **kwargs)
self.actions = torch.zeros(self.num_envs, 1, device=self.device)
# 读取关节
self.cart_dof_idx, _ = self.cartpole.find_joints(self.cfg.cart_dof_name) #平移关节id
self.pole_dof_idx, _ = self.cartpole.find_joints(self.cfg.pole_dof_name) #旋转关节id
def _setup_scene(self):
self.cartpole = Articulation(self.cfg.robot_cfg) #根据robot_cfg来创建机器人对象
self.scene.articulations["cartpole"] = self.cartpole #机器人注册到 Isaac Lab 的 scene 里
self.scene.clone_environments(copy_from_source=False) #复制多个并行环境
light_cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
light_cfg.func("/World/Light", light_cfg) #添加灯光渲染
def _pre_physics_step(self, actions: torch.Tensor): #做出action前要做什么(接收算法结果)
self.actions = actions.clone().clamp(-1.0, 1.0) #保存动作、限制动作范围
def _apply_action(self):
force = self.actions * self.cfg.action_scale
# 动作施加
self.cartpole.set_joint_effort_target(force, joint_ids=self.cart_dof_idx) #设置关节的目标作用力 joint_ids为单个关节编号
def _get_observations(self) -> dict:
joint_pos = self.cartpole.data.joint_pos # [batch, num_dof]
joint_vel = self.cartpole.data.joint_vel
cart_pos = joint_pos[:, self.cart_dof_idx[0]].unsqueeze(-1) # 小车平移关节水平位置
cart_vel = joint_vel[:, self.cart_dof_idx[0]].unsqueeze(-1) # 小车速度
pole_angle = joint_pos[:, self.pole_dof_idx[0]].unsqueeze(-1) # 摆杆倾角
pole_vel = joint_vel[:, self.pole_dof_idx[0]].unsqueeze(-1) # 摆杆角速度
obs = torch.cat(
(
cart_pos,
cart_vel,
pole_angle,
pole_vel,
),
dim=-1,
)
return {"policy": obs} # shape : [num_envs, observation_dim]
def _get_rewards(self) -> torch.Tensor:
joint_pos = self.cartpole.data.joint_pos
joint_vel = self.cartpole.data.joint_vel
cart_pos = joint_pos[:, self.cart_dof_idx[0]]
cart_vel = joint_vel[:, self.cart_dof_idx[0]]
pole_angle = joint_pos[:, self.pole_dof_idx[0]]
pole_vel = joint_vel[:, self.pole_dof_idx[0]]
alive_reward = 1.0
pole_angle_penalty = pole_angle.square()
cart_pos_penalty = 0.01 * cart_pos.square()
cart_vel_penalty = 0.001 * cart_vel.square()
pole_vel_penalty = 0.005 * pole_vel.square()
action_penalty = 0.001 * self.actions.squeeze(-1).square()
reward = (
alive_reward
- pole_angle_penalty
- cart_pos_penalty
- cart_vel_penalty
- pole_vel_penalty
- action_penalty
)
return reward # shape: [num_envs] 每个并行环境一个奖励值
def _get_dones(self) -> tuple[torch.Tensor, torch.Tensor]:
joint_pos = self.cartpole.data.joint_pos
cart_pos = joint_pos[:, self.cart_dof_idx[0]]
pole_angle = joint_pos[:, self.pole_dof_idx[0]]
time_out = self.episode_length_buf >= self.max_episode_length - 1 #达到最大步数结束
out_of_bounds = torch.logical_or(
torch.abs(cart_pos) > self.cfg.max_cart_pos,
torch.abs(pole_angle) > self.cfg.max_pole_angle,
) # 因为失败而结束
return out_of_bounds, time_out
def _reset_idx(self, env_ids: torch.Tensor | None):
if env_ids is None:
env_ids = self.cartpole._ALL_INDICES
super()._reset_idx(env_ids)
joint_pos = self.cartpole.data.default_joint_pos[env_ids].clone()
joint_vel = self.cartpole.data.default_joint_vel[env_ids].clone()
joint_pos[:, self.pole_dof_idx[0]] += torch.empty(
len(env_ids), device=self.device
).uniform_(-0.125, 0.125)
default_root_state = self.cartpole.data.default_root_state[env_ids].clone()
default_root_state[:, :3] += self.scene.env_origins[env_ids]
self.cartpole.write_root_pose_to_sim(default_root_state[:, :7], env_ids)
self.cartpole.write_root_velocity_to_sim(default_root_state[:, 7:], env_ids)
self.cartpole.write_joint_state_to_sim(joint_pos, joint_vel, None, env_ids)
定义了一个 Isaac Lab 直接强化学习环境,告诉框架怎么创建机器人场景、怎么接收动作、怎么控制机器人、怎么返回观测、怎么计算奖励、怎么判断结束以及怎么重置环境
3.环境设计
1)定义机器人
jetbot.py
代码如下:
JETBOT_CONFIG = ArticulationCfg(
spawn=sim_utils.UsdFileCfg(usd_path=f"{ISAAC_NUCLEUS_DIR}/Robots/NVIDIA/Jetbot/jetbot.usd"),
actuators={"wheel_acts": ImplicitActuatorCfg(joint_names_expr=[".*"], damping=None, stiffness=None)},
)
2)定义训练模拟并管理克隆
代码如下:
from isaac_lab_tutorial.robots.jetbot import JETBOT_CONFIG
@configclass
class IsaacLabTutorialEnvCfg(DirectRLEnvCfg):
# env
decimation = 2
episode_length_s = 5.0
# - spaces definition
action_space = 2
observation_space = 3
state_space = 0
# simulation
sim: SimulationCfg = SimulationCfg(dt=1 / 120, render_interval=decimation)
# robot(s)
robot_cfg: ArticulationCfg = JETBOT_CONFIG.replace(prim_path="/World/envs/env_.*/Robot")
# scene
scene: InteractiveSceneCfg = InteractiveSceneCfg(num_envs=100, env_spacing=4.0, replicate_physics=True)
dof_names = ["left_wheel_joint", "right_wheel_joint"] #关节名称
3)将代理的动作应用到机器人上
class IsaacLabTutorialEnv(DirectRLEnv):
cfg: IsaacLabTutorialEnvCfg
def __init__(self, cfg: IsaacLabTutorialEnvCfg, render_mode: str | None = None, **kwargs):
super().__init__(cfg, render_mode, **kwargs)
self.dof_idx, _ = self.robot.find_joints(self.cfg.dof_names)
def _setup_scene(self):
self.robot = Articulation(self.cfg.robot_cfg) #获取机器人
# add ground plane 负责碰撞、物理支撑
spawn_ground_plane(prim_path="/World/ground", cfg=GroundPlaneCfg())
# clone and replicate 批量克隆并行环境
self.scene.clone_environments(copy_from_source=False)
# add articulation to scene robot注册到场景管理
self.scene.articulations["robot"] = self.robot
# add lights 全局灯光
light_cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
light_cfg.func("/World/Light", light_cfg)
def _pre_physics_step(self, actions: torch.Tensor) -> None:
self.actions = actions.clone() #接收动作
def _apply_action(self) -> None:
self.robot.set_joint_velocity_target(self.actions, joint_ids=self.dof_idx) #执行动作
当我们谈论像机器人这样的场景实体时,我们可以广泛地谈论机器人,作为存在于每个场景中的实体,也可以描述一个具体、单一的克隆体 舞台上的机器人。
4)计算并返回奖励和观察结果
def _get_observations(self) -> dict: #每一轮自动交互
self.velocity = self.robot.data.root_com_lin_vel_b #获取线速度 [num_envs,3]
observations = {"policy": self.velocity}
return observations # 基座三轴速度作为唯一观测
def _get_rewards(self) -> torch.Tensor:
total_reward = torch.linalg.norm(self.velocity, dim=-1, keepdim=True) #计算三轴速度的二范数
return total_reward
对于每个场景的克隆,我们需要计算一个奖励值,并返回为形状的张量。作为占位符,我们将把奖励设为 喷气机器人在机体框架中的线速度大小。有了这个奖励和观察空间,代理应学会随机确定方向,向前或向后驾驶喷气机器人 训练刚开始不久。[num_envs, 1]
5)管理重置和终端状态
def _get_dones(self) -> tuple[torch.Tensor, torch.Tensor]:
time_out = self.episode_length_buf >= self.max_episode_length - 1 #最大时长
return False, time_out
def _reset_idx(self, env_ids: Sequence[int] | None):
if env_ids is None:
env_ids = self.robot._ALL_INDICES
super()._reset_idx(env_ids)
default_root_state = self.robot.data.default_root_state[env_ids]
default_root_state[:, :3] += self.scene.env_origins[env_ids]
self.robot.write_root_state_to_sim(default_root_state, env_ids)
终止和重置分成两部分处理。首先是方法,其目标很简单,就是标记哪些环境需要重置以及为什么。 传统上,在强化学习中,“发作”以两种方式结束:要么代理达到终结状态,要么发作达到最大持续时间。
4.注册task
isaac_lab_tutorial/source/isaac_lab_tutorial/isaac_lab_tutorial/tasks/direct/isaac_lab_tutorial/init.py
# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
import gymnasium as gym
from . import agents
##
# Register Gym environments.
##
gym.register(
id="Template-Isaac-Lab-Tutorial-Direct-v0",
entry_point=f"{__name__}.isaac_lab_tutorial_env:IsaacLabTutorialEnv",
disable_env_checker=True,
kwargs={
"env_cfg_entry_point": f"{__name__}.isaac_lab_tutorial_env_cfg:IsaacLabTutorialEnvCfg",
"skrl_amp_cfg_entry_point": f"{agents.__name__}:skrl_amp_cfg.yaml",
"skrl_cfg_entry_point": f"{agents.__name__}:skrl_ppo_cfg.yaml",
},
)
5.执行运行命令开始训练
这里task写上面注册号的id名
python scripts/skrl/train.py --task=Template-Isaac-Lab-Tutorial-Direct-v0
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)