在isaaclab中创建的强化学习训练环境有两种:direct workflow,风格与isaacgym一样。另外一种是manager-based workflow更加模块化,它主要是两部分包括仿真环境也就是即将介绍的interactive scene,与mdp的内容,比如奖励函数,observcation等等。
这次介绍的interactive scene是用来加载各种asset,同时也包括了简易整体的运行框架,之后不一定经常用到,但是对了解isaaclab的运行模式很有帮助,而且也适合想用并行环境做一些non-learning-based methods的轨迹规划等工作。
官方tutorial连接:
Using the Interactive Scene — Isaac Lab Documentation
代码:
# Copyright (c) 2022-2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""This script demonstrates how to use the interactive scene interface to setup a scene with multiple prims.
.. code-block:: bash
# Usage
./isaaclab.sh -p scripts/tutorials/02_scene/create_scene.py --num_envs 32
"""
"""Launch Isaac Sim Simulator first."""
import argparse
from isaaclab.app import AppLauncher
# add argparse arguments
parser = argparse.ArgumentParser(description="Tutorial on using the interactive scene interface.")
parser.add_argument("--num_envs", type=int, default=2, help="Number of environments to spawn.")
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()
# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
"""Rest everything follows."""
import torch
import isaaclab.sim as sim_utils
from isaaclab.assets import ArticulationCfg, AssetBaseCfg
from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
from isaaclab.sim import SimulationContext
from isaaclab.utils import configclass
##
# Pre-defined configs
##
# 在这种模块化的环境中,一般会把机器人配置文件单独生成,因为机器人的参数比较多,
# 单独列成文件修改比较方便,而且机器人参数设定之后一般不会经常修改,
# 可以直接在其他环境调用。
from isaaclab_assets import CARTPOLE_CFG
# 下面是场景设置,包含了所有的asset,地板,灯光,机器人等等需要加载的内容,
# 但是在这里只是设置参数,无法进行任何交互,
# 之后根据这个场景设置文件,加载场景之后才会进入到仿真。
@configclass
class CartpoleSceneCfg(InteractiveSceneCfg):
"""Configuration for a cart-pole scene."""
ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
dome_light = AssetBaseCfg(
prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
)
# {ENV_REGEX_NS}是一种便捷的正则化命名方式
# 会根据环境数量自动复制asset到每一个并行环境:env[0,1...,num_env]/Robot,
# 也是一个比较有用的wrapper。
cartpole: ArticulationCfg = CARTPOLE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
# 这个是比较朴直观的仿真流程,之后强化学校训练需要的内容基本上都是要从这个仿真过程中获取信息
def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
"""Runs the simulation loop."""
# 读取我们刚刚在scene设置rigid body,aritulation,
# 注意这里普通的asset比如灯光地板这些是没有交互属性的,
# 除非设置成可交互的rigid/deformable body或者articulation
robot = scene["cartpole"]
# Define simulation stepping
sim_dt = sim.get_physics_dt()
count = 0
# Simulation loop
while simulation_app.is_running():
# Reset部分,根据之前的CFG文件里的默认机器人参数,特别是位姿,恢复到初始位置
if count % 500 == 0:
# reset counter
count = 0
# 这里获取的位姿要注意,root_state获取的是相对于该子并行环境env[0,1,..]的位姿,
# 但是每个子并行环境在整体环境(也就是world frame下)也都有自己的坐标,
# 这些坐标是根据设置的环境间隔决定的,
# 比如我们设置环境间隔是2m,
# 那么每个子环境的坐标大概就是[4(2x2),0,0],[2,2,0]这样子。
# 所以根据需求我们需要获取不同的位姿,是独立子环境下还是在整个大环境下。
root_state = robot.data.default_root_state.clone()
root_state[:, :3] += scene.env_origins
# 这里就是写入信息到仿真环境中了,就像我们设置完状态之后需要告知环境我们的改变。
robot.write_root_pose_to_sim(root_state[:, :7])
robot.write_root_velocity_to_sim(root_state[:, 7:])
# set joint positions with some noise
joint_pos, joint_vel = robot.data.default_joint_pos.clone(), robot.data.default_joint_vel.clone()
joint_pos += torch.rand_like(joint_pos) * 0.1
robot.write_joint_state_to_sim(joint_pos, joint_vel)
# clear internal buffers
scene.reset()
print("[INFO]: Resetting robot state...")
# 这里是每个step的机器人控制部分了
# 可以添加自己的IK solver,controller。
# 如果做motion planing,比如RRT算法,这里可以开始撒点探索了。
# 教程代码里是对每个关节施加了随机大小的力,让它随机运动。
efforts = torch.randn_like(robot.data.joint_pos) * 5.0
# 决定力大小之后要告知机器人,让机器人模型加载这个力
robot.set_joint_effort_target(efforts)
# 加载结束之后同样要告知环境进行模拟
scene.write_data_to_sim()
# Perform step
sim.step()
# Increment counter
count += 1
# Update buffers
scene.update(sim_dt)
def main():
"""Main function."""
# 这里就是加载simulation的cfg文件,
# 然后用SimulationContext加载环境,
# 这时候的仿真已经具备物理环境参数了,比如重力什么的,但是还没有加载asset
sim_cfg = sim_utils.SimulationCfg(device=args_cli.device)
sim = SimulationContext(sim_cfg)
# Set main camera
sim.set_camera_view([2.5, 0.0, 4.0], [0.0, 0.0, 2.0])
# 这里就是加载scene了,也就是场景,
# 加载物体,机器人什么的,同时设置需要并行环境数量与间距
scene_cfg = CartpoleSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0)
scene = InteractiveScene(scene_cfg)
# 重置环境,reset是设置完之后必须要做的,cache一下各种api,
# 这时候就没有办法再加载新的asset了,
# 有点类似于上课前的点名,点完名就上课了,不再接受其他学生了。
sim.reset()
# Now we are ready!
print("[INFO]: Setup complete...")
# 这里就是我们之前设置的仿真循环了
run_simulator(sim, scene)
if __name__ == "__main__":
# run the main function
main()
# close sim app
simulation_app.close()
在代码中我用中文注释了一些内容帮助大家理解整个仿真框架,我们最近基于这个环境开发了一个抓取环境,在object上随机取点,测试哪个点是最容易抓取的,后续完成了会开个帖子放代码。