包装环境#

环境包装器是一种修改环境行为而不修改环境本身的方法。这可以用来应用函数来修改观察或奖励,记录视频,强制时间限制等。API的详细说明在 gymnasium.Wrapper 类中可用。

目前,所有继承自 ManagerBasedRLEnv 类或 DirectRLEnv 类的RL环境都与 gymnasium.Wrapper 兼容,因为基类实现了 gymnasium.Env 接口。要包装一个环境,您需要先初始化基础环境。然后,您可以通过多次调用 env = wrapper(env, *args, **kwargs) 来包装它,以便包装尽可能多的包装器。

例如,这是如何将一个环境包装起来强制在step或render之前调用reset的方式 :

"""Launch Isaac Sim Simulator first."""


from omni.isaac.lab.app import AppLauncher

# launch omniverse app in headless mode
app_launcher = AppLauncher(headless=True)
simulation_app = app_launcher.app

"""Rest everything follows."""

import gymnasium as gym

import omni.isaac.lab_tasks  # noqa: F401
from omni.isaac.lab_tasks.utils import load_cfg_from_registry

# create base environment
cfg = load_cfg_from_registry("Isaac-Reach-Franka-v0", "env_cfg_entry_point")
env = gym.make("Isaac-Reach-Franka-v0", 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-v0 环境中采用不同的渲染模式时的性能 :

  • 没有开启离屏渲染的无 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."""

    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",
    which is the default camera in the viewport.
    """

    resolution: tuple[int, int] = (1280, 720)
    """The resolution (width, height) of the camera specified using :attr:`cam_prim_path`.
    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 in. Default is "world".

    Available options are:

    * ``"world"``: The origin of the world.
    * ``"env"``: The origin of the environment defined by :attr:`env_index`.
    * ``"asset_root"``: The center of the asset defined by :attr:`asset_name` in environment :attr:`env_index`.
    * ``"asset_body"``: The center of the body defined by :attr:`body_name` in asset defined by :attr:`asset_name` in environment :attr:`env_index`.
    """

    env_index: int = 0
    """The environment index for frame origin. Default is 0.

    This quantity is only effective if :attr:`origin` is set to "env" or "asset_root".
    """

    asset_name: str | None = None
    """The asset name in the interactive scene for the frame origin. Default is None.

    This quantity is only effective if :attr:`origin` is set to "asset_root".
    """

    body_name: str | None = None
    """The name of the body in :attr:`asset_name` in the interactive scene for the frame origin. Default is None.

    This quantity is only effective if :attr:`origin` is set to "asset_body".
    """

调整参数后,您可以通过将环境包装在 gymnasium.wrappers.RecordVideo 包装器并启用离屏渲染标志来记录视频。此外,您需要指定环境的渲染模式为 "rgb_array"

例如,以下代码将记录 Isaac-Reach-Franka-v0 环境的视频,持续200步,并将其保存在 videos 文件夹中,步长为1500步。

"""Launch Isaac Sim Simulator first."""


from omni.isaac.lab.app import AppLauncher

# launch omniverse app in headless mode with off-screen rendering
app_launcher = AppLauncher(headless=True, enable_cameras=True)
simulation_app = app_launcher.app

"""Rest everything follows."""

import gymnasium as gym

# adjust camera resolution and pose
env_cfg.viewer.resolution = (640, 480)
env_cfg.viewer.eye = (1.0, 1.0, 1.0)
env_cfg.viewer.lookat = (0.0, 0.0, 0.0)
# create isaac-env instance
# set render mode to rgb_array to obtain images on render calls
env = gym.make(task_name, cfg=env_cfg, render_mode="rgb_array")
# wrap for video recording
video_kwargs = {
    "video_folder": "videos/train",
    "step_trigger": lambda step: step % 1500 == 0,
    "video_length": 200,
}
env = gym.wrappers.RecordVideo(env, **video_kwargs)

学习框架的包装器#

每个学习框架都有自己的API与环境交互。例如, Stable-Baselines3 库使用 gym.Env 接口与环境进行交互。然而,像 RL-GamesRSL-RLSKRL 这样的库使用自己的API来与学习环境进行交互。由于并非所有情况均适用,我们不会将 ManagerBasedRLEnvDirectRLEnv 类建立在任何特定学习框架的环境定义基础上。相反,我们实现包装器来使其与学习框架的环境定义兼容。

使用Stable-Baselines3与RL任务环境的示例 :

from omni.isaac.lab_tasks.utils.wrappers.sb3 import Sb3VecEnvWrapper

# create isaac-env instance
env = gym.make(task_name, cfg=env_cfg)
# wrap around environment for stable baselines
env = Sb3VecEnvWrapper(env)

小心

在应用所有其他包装器后,应在最后使用相应学习框架的包装器包装环境。这是因为学习框架的包装器会修改环境API的解释,这可能不再与 gymnasium.Env 兼容。

添加新的包装器#

所有新的包装器都应添加到 omni.isaac.lab_tasks.utils.wrappers 模块。它们应该检查底层环境是否是 omni.isaac.lab.envs.ManagerBasedRLEnvDirectRLEnv 类的实例,然后再应用该包装器。这可以通过使用 unwrapped() 属性来完成。

我们在这个模块中包括了一组包装器,供您作为实现自己包装器的参考。如果您实现了一个新的包装器,请考虑通过开放一个拉取请求将其贡献给框架。