Unverified Commit 052c277b authored by David Hoeller's avatar David Hoeller Committed by GitHub

Fixes running environments with a single instance (#355)

# Description

This MR fixes running of single environments (`num_envs=1`). Previously,
in the `InteractiveScene` class, physics cloning happened when the
`replicate_physics` flag was set to True even if there was only one
environment.

Fixes [#199](https://github.com/NVIDIA-Omniverse/orbit/issues/199) and
[#203](https://github.com/NVIDIA-Omniverse/orbit/issues/203)

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have run all the tests with `./orbit.sh --test` and they pass
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
parent 9c3f65f3
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.10.12" version = "0.10.13"
# Description # Description
title = "ORBIT framework for Robot Learning" title = "ORBIT framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.10.13 (2024-01-15)
~~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Fixed running of environments with a single instance even if the :attr:`replicate_physics`` flag is set to True.
0.10.12 (2024-01-10) 0.10.12 (2024-01-10)
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
......
...@@ -142,7 +142,7 @@ class InteractiveScene: ...@@ -142,7 +142,7 @@ class InteractiveScene:
self._add_entities_from_cfg() self._add_entities_from_cfg()
# replicate physics if we have more than one environment # replicate physics if we have more than one environment
# this is done to make scene initialization faster at play time # this is done to make scene initialization faster at play time
if self.cfg.replicate_physics: if self.cfg.replicate_physics and self.cfg.num_envs > 1:
# in isaac sim 2022.2, this function is private # in isaac sim 2022.2, this function is private
if isaac_major_version == 2022: if isaac_major_version == 2022:
self.cloner._replicate_physics( # pyright: ignore [reportPrivateUsage] self.cloner._replicate_physics( # pyright: ignore [reportPrivateUsage]
......
...@@ -49,20 +49,48 @@ class TestEnvironments(unittest.TestCase): ...@@ -49,20 +49,48 @@ class TestEnvironments(unittest.TestCase):
# print all existing task names # print all existing task names
print(">>> All registered environments:", cls.registered_tasks) print(">>> All registered environments:", cls.registered_tasks)
def setUp(self) -> None: """
Test fixtures.
"""
def test_multiple_instances_gpu(self):
"""Run all environments with multiple instances and check environments return valid signals."""
# common parameters # common parameters
self.num_envs = 64 num_envs = 32
self.use_gpu = True use_gpu = True
# iterate over all registered environments
for task_name in self.registered_tasks:
print(f">>> Running test for environment: {task_name}")
# check environment
self._check_random_actions(task_name, use_gpu, num_envs, num_steps=1000)
# close the environment
print(f">>> Closing environment: {task_name}")
print("-" * 80)
def test_random_actions(self): def test_single_instance_gpu(self):
"""Run random actions and check environments return valid signals.""" """Run all environments with single instance and check environments return valid signals."""
# common parameters
num_envs = 1
use_gpu = True
# iterate over all registered environments
for task_name in self.registered_tasks: for task_name in self.registered_tasks:
print(f">>> Running test for environment: {task_name}") print(f">>> Running test for environment: {task_name}")
# check environment
self._check_random_actions(task_name, use_gpu, num_envs, num_steps=1000)
# close the environment
print(f">>> Closing environment: {task_name}")
print("-" * 80)
"""
Helper functions.
"""
def _check_random_actions(self, task_name: str, use_gpu: bool, num_envs: int, num_steps: int = 1000):
"""Run random actions and check environments return valid signals."""
# create a new stage # create a new stage
omni.usd.get_context().new_stage() omni.usd.get_context().new_stage()
# parse configuration # parse configuration
env_cfg: RLTaskEnvCfg = parse_env_cfg(task_name, use_gpu=self.use_gpu, num_envs=self.num_envs) env_cfg: RLTaskEnvCfg = parse_env_cfg(task_name, use_gpu=use_gpu, num_envs=num_envs)
# create environment # create environment
env: RLTaskEnv = gym.make(task_name, cfg=env_cfg) env: RLTaskEnv = gym.make(task_name, cfg=env_cfg)
...@@ -70,10 +98,9 @@ class TestEnvironments(unittest.TestCase): ...@@ -70,10 +98,9 @@ class TestEnvironments(unittest.TestCase):
obs, _ = env.reset() obs, _ = env.reset()
# check signal # check signal
self.assertTrue(self._check_valid_tensor(obs)) self.assertTrue(self._check_valid_tensor(obs))
# simulate environment for num_steps steps
# simulate environment for 1000 steps
with torch.inference_mode(): with torch.inference_mode():
for _ in range(1000): for _ in range(num_steps):
# sample actions from -1 to 1 # sample actions from -1 to 1
actions = 2 * torch.rand(env.action_space.shape, device=env.unwrapped.device) - 1 actions = 2 * torch.rand(env.action_space.shape, device=env.unwrapped.device) - 1
# apply actions # apply actions
...@@ -83,13 +110,8 @@ class TestEnvironments(unittest.TestCase): ...@@ -83,13 +110,8 @@ class TestEnvironments(unittest.TestCase):
self.assertTrue(self._check_valid_tensor(data), msg=f"Invalid data: {data}") self.assertTrue(self._check_valid_tensor(data), msg=f"Invalid data: {data}")
# close the environment # close the environment
print(f">>> Closing environment: {task_name}")
env.close() env.close()
"""
Helper functions.
"""
@staticmethod @staticmethod
def _check_valid_tensor(data: torch.Tensor | dict) -> bool: def _check_valid_tensor(data: torch.Tensor | dict) -> bool:
"""Checks if given data does not have corrupted values. """Checks if given data does not have corrupted values.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment