包装环境#
gymnasium.Wrapper 可在不修改环境实现的情况下改变观测、奖励或执行过程,常用于录制视频和限制时间。
ManagerBasedRLEnv 和 DirectRLEnv 都实现 gymnasium.Env。先创建环境,再用 env = wrapper(env, *args, **kwargs) 依次套用包装器。顺序很重要:每个包装器接收其内层的输出。
例如,这是如何将一个环境包装起来强制在 step 或 render 之前调用 reset 的方式 :
import gymnasium as gym
from isaaclab.app import launch_simulation
import isaaclab_tasks # noqa: F401
from isaaclab_tasks.utils import load_cfg_from_registry
cfg = load_cfg_from_registry("Isaac-Reach-Franka", "env_cfg_entry_point")
# start the simulation runtime this configuration needs, and stop it on exit
with launch_simulation(cfg):
# create base environment
env = gym.make("Isaac-Reach-Franka", cfg=cfg)
# wrap environment to enforce that reset is called before step
env = gym.wrappers.OrderEnforcing(env)
用于记录视频的包装器#
gymnasium.wrappers.RecordVideo 包装器可用于记录环境的视频。该包装器接受一个 video_dir 参数,指定要保存视频的位置。根据指定的步数或情节,以指定的间隔将视频以 mp4 格式保存。
要使用该包装器,您需要首先安装 ffmpeg 。在 Ubuntu 上,可以通过运行以下命令进行安装 :
sudo apt-get install ffmpeg
注意
默认情况下,在无头模式运行环境时,Omniverse 视口会被禁用。这样做是为了通过避免不必要的渲染来提高性能。
使用 RTX 3090 GPU 运行 Isaac-Reach-Franka 环境时,不同渲染模式的性能如下:
没有开启离屏渲染的无 GUI 执行 : ~65,000 FPS
开启了离屏渲染的无 GUI 执行 : ~57,000 FPS
全渲染的 GUI 执行 : ~13,000 FPS
用于渲染的视口相机是场景中称为 "/OmniverseKit_Persp" 的默认相机。相机的姿势和图像分辨率可以通过 ViewerCfg 类进行配置。
ViewerCfg 类的默认参数 :
@configclass
class ViewerCfg:
"""Configuration of the scene viewport camera.
.. deprecated::
:class:`ViewerCfg` is deprecated and will be removed in a future release.
Configure the viewport camera via :class:`~isaaclab_visualizers.kit.KitVisualizerCfg`
and add it to :attr:`~isaaclab.sim.SimulationCfg.visualizer_cfgs` instead, which applies when
``--visualizer kit`` selects the Kit visualizer::
from isaaclab.sim import SimulationCfg
from isaaclab_visualizers.kit import KitVisualizerCfg
sim_cfg = SimulationCfg(visualizer_cfgs=[KitVisualizerCfg(eye=(7.5, 7.5, 7.5), lookat=(0.0, 0.0, 0.0))])
"""
eye: tuple[float, float, float] = (7.5, 7.5, 7.5)
"""Initial camera position (in m). Default is (7.5, 7.5, 7.5)."""
lookat: tuple[float, float, float] = (0.0, 0.0, 0.0)
"""Initial camera target position (in m). Default is (0.0, 0.0, 0.0)."""
cam_prim_path: str = "/OmniverseKit_Persp"
"""The camera prim path to record images from. Default is "/OmniverseKit_Persp"."""
resolution: tuple[int, int] = (1280, 720)
"""The resolution (width, height) of the camera. Default is (1280, 720)."""
origin_type: Literal["world", "env", "asset_root", "asset_body"] = "world"
"""The frame in which the camera position (eye) and target (lookat) are defined. Default is "world"."""
env_index: int = 0
"""The environment index for frame origin. Default is 0."""
asset_name: str | None = None
"""The asset name in the interactive scene for the frame origin. Default is None."""
body_name: str | None = None
"""The name of the body in :attr:`asset_name` for the frame origin. Default is None."""
def __post_init__(self) -> None:
# Warn only when the user configured a non-default field so that bare ``ViewerCfg()``
# usage (e.g. in task configs that haven't been migrated yet) stays silent.
#
# @configclass stores mutable defaults (tuples, lists) via default_factory rather than
# default, so we must check both to obtain the canonical default value.
differing = []
for f in fields(self):
if not f.init:
continue
if f.default is not MISSING:
default = f.default
elif f.default_factory is not MISSING: # type: ignore[misc]
default = f.default_factory() # type: ignore[misc]
else:
continue
if not _viewer_cfg_field_matches_default(getattr(self, f.name), default):
differing.append(f.name)
if differing:
warnings.warn(
"ViewerCfg is deprecated and will be removed in a future release. "
"Use KitVisualizerCfg added to SimulationCfg.visualizer_cfgs instead.",
DeprecationWarning,
stacklevel=2,
)
要录制视频,将 VideoRecorderCfg 添加到环境配置。它会在环境步进时,从可视化器或相机传感器录制 mp4 片段,因此无需包装器或 render_mode ,且会自动启动可视化器所需的运行时。
例如,以下代码每隔 1500 步,从 Kit 可视化器录制 Isaac-Reach-Franka 环境的一段 200 步视频,保存到 videos/train 目录。其他录制源和片段选项见 录制视频 。
import gymnasium as gym
from isaaclab_visualizers.kit import KitVisualizerCfg
from isaaclab.app import launch_simulation
from isaaclab.envs.utils.video_recorder_cfg import VideoRecorderCfg
# record from a Kit visualizer with this camera pose
env_cfg.sim.visualizer_cfgs = KitVisualizerCfg(eye=(1.0, 1.0, 1.0), lookat=(0.0, 0.0, 0.0))
env_cfg.video_recorders = [
VideoRecorderCfg(source="viz:kit", output_dir="videos/train", video_length=200, video_interval=1500)
]
# select the Kit visualizer, as ``--viz kit`` does; the config above only sets its camera pose
with launch_simulation(env_cfg, {"visualizer": "kit"}):
env = gym.make(task_name, cfg=env_cfg)
学习框架的包装器#
每个学习框架都有自己的 API 与环境交互。例如, Stable-Baselines3 库使用 gym.Env 接口与环境进行交互。然而,像 RL-Games , RSL-RL 或 SKRL 这样的库使用自己的 API 来与学习环境进行交互。由于并非所有情况均适用,我们不会将 ManagerBasedRLEnv 和 DirectRLEnv 类建立在任何特定学习框架的环境定义基础上。相反,我们实现包装器来使其与学习框架的环境定义兼容。
使用 Stable-Baselines3 与 RL 任务环境的示例 :
from isaaclab_rl.sb3 import Sb3VecEnvWrapper
# create isaac-env instance
env = gym.make(task_name, cfg=env_cfg)
# wrap around environment for stable baselines
env = Sb3VecEnvWrapper(env)
Stable-Baselines3 要求连续动作具有有限边界。如果环境的动作空间无界, Sb3VecEnvWrapper 会向 Stable-Baselines3 提供归一化的 [-1, 1] 边界,同时保持底层环境不变。如果策略使用其他有限动作范围,应设置 action_bounds 。
小心
在应用所有其他包装器后,应在最后使用相应学习框架的包装器包装环境。这是因为学习框架的包装器会修改环境 API 的解释,这可能不再与 gymnasium.Env 兼容。
添加新的包装器#
所有新的包装器都应添加到 isaaclab_rl 模块。它们应该检查底层环境是否是 isaaclab.envs.ManagerBasedRLEnv 或 DirectRLEnv 类的实例,然后再应用该包装器。这可以通过使用 unwrapped() 属性来完成。
我们在这个模块中包括了一组包装器,供您作为实现自己包装器的参考。如果您实现了一个新的包装器,请考虑通过开放一个拉取请求将其贡献给框架。