Wrapping environments
Environment wrappers are a way to modify the behavior of an environment without modifying the environment itself.
This can be used to apply functions to modify observations or rewards, record videos, enforce time limits, etc.
A detailed description of the API is available in the gymnasium.Wrapper class.
At present, all RL environments inheriting from the ~envs.ManagerBasedRLEnv or ~envs.DirectRLEnv classes
are compatible with gymnasium.Wrapper, since the base class implements the gymnasium.Env interface.
In order to wrap an environment, you need to first initialize the base environment. After that, you can
wrap it with as many wrappers as you want by calling env = wrapper(env, *args, **kwargs) repeatedly.
For example, here is how you would wrap an environment to enforce that reset is called before step or render:
Wrapper for recording videos
The gymnasium.wrappers.RecordVideo wrapper can be used to record videos of the environment.
The wrapper takes a video_dir argument, which specifies where to save the videos. The videos are saved in
mp4 format at specified intervals for specified
number of environment steps or episodes.
To use the wrapper, you need to first install ffmpeg. On Ubuntu, you can install it by running:
By default, when running an environment in headless mode, the Omniverse viewport is disabled. This is done to improve performance by avoiding unnecessary rendering.
We notice the following performance in different rendering modes with the Isaac-Reach-Franka environment
using an RTX 3090 GPU:
- No GUI execution without off-screen rendering enabled: ~65,000 FPS
- No GUI execution with off-screen enabled: ~57,000 FPS
- GUI execution with full rendering: ~13,000 FPS
The viewport camera used for rendering is the default camera in the scene called "/OmniverseKit_Persp".
The camera’s pose and image resolution can be configured through the
~envs.ViewerCfg class.
To record videos, add a ~envs.utils.video_recorder_cfg.VideoRecorderCfg to the environment
configuration. It records from a visualizer (or a camera sensor) into mp4 clips while the environment steps,
so no wrapper or render_mode is needed, and the runtime the visualizer needs starts automatically.
As an example, the following code records 200-step clips of the Isaac-Reach-Franka environment from a Kit
visualizer every 1500 steps into the videos/train folder. See Recording video for the other
sources and clip options.
Wrapper for learning frameworks
Every learning framework has its own API for interacting with environments. For example, the
Stable-Baselines3 library uses the gym.Env
interface to interact with environments. However, libraries like RL-Games, RSL-RL or SKRL
use their own API for interfacing with a learning environments. Since there is no one-size-fits-all
solution, we do not base the ~envs.ManagerBasedRLEnv and ~envs.DirectRLEnv classes on any particular learning framework’s
environment definition. Instead, we implement wrappers to make it compatible with the learning
framework’s environment definition.
As an example of how to use the RL task environment with Stable-Baselines3:
Stable-Baselines3 requires finite continuous action bounds. When the environment has an unbounded action
space, ~isaaclab_rl.sb3.Sb3VecEnvWrapper exposes normalized [-1, 1] bounds to Stable-Baselines3
without changing the underlying environment. Set action_bounds when the policy uses a different
finite action domain.
Wrapping the environment with the respective learning framework’s wrapper should happen in the end,
i.e. after all other wrappers have been applied. This is because the learning framework’s wrapper
modifies the interpretation of environment’s APIs which may no longer be compatible with gymnasium.Env.
Adding new wrappers
All new wrappers should be added to the isaaclab_rl module.
They should check that the underlying environment is an instance of isaaclab.envs.ManagerBasedRLEnv
or ~envs.DirectRLEnv
before applying the wrapper. This can be done by using the unwrapped property.
We include a set of wrappers in this module that can be used as a reference to implement your own wrappers. If you implement a new wrapper, please consider contributing it to the framework by opening a pull request.