Skip to content

Commit 281f731

Browse files
author
Kelly Guo
committed
Refactor: replace step(render=) param with render_enabled property
Replace the render flag parameter on step() with a mutable render_enabled property on all env base classes. Preserves the gymnasium.Env.step() API. Usage: env.render_enabled = False env.step(action) Classes: ManagerBasedEnv, ManagerBasedRLEnv, DirectRLEnv, DirectMARLEnv, MARL utility wrappers.
1 parent 4dd21ae commit 281f731

7 files changed

Lines changed: 59 additions & 31 deletions

File tree

source/isaaclab/docs/CHANGELOG.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ Changelog
77
Added
88
^^^^^
99

10-
* Added ``render`` flag to the ``step()`` method of all environment base classes
10+
* Added ``render_enabled`` property to all environment base classes
1111
(:class:`~isaaclab.envs.ManagerBasedEnv`, :class:`~isaaclab.envs.ManagerBasedRLEnv`,
1212
:class:`~isaaclab.envs.DirectRLEnv`, :class:`~isaaclab.envs.DirectMARLEnv`).
13-
Passing ``render=False`` skips all rendering calls (GUI updates, RTX sensor rendering,
14-
post-reset re-renders) while physics simulation continues normally. Defaults to ``True``
13+
Setting ``env.render_enabled = False`` before calling ``step()`` skips all rendering calls
14+
(GUI updates, RTX sensor rendering, post-reset re-renders) while physics simulation continues
15+
normally. The property can be toggled between steps for per-step control. Defaults to ``True``
1516
for full backward compatibility.
1617

1718

source/isaaclab/isaaclab/envs/direct_marl_env.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ def _init_sim(self, render_mode: str | None = None, **kwargs):
217217
# initialize data and constants
218218
# -- counter for simulation steps
219219
self._sim_step_counter = 0
220+
# -- rendering control
221+
self.render_enabled: bool = True
222+
"""Whether rendering is enabled during :meth:`step`.
223+
224+
When set to ``False``, all rendering calls (GUI updates, RTX sensor rendering, post-reset
225+
re-renders) are skipped while physics simulation continues normally. This can be toggled
226+
between steps to control rendering on a per-step basis. Defaults to ``True``.
227+
"""
220228
# -- counter for curriculum
221229
self.common_step_counter = 0
222230
# -- init buffers
@@ -373,7 +381,7 @@ def reset(
373381
# return observations
374382
return self.obs_dict, self.extras
375383

376-
def step(self, actions: dict[AgentID, ActionType], render: bool = True) -> EnvStepReturn:
384+
def step(self, actions: dict[AgentID, ActionType]) -> EnvStepReturn:
377385
"""Execute one time-step of the environment's dynamics.
378386
379387
The environment steps forward at a fixed time-step, while the physics simulation is decimated at a
@@ -391,11 +399,11 @@ def step(self, actions: dict[AgentID, ActionType], render: bool = True) -> EnvSt
391399
5. Apply interval events if they are enabled.
392400
6. Compute observations.
393401
402+
Rendering can be controlled per-step via :attr:`render_enabled`.
403+
394404
Args:
395405
actions: The actions to apply on the environment (keyed by the agent ID).
396406
Shape of individual tensors is (num_envs, action_dim).
397-
render: Whether to render during this step. When False, all rendering calls
398-
(GUI updates, RTX sensor rendering) are skipped. Defaults to True.
399407
400408
Returns:
401409
A tuple containing the observations, rewards, resets (terminated and truncated) and
@@ -413,7 +421,7 @@ def step(self, actions: dict[AgentID, ActionType], render: bool = True) -> EnvSt
413421

414422
# check if we need to do rendering within the physics loop
415423
# note: uses cached property to avoid settings lookup every step
416-
is_rendering = render and self.sim.is_rendering
424+
is_rendering = self.render_enabled and self.sim.is_rendering
417425

418426
# perform physics stepping
419427
for _ in range(self.cfg.decimation):

source/isaaclab/isaaclab/envs/direct_rl_env.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ def _init_sim(self, render_mode: str | None = None, **kwargs):
223223
# initialize data and constants
224224
# -- counter for simulation steps
225225
self._sim_step_counter = 0
226+
# -- rendering control
227+
self.render_enabled: bool = True
228+
"""Whether rendering is enabled during :meth:`step`.
229+
230+
When set to ``False``, all rendering calls (GUI updates, RTX sensor rendering, post-reset
231+
re-renders) are skipped while physics simulation continues normally. This can be toggled
232+
between steps to control rendering on a per-step basis. Defaults to ``True``.
233+
"""
226234
# -- counter for curriculum
227235
self.common_step_counter = 0
228236
# -- init buffers
@@ -367,7 +375,7 @@ def reset(self, seed: int | None = None, options: dict[str, Any] | None = None)
367375
# return observations
368376
return self._get_observations(), self.extras
369377

370-
def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
378+
def step(self, action: torch.Tensor) -> VecEnvStepReturn:
371379
"""Execute one time-step of the environment's dynamics.
372380
373381
The environment steps forward at a fixed time-step, while the physics simulation is decimated at a
@@ -385,10 +393,10 @@ def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
385393
5. Apply interval events if they are enabled.
386394
6. Compute observations.
387395
396+
Rendering can be controlled per-step via :attr:`render_enabled`.
397+
388398
Args:
389399
action: The actions to apply on the environment. Shape is (num_envs, action_dim).
390-
render: Whether to render during this step. When False, all rendering calls
391-
(GUI updates, RTX sensor rendering) are skipped. Defaults to True.
392400
393401
Returns:
394402
A tuple containing the observations, rewards, resets (terminated and truncated) and extras.
@@ -403,7 +411,7 @@ def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
403411

404412
# check if we need to do rendering within the physics loop
405413
# note: uses cached property to avoid settings lookup every step
406-
is_rendering = render and self.sim.is_rendering
414+
is_rendering = self.render_enabled and self.sim.is_rendering
407415

408416
# perform physics stepping
409417
for _ in range(self.cfg.decimation):

source/isaaclab/isaaclab/envs/manager_based_env.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ def _init_sim(self):
153153
# counter for simulation steps
154154
self._sim_step_counter = 0
155155

156+
# rendering control
157+
self.render_enabled: bool = True
158+
"""Whether rendering is enabled during :meth:`step`.
159+
160+
When set to ``False``, all rendering calls (GUI updates, RTX sensor rendering, post-reset
161+
re-renders) are skipped while physics simulation continues normally. This can be toggled
162+
between steps to control rendering on a per-step basis. Defaults to ``True``.
163+
"""
164+
156165
# allocate dictionary to store metrics
157166
self.extras = {}
158167

@@ -485,7 +494,7 @@ def reset_to(
485494
# return observations
486495
return self.obs_buf, self.extras
487496

488-
def step(self, action: torch.Tensor, render: bool = True) -> tuple[VecEnvObs, dict]:
497+
def step(self, action: torch.Tensor) -> tuple[VecEnvObs, dict]:
489498
"""Execute one time-step of the environment's dynamics.
490499
491500
The environment steps forward at a fixed time-step, while the physics simulation is
@@ -494,10 +503,10 @@ def step(self, action: torch.Tensor, render: bool = True) -> tuple[VecEnvObs, di
494503
simulation steps per environment step) and the :attr:`ManagerBasedEnvCfg.sim.dt` (physics time-step).
495504
Based on these parameters, the environment time-step is computed as the product of the two.
496505
506+
Rendering can be controlled per-step via :attr:`render_enabled`.
507+
497508
Args:
498509
action: The actions to apply on the environment. Shape is (num_envs, action_dim).
499-
render: Whether to render during this step. When False, all rendering calls
500-
(GUI updates, RTX sensor rendering) are skipped. Defaults to True.
501510
502511
Returns:
503512
A tuple containing the observations and extras.
@@ -509,7 +518,7 @@ def step(self, action: torch.Tensor, render: bool = True) -> tuple[VecEnvObs, di
509518

510519
# check if we need to do rendering within the physics loop
511520
# note: uses cached property to avoid settings lookup every step
512-
is_rendering = render and self.sim.is_rendering
521+
is_rendering = self.render_enabled and self.sim.is_rendering
513522

514523
# perform physics stepping
515524
for _ in range(self.cfg.decimation):

source/isaaclab/isaaclab/envs/manager_based_rl_env.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def setup_manager_visualizers(self):
158158
Operations - MDP
159159
"""
160160

161-
def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
161+
def step(self, action: torch.Tensor) -> VecEnvStepReturn:
162162
"""Execute one time-step of the environment's dynamics and reset terminated environments.
163163
164164
Unlike the :class:`ManagerBasedEnv.step` class, the function performs the following operations:
@@ -171,10 +171,10 @@ def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
171171
6. Compute the observations.
172172
7. Return the observations, rewards, resets and extras.
173173
174+
Rendering can be controlled per-step via :attr:`render_enabled`.
175+
174176
Args:
175177
action: The actions to apply on the environment. Shape is (num_envs, action_dim).
176-
render: Whether to render during this step. When False, all rendering calls
177-
(GUI updates, RTX sensor rendering) are skipped. Defaults to True.
178178
179179
Returns:
180180
A tuple containing the observations, rewards, resets (terminated and truncated) and extras.
@@ -186,7 +186,7 @@ def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
186186

187187
# check if we need to do rendering within the physics loop
188188
# note: uses cached property to avoid settings lookup every step
189-
is_rendering = render and self.sim.is_rendering
189+
is_rendering = self.render_enabled and self.sim.is_rendering
190190

191191
# perform physics stepping
192192
for _ in range(self.cfg.decimation):

source/isaaclab/isaaclab/envs/utils/marl.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def reset(self, seed: int | None = None, options: dict[str, Any] | None = None)
9797

9898
return obs, extras
9999

100-
def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
100+
def step(self, action: torch.Tensor) -> VecEnvStepReturn:
101101
# split single-agent actions to build the multi-agent ones
102102
# FIXME: This implementation assumes the spaces are fundamental ones. Fix it to support composite spaces
103103
index = 0
@@ -108,7 +108,7 @@ def step(self, action: torch.Tensor, render: bool = True) -> VecEnvStepReturn:
108108
index += delta
109109

110110
# step the environment
111-
obs, rewards, terminated, time_outs, extras = self.env.step(_actions, render=render)
111+
obs, rewards, terminated, time_outs, extras = self.env.step(_actions)
112112

113113
# use environment state as observation
114114
if self._state_as_observation:
@@ -233,7 +233,7 @@ def reset(
233233

234234
return obs, extras
235235

236-
def step(self, actions: dict[AgentID, ActionType], render: bool = True) -> EnvStepReturn:
236+
def step(self, actions: dict[AgentID, ActionType]) -> EnvStepReturn:
237237
# split agent actions to build the multi-agent ones
238238
# FIXME: This implementation assumes the spaces are fundamental ones. Fix it to support composite spaces
239239
index = 0
@@ -244,7 +244,7 @@ def step(self, actions: dict[AgentID, ActionType], render: bool = True) -> EnvSt
244244
index += delta
245245

246246
# step the environment
247-
obs, rewards, terminated, time_outs, extras = self.env.step(_actions, render=render)
247+
obs, rewards, terminated, time_outs, extras = self.env.step(_actions)
248248

249249
# use environment state as observation
250250
if self._state_as_observation:

source/isaaclab/test/envs/test_env_rendering_logic.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def wrapped_step(dt):
243243

244244
@pytest.mark.parametrize("env_type", ["manager_based_env", "manager_based_rl_env", "direct_rl_env"])
245245
def test_env_render_false_skips_rendering(env_type, physics_callback, render_callback):
246-
"""Test that passing render=False to step() skips all rendering while physics continues."""
246+
"""Test that setting render_enabled=False skips all rendering while physics continues."""
247247
physics_cb, get_physics_stats = physics_callback
248248
render_cb, get_render_stats = render_callback
249249

@@ -295,17 +295,18 @@ def wrapped_step(dt):
295295
# create a zero action tensor for stepping the environment
296296
actions = torch.zeros((env.num_envs, 0), device=env.device)
297297

298-
# Step with render=False for several steps
298+
# Step with render_enabled=False for several steps
299+
env.render_enabled = False
299300
for i in range(10):
300-
env.step(action=actions, render=False)
301+
env.step(action=actions)
301302

302303
# Physics should still advance normally
303304
_, num_physics_steps = get_physics_stats()
304-
assert num_physics_steps == (i + 1) * env.cfg.decimation, "Physics steps mismatch with render=False"
305+
assert num_physics_steps == (i + 1) * env.cfg.decimation, "Physics steps mismatch with render_enabled=False"
305306

306307
# No rendering should have occurred
307308
_, num_render_steps = get_render_stats()
308-
assert num_render_steps == 0, f"Expected 0 render steps with render=False, got {num_render_steps}"
309+
assert num_render_steps == 0, f"Expected 0 render steps with render_enabled=False, got {num_render_steps}"
309310

310311
finally:
311312
if viz is not None and original_step is not None:
@@ -320,7 +321,7 @@ def wrapped_step(dt):
320321

321322
@pytest.mark.parametrize("env_type", ["manager_based_env", "manager_based_rl_env", "direct_rl_env"])
322323
def test_env_render_flag_mixed_steps(env_type, physics_callback, render_callback):
323-
"""Test that render flag can be toggled between steps and rendering counts are correct."""
324+
"""Test that render_enabled can be toggled between steps and rendering counts are correct."""
324325
physics_cb, get_physics_stats = physics_callback
325326
render_cb, get_render_stats = render_callback
326327

@@ -374,10 +375,11 @@ def wrapped_step(dt):
374375

375376
expected_render_steps = 0
376377

377-
# Step 5 times with render=True, then 5 with render=False
378+
# Step 5 times with render_enabled=True, then 5 with render_enabled=False
378379
for i in range(10):
379380
should_render = i < 5
380-
env.step(action=actions, render=should_render)
381+
env.render_enabled = should_render
382+
env.step(action=actions)
381383

382384
# Physics always advances
383385
_, num_physics_steps = get_physics_stats()

0 commit comments

Comments
 (0)