Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes grid origins in TerrainImporter to match Isaac Sim cloner #300

Merged
merged 14 commits into from
Mar 24, 2024
Merged
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Guidelines for modifications:
* René Zurbrügg
* Ritvik Singh
* Rosario Scalise
* Shafeef Omar

## Acknowledgements

Expand Down
2 changes: 1 addition & 1 deletion source/extensions/omni.isaac.orbit/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "0.15.1"
version = "0.15.2"

# Description
title = "ORBIT framework for Robot Learning"
Expand Down
16 changes: 16 additions & 0 deletions source/extensions/omni.isaac.orbit/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
Changelog
---------

0.15.2 (2024-03-21)
~~~~~~~~~~~~~~~~~~~

Fixed
^^^^^

* Fixed the env origins in :meth:`_compute_env_origins_grid` of :class:`omni.isaac.orbit.terrain.TerrainImporter`
to match that of Isaac Sim cloner in :class:`omni.isaac.cloner.GridCloner`.

Added
^^^^^

* Added unit test to ensure consistency between environment origins generated by IsaacSim's Grid Cloner and those
produced by the TerrainImporter.


0.15.1 (2024-03-19)
~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,16 @@ def _compute_env_origins_curriculum(self, num_envs: int, origins: torch.Tensor)
return env_origins

def _compute_env_origins_grid(self, num_envs: int, env_spacing: float) -> torch.Tensor:
"""Compute the origins of the environments in a grid based on configured spacing."""
"""Compute the origins of the environments in a grid based on configured spacing"""
Mayankm96 marked this conversation as resolved.
Show resolved Hide resolved
# create tensor based on number of environments
env_origins = torch.zeros(num_envs, 3, device=self.device)
# create a grid of origins
num_cols = np.floor(np.sqrt(num_envs))
num_rows = np.ceil(num_envs / num_cols)
xx, yy = torch.meshgrid(torch.arange(num_rows), torch.arange(num_cols), indexing="xy")
env_origins[:, 0] = env_spacing * xx.flatten()[:num_envs] - env_spacing * (num_rows - 1) / 2
env_origins[:, 1] = env_spacing * yy.flatten()[:num_envs] - env_spacing * (num_cols - 1) / 2
num_rows = np.ceil(num_envs / int(np.sqrt(num_envs)))
num_cols = np.ceil(num_envs / num_rows)
ii, jj = torch.meshgrid(
torch.arange(num_rows, device=self.device), torch.arange(num_cols, device=self.device), indexing="ij"
)
env_origins[:, 0] = -(ii.flatten()[:num_envs] - (num_rows - 1) / 2) * env_spacing
env_origins[:, 1] = (jj.flatten()[:num_envs] - (num_cols - 1) / 2) * env_spacing
env_origins[:, 2] = 0.0
return env_origins
104 changes: 104 additions & 0 deletions source/extensions/omni.isaac.orbit/test/terrains/test_grid_cloner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) 2022-2024, The ORBIT Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""
This script checks whether the env origins generated by the TerrainImporter for flat
ground and Isaac SimGrid Cloner are the same.
"""

from __future__ import annotations

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

from omni.isaac.orbit.app import AppLauncher

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

"""Rest everything follows."""

import torch
import unittest

import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
from omni.isaac.cloner import GridCloner

import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.terrains import TerrainImporter, TerrainImporterCfg


def get_grid_cloner_env_origins(num_envs: int = 1, env_spacing: float = 3.0):
"""Get env_origins generated by IsaacSim GridCloner (grid_cloner.py)."""
cloner = GridCloner(spacing=env_spacing)
cloner.define_base_env("/World/envs")
envs_prim_paths = cloner.generate_paths("/World/envs/env", num_paths=num_envs)
prim_utils.define_prim("/World/envs/env_0")
isaac_sim_env_origins = torch.tensor(
cloner.clone(source_prim_path="/World/envs/env_0", prim_paths=envs_prim_paths, replicate_physics=True),
device="cuda:0",
dtype=torch.float32,
)

return isaac_sim_env_origins


def get_terrain_importer_env_origins(num_envs: int = 1, env_spacing: float = 3.0):
"""Get env_origins generated by TerrainImporter (_compute_env_origins_grid())."""
terrain_importer_cfg = TerrainImporterCfg(
num_envs=num_envs,
env_spacing=env_spacing,
prim_path="/World/ground",
terrain_type="plane",
terrain_generator=None,
)
terrain_importer = TerrainImporter(terrain_importer_cfg)
return terrain_importer.env_origins


class TestGridCloner(unittest.TestCase):
"""Test for grid cloning."""

def setUp(self):
"""Create a blank new stage for each test."""
# Create a new stage
stage_utils.create_new_stage()
# Load kit helper
self.sim = sim_utils.SimulationContext(sim_utils.SimulationCfg(dt=0.005))

def tearDown(self):
"""Stops simulator after each test."""
# stop simulation
self.sim.stop()
# clear the stage
self.sim.clear_instance()

"""
Tests
"""

def test_env_origins(self):
"""Test env origins generated by TerrainImporter & IsaacSim GridCloner to check consistency."""
# fix env spacing for convenience
env_spacing = 2.17
# iterate over different number of environments
for num_envs in [1, 4, 7, 12]:
with self.subTest(num_envs=num_envs):
with sim_utils.build_simulation_context(auto_add_lighting=True) as sim:
grid_cloner_origins = get_grid_cloner_env_origins(num_envs, env_spacing)
terrain_origins = get_terrain_importer_env_origins(num_envs, env_spacing)
self.assertTrue(torch.all(terrain_origins == grid_cloner_origins))

sim.reset()
for _ in range(5):
sim.step()


if __name__ == "__main__":
# run main
unittest.main(verbosity=2, exit=False)
# close sim app
simulation_app.close()