Unverified Commit bd87f9c1 authored by Mayank Mittal's avatar Mayank Mittal Committed by GitHub

Splits terrain importer and terrain generator configuration files (#100)

# Description

Earlier the `TerrainGeneratorCfg` and `TerrainImporterCfg` were in the
same file. However, this leads to some issues with circular dependencies
when referring to the `TerrainImporter` as an attribute of the
`TerrainImporterCfg` (i.e. providing the class name as a member of the
config object).

The MR fixes the above circular dependency. Also, it moves all the
terrain parameters to its configuration object to make the terrain
initialization consistent with the other asset constructors.

## Type of change

- Breaking change (fix or feature that would cause existing
functionality to not work as expected)

## 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
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
parent 8f8c3700
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.8.1" version = "0.8.2"
# Description # Description
title = "ORBIT framework for Robot Learning" title = "ORBIT framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.8.2 (2023-08-02)
~~~~~~~~~~~~~~~~~~
Changed
^^^^^^^
* Cleaned up the :class:`omni.isaac.orbit.terrain.TerrainImporter` class to take all the parameters from the configuration
object. This makes it consistent with the other classes in the package.
* Moved the configuration classes for terrain generator and terrain importer into separate files to resolve circular
dependency issues.
0.8.1 (2023-08-02) 0.8.1 (2023-08-02)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
......
...@@ -23,8 +23,9 @@ There are two main components in this module: ...@@ -23,8 +23,9 @@ There are two main components in this module:
""" """
from .height_field import * # noqa: F401, F403 from .height_field import * # noqa: F401, F403
from .terrain_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg, TerrainImporterCfg
from .terrain_generator import TerrainGenerator from .terrain_generator import TerrainGenerator
from .terrain_generator_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg
from .terrain_importer import TerrainImporter from .terrain_importer import TerrainImporter
from .terrain_importer_cfg import TerrainImporterCfg
from .trimesh import * # noqa: F401, F403 from .trimesh import * # noqa: F401, F403
from .utils import color_meshes_by_height, create_prim_from_mesh from .utils import color_meshes_by_height, create_prim_from_mesh
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import omni.isaac.orbit.terrains as terrain_gen import omni.isaac.orbit.terrains as terrain_gen
from ..terrain_cfg import TerrainGeneratorCfg from ..terrain_generator_cfg import TerrainGeneratorCfg
ROUGH_TERRAINS_CFG = TerrainGeneratorCfg( ROUGH_TERRAINS_CFG = TerrainGeneratorCfg(
size=(8.0, 8.0), size=(8.0, 8.0),
......
...@@ -15,7 +15,7 @@ from typing import TYPE_CHECKING ...@@ -15,7 +15,7 @@ from typing import TYPE_CHECKING
from .utils import height_field_to_mesh from .utils import height_field_to_mesh
if TYPE_CHECKING: if TYPE_CHECKING:
import omni.isaac.orbit.terrains.height_field.hf_terrains_cfg as hf_terrains_cfg from . import hf_terrains_cfg
@height_field_to_mesh @height_field_to_mesh
......
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
from dataclasses import MISSING from dataclasses import MISSING
from typing import Optional, Tuple from typing import Optional, Tuple
import omni.isaac.orbit.terrains.height_field.hf_terrains as hf_terrains
from omni.isaac.orbit.terrains.terrain_cfg import SubTerrainBaseCfg
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from ..terrain_generator_cfg import SubTerrainBaseCfg
from . import hf_terrains
@configclass @configclass
class HfTerrainBaseCfg(SubTerrainBaseCfg): class HfTerrainBaseCfg(SubTerrainBaseCfg):
......
...@@ -14,7 +14,7 @@ from omni.isaac.orbit.utils.io import dump_yaml ...@@ -14,7 +14,7 @@ from omni.isaac.orbit.utils.io import dump_yaml
from omni.isaac.orbit.utils.timer import Timer from omni.isaac.orbit.utils.timer import Timer
from .height_field import HfTerrainBaseCfg from .height_field import HfTerrainBaseCfg
from .terrain_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg from .terrain_generator_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg
from .trimesh.utils import make_border from .trimesh.utils import make_border
......
...@@ -18,7 +18,6 @@ import numpy as np ...@@ -18,7 +18,6 @@ import numpy as np
import trimesh import trimesh
from dataclasses import MISSING from dataclasses import MISSING
from typing import Callable from typing import Callable
from typing_extensions import Literal
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
...@@ -124,74 +123,3 @@ class TerrainGeneratorCfg: ...@@ -124,74 +123,3 @@ class TerrainGeneratorCfg:
cache_dir: str = "/tmp/orbit/terrains" cache_dir: str = "/tmp/orbit/terrains"
"""The directory where the terrain cache is stored. Defaults to "/tmp/orbit/terrains".""" """The directory where the terrain cache is stored. Defaults to "/tmp/orbit/terrains"."""
@configclass
class TerrainImporterCfg:
"""Configuration for the terrain manager."""
prim_path: str = MISSING
"""The absolute path of the USD terrain prim.
All sub-terrains are imported relative to this prim path.
"""
terrain_type: Literal["generator", "plane", "usd"] = "generator"
"""The type of terrain to generate. Defaults to "generator".
Available options are "plane", "usd", and "generator".
"""
terrain_generator: TerrainGeneratorCfg | None = None
"""The terrain generator configuration.
Only used if ``terrain_type`` is set to "generator".
"""
usd_path: str | None = None
"""The path to the USD file containing the terrain.
Only used if ``terrain_type`` is set to "usd".
"""
color: tuple[float, float, float] | None = (0.065, 0.0725, 0.080)
"""The color of the terrain. Defaults to (0.065, 0.0725, 0.080).
If :obj:`None`, no color is applied to the prim.
"""
static_friction: float = 1.0
"""The static friction coefficient of the terrain. Defaults to 1.0."""
dynamic_friction: float = 1.0
"""The dynamic friction coefficient of the terrain. Defaults to 1.0."""
restitution: float = 0.0
"""The restitution coefficient of the terrain. Defaults to 0.0."""
improve_patch_friction: bool = False
"""Whether to enable patch friction. Defaults to False."""
combine_mode: str = "average"
"""Determines the way physics materials will be combined during collisions. Defaults to `average`.
Available options are `average`, `min`, `multiply`, `multiply`, and `max`.
"""
env_spacing: float = 3.0
"""The spacing between environment origins when defined in a grid. Defaults to 3.0.
Note:
This parameter is used only when no sub-terrain origins are defined.
"""
max_init_terrain_level: int | None = None
"""The maximum initial terrain level for defining environment origins. Defaults to None.
The terrain levels are specified by the number of rows in the grid arrangement of
sub-terrains. If :obj:`None`, then the initial terrain level is set to the maximum
terrain level available (``num_rows - 1``).
Note:
This parameter is used only when sub-terrain origins are defined.
"""
...@@ -3,14 +3,16 @@ ...@@ -3,14 +3,16 @@
# #
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import numpy as np import numpy as np
import torch import torch
import trimesh import trimesh
from typing import Dict, Optional, Tuple from typing import TYPE_CHECKING
import omni.isaac.core.utils.prims as prim_utils import omni.isaac.core.utils.prims as prim_utils
import warp import warp
from omni.isaac.core.simulation_context import SimulationContext
from pxr import UsdGeom from pxr import UsdGeom
from omni.isaac.orbit.markers import VisualizationMarkers from omni.isaac.orbit.markers import VisualizationMarkers
...@@ -18,11 +20,13 @@ from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG ...@@ -18,11 +20,13 @@ from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG
from omni.isaac.orbit.utils.kit import create_ground_plane from omni.isaac.orbit.utils.kit import create_ground_plane
from omni.isaac.orbit.utils.warp import convert_to_warp_mesh from omni.isaac.orbit.utils.warp import convert_to_warp_mesh
from .terrain_cfg import TerrainImporterCfg
from .terrain_generator import TerrainGenerator from .terrain_generator import TerrainGenerator
from .trimesh.utils import make_plane from .trimesh.utils import make_plane
from .utils import create_prim_from_mesh from .utils import create_prim_from_mesh
if TYPE_CHECKING:
from .terrain_importer_cfg import TerrainImporterCfg
class TerrainImporter: class TerrainImporter:
r"""A class to handle terrain meshes and import them into the simulator. r"""A class to handle terrain meshes and import them into the simulator.
...@@ -41,39 +45,39 @@ class TerrainImporter: ...@@ -41,39 +45,39 @@ class TerrainImporter:
curriculum. For example, in a game, the player starts with easy levels and progresses to harder levels. curriculum. For example, in a game, the player starts with easy levels and progresses to harder levels.
""" """
meshes: Dict[str, trimesh.Trimesh] meshes: dict[str, trimesh.Trimesh]
"""A dictionary containing the names of the meshes and their keys.""" """A dictionary containing the names of the meshes and their keys."""
warp_meshes: Dict[str, warp.Mesh] warp_meshes: dict[str, warp.Mesh]
"""A dictionary containing the names of the warp meshes and their keys.""" """A dictionary containing the names of the warp meshes and their keys."""
terrain_origins: Optional[torch.Tensor] terrain_origins: torch.Tensor | None
"""The origins of the sub-terrains in the added terrain mesh. Shape is (num_rows, num_cols, 3). """The origins of the sub-terrains in the added terrain mesh. Shape is (num_rows, num_cols, 3).
If :obj:`None`, then it is assumed no sub-terrains exist. The environment origins are computed in a grid. If :obj:`None`, then it is assumed no sub-terrains exist. The environment origins are computed in a grid.
""" """
env_origins: torch.Tensor env_origins: torch.Tensor
"""The origins of the environment instances. Shape is (num_envs, 3).""" """The origins of the environments. Shape is (num_envs, 3)."""
def __init__(self, cfg: TerrainImporterCfg, num_envs: int, device: str): def __init__(self, cfg: TerrainImporterCfg):
"""Initialize the terrain importer. """Initialize the terrain importer.
Args: Args:
cfg (TerrainImporterCfg): The configuration for the terrain importer. cfg (TerrainImporterCfg): The configuration for the terrain importer.
num_envs (int): The number of environment origins to configure.
device (str, optional): The device to use.
Raises: Raises:
ValueError: If input terrain type is not supported. ValueError: If input terrain type is not supported.
ValueError: If terrain type is 'generator' and no configuration provided for ``terrain_generator``. ValueError: If terrain type is 'generator' and no configuration provided for ``terrain_generator``.
ValueError: If terrain type is 'usd' and no configuration provided for ``usd_path``. ValueError: If terrain type is 'usd' and no configuration provided for ``usd_path``.
ValueError: If terrain type is 'usd' or 'plane' and no configuration provided for ``env_spacing``.
""" """
# store inputs # store inputs
self.cfg = cfg self.cfg = cfg
self.device = device self.device = SimulationContext.instance().device
# create a dict of meshes # create a dict of meshes
self.meshes = dict() self.meshes = dict()
self.warp_meshes = dict() self.warp_meshes = dict()
self.env_origins = None self.env_origins = None
self.terrain_origins = None
# marker for visualization # marker for visualization
self.origin_visualizer = None self.origin_visualizer = None
...@@ -83,35 +87,42 @@ class TerrainImporter: ...@@ -83,35 +87,42 @@ class TerrainImporter:
raise ValueError("Input terrain type is 'generator' but no value provided for 'terrain_generator'.") raise ValueError("Input terrain type is 'generator' but no value provided for 'terrain_generator'.")
# generate the terrain # generate the terrain
terrain_generator = TerrainGenerator(cfg=self.cfg.terrain_generator) terrain_generator = TerrainGenerator(cfg=self.cfg.terrain_generator)
self.import_mesh(terrain_generator.terrain_mesh, key="terrain") self.import_mesh("terrain", terrain_generator.terrain_mesh)
# configure the terrain origins based on the terrain generator # configure the terrain origins based on the terrain generator
self.configure_env_origins(num_envs, terrain_generator.terrain_origins) self.configure_env_origins(terrain_generator.terrain_origins)
elif self.cfg.terrain_type == "usd": elif self.cfg.terrain_type == "usd":
# check if config is provided # check if config is provided
if self.cfg.usd_path is None: if self.cfg.usd_path is None:
raise ValueError("Input terrain type is 'usd' but no value provided for 'usd_path'.") raise ValueError("Input terrain type is 'usd' but no value provided for 'usd_path'.")
# import the terrain # import the terrain
self.import_usd(self.cfg.usd_path, key="terrain") self.import_usd("terrain", self.cfg.usd_path)
# configure the origins in a grid # configure the origins in a grid
self.configure_env_origins(num_envs) self.configure_env_origins()
elif self.cfg.terrain_type == "plane": elif self.cfg.terrain_type == "plane":
# load the plane # load the plane
self.import_ground_plane(key="terrain") self.import_ground_plane("terrain")
# configure the origins in a grid # configure the origins in a grid
self.configure_env_origins(num_envs) self.configure_env_origins()
else: else:
raise ValueError(f"Terrain type '{self.cfg.terrain_type}' not available.") raise ValueError(f"Terrain type '{self.cfg.terrain_type}' not available.")
def import_ground_plane(self, size: Tuple[int, int] = (2.0e6, 2.0e6), key: str = "terrain", **kwargs): """
Operations - Import.
"""
def import_ground_plane(self, key: str, size: tuple[int, int] = (2.0e6, 2.0e6), **kwargs):
"""Add a plane to the terrain importer. """Add a plane to the terrain importer.
Args: Args:
key (str): The key to store the mesh.
size (Tuple[int, int], optional): The size of the plane. Defaults to (2.0e6, 2.0e6). size (Tuple[int, int], optional): The size of the plane. Defaults to (2.0e6, 2.0e6).
key (str, optional): The key to store the mesh. Defaults to "terrain".
Raises: Raises:
ValueError: If a terrain with the same key already exists. ValueError: If a terrain with the same key already exists.
""" """
# check if key exists
if key in self.meshes:
raise ValueError(f"Mesh with key {key} already exists. Existing keys: {self.meshes.keys()}.")
# create a plane # create a plane
mesh = make_plane(size, height=0.0, center_zero=True) mesh = make_plane(size, height=0.0, center_zero=True)
# store the mesh # store the mesh
...@@ -134,21 +145,21 @@ class TerrainImporter: ...@@ -134,21 +145,21 @@ class TerrainImporter:
# import the grid mesh # import the grid mesh
create_ground_plane(self.cfg.prim_path, **mesh_props) create_ground_plane(self.cfg.prim_path, **mesh_props)
def import_mesh(self, mesh: trimesh.Trimesh, key: str = "terrain", **kwargs): def import_mesh(self, key: str, mesh: trimesh.Trimesh, **kwargs):
"""Import a mesh into the simulator. """Import a mesh into the simulator.
The mesh is imported into the simulator under the prim path ``cfg.prim_path/{key}``. The created path The mesh is imported into the simulator under the prim path ``cfg.prim_path/{key}``. The created path
contains the mesh as a :class:`pxr.UsdGeom` instance along with visual or physics material prims. contains the mesh as a :class:`pxr.UsdGeom` instance along with visual or physics material prims.
Args: Args:
key (str): The key to store the mesh.
mesh (trimesh.Trimesh): The mesh to import. mesh (trimesh.Trimesh): The mesh to import.
key (str, optional): The key to store the mesh. Defaults to "terrain".
**kwargs: The properties of the mesh. If not provided, the default properties are used. **kwargs: The properties of the mesh. If not provided, the default properties are used.
Raises: Raises:
ValueError: If a terrain with the same key already exists. ValueError: If a terrain with the same key already exists.
""" """
# add mesh to the dict # check if key exists
if key in self.meshes: if key in self.meshes:
raise ValueError(f"Mesh with key {key} already exists. Existing keys: {self.meshes.keys()}.") raise ValueError(f"Mesh with key {key} already exists. Existing keys: {self.meshes.keys()}.")
# store the mesh # store the mesh
...@@ -174,7 +185,7 @@ class TerrainImporter: ...@@ -174,7 +185,7 @@ class TerrainImporter:
# import the mesh # import the mesh
create_prim_from_mesh(mesh_prim_path, mesh.vertices, mesh.faces, **mesh_props) create_prim_from_mesh(mesh_prim_path, mesh.vertices, mesh.faces, **mesh_props)
def import_usd(self, usd_path: str, key: str = "terrain"): def import_usd(self, key: str, usd_path: str):
"""Import a mesh from a USD file. """Import a mesh from a USD file.
We assume that the USD file contains a single mesh. If the USD file contains multiple meshes, then We assume that the USD file contains a single mesh. If the USD file contains multiple meshes, then
...@@ -186,8 +197,8 @@ class TerrainImporter: ...@@ -186,8 +197,8 @@ class TerrainImporter:
be defined in the USD file. be defined in the USD file.
Args: Args:
key (str): The key to store the mesh.
usd_path (str): The path to the USD file. usd_path (str): The path to the USD file.
key (str, optional): The key to store the mesh. Defaults to "terrain".
Raises: Raises:
ValueError: If a terrain with the same key already exists. ValueError: If a terrain with the same key already exists.
...@@ -215,15 +226,18 @@ class TerrainImporter: ...@@ -215,15 +226,18 @@ class TerrainImporter:
device = "cuda" if "cuda" in self.device else "cpu" device = "cuda" if "cuda" in self.device else "cpu"
self.warp_meshes[key] = convert_to_warp_mesh(vertices, faces, device=device) self.warp_meshes[key] = convert_to_warp_mesh(vertices, faces, device=device)
def configure_env_origins(self, num_envs: int, origins: Optional[np.ndarray] = None): """
Operations - Origins.
"""
def configure_env_origins(self, origins: np.ndarray | None = None):
"""Configure the origins of the environments based on the added terrain. """Configure the origins of the environments based on the added terrain.
Args: Args:
num_envs (int): The number of environment origins to define.
origins (Optional[np.ndarray]): The origins of the sub-terrains. Shape: (num_rows, num_cols, 3). origins (Optional[np.ndarray]): The origins of the sub-terrains. Shape: (num_rows, num_cols, 3).
""" """
# create markers for the origins # create markers for the origins
markers = VisualizationMarkers(f"{self.cfg.prim_path}/originMarkers", cfg=FRAME_MARKER_CFG) markers = VisualizationMarkers("/Visuals/TerrainOrigin", cfg=FRAME_MARKER_CFG)
# decide whether to compute origins in a grid or based on curriculum # decide whether to compute origins in a grid or based on curriculum
if origins is not None: if origins is not None:
# convert to numpy # convert to numpy
...@@ -232,13 +246,16 @@ class TerrainImporter: ...@@ -232,13 +246,16 @@ class TerrainImporter:
# store the origins # store the origins
self.terrain_origins = origins.to(self.device, dtype=torch.float) self.terrain_origins = origins.to(self.device, dtype=torch.float)
# compute environment origins # compute environment origins
self.env_origins = self._compute_env_origins_curriculum(num_envs, self.terrain_origins) self.env_origins = self._compute_env_origins_curriculum(self.cfg.num_envs, self.terrain_origins)
# put markers on the sub-terrain origins # put markers on the sub-terrain origins
markers.visualize(self.terrain_origins.reshape(-1, 3)) markers.visualize(self.terrain_origins.reshape(-1, 3))
else: else:
self.terrain_origins = None self.terrain_origins = None
# check if env spacing is valid
if self.cfg.env_spacing is None:
raise ValueError("Environment spacing must be specified for configuring grid-like origins.")
# compute environment origins # compute environment origins
self.env_origins = self._compute_env_origins_grid(num_envs, self.cfg.env_spacing) self.env_origins = self._compute_env_origins_grid(self.cfg.num_envs, self.cfg.env_spacing)
# put markers on the grid origins # put markers on the grid origins
markers.visualize(self.env_origins.reshape(-1, 3)) markers.visualize(self.env_origins.reshape(-1, 3))
......
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES, ETH Zurich, and University of Toronto
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from dataclasses import MISSING
from typing import TYPE_CHECKING
from typing_extensions import Literal
from omni.isaac.orbit.utils import configclass
from .terrain_importer import TerrainImporter
if TYPE_CHECKING:
from .terrain_generator_cfg import TerrainGeneratorCfg
@configclass
class TerrainImporterCfg:
"""Configuration for the terrain manager."""
cls_name: type = TerrainImporter
"""The class name of the terrain importer."""
prim_path: str = MISSING
"""The absolute path of the USD terrain prim.
All sub-terrains are imported relative to this prim path.
"""
num_envs: int = MISSING
"""The number of environment origins to consider."""
terrain_type: Literal["generator", "plane", "usd"] = "generator"
"""The type of terrain to generate. Defaults to "generator".
Available options are "plane", "usd", and "generator".
"""
terrain_generator: TerrainGeneratorCfg | None = None
"""The terrain generator configuration.
Only used if ``terrain_type`` is set to "generator".
"""
usd_path: str | None = None
"""The path to the USD file containing the terrain.
Only used if ``terrain_type`` is set to "usd".
"""
env_spacing: float | None = None
"""The spacing between environment origins when defined in a grid. Defaults to None.
Note:
This parameter is used only when the ``terrain_type`` is ``"plane"`` or ``"usd"``.
"""
color: tuple[float, float, float] | None = (0.065, 0.0725, 0.080)
"""The color of the terrain. Defaults to (0.065, 0.0725, 0.080).
If :obj:`None`, no color is applied to the prim.
"""
static_friction: float = 1.0
"""The static friction coefficient of the terrain. Defaults to 1.0."""
dynamic_friction: float = 1.0
"""The dynamic friction coefficient of the terrain. Defaults to 1.0."""
restitution: float = 0.0
"""The restitution coefficient of the terrain. Defaults to 0.0."""
improve_patch_friction: bool = False
"""Whether to enable patch friction. Defaults to False."""
combine_mode: str = "average"
"""Determines the way physics materials will be combined during collisions. Defaults to `average`.
Available options are `average`, `min`, `multiply`, `multiply`, and `max`.
"""
max_init_terrain_level: int | None = None
"""The maximum initial terrain level for defining environment origins. Defaults to None.
The terrain levels are specified by the number of rows in the grid arrangement of
sub-terrains. If :obj:`None`, then the initial terrain level is set to the maximum
terrain level available (``num_rows - 1``).
Note:
This parameter is used only when sub-terrain origins are defined.
"""
...@@ -8,9 +8,10 @@ from typing import Tuple, Union ...@@ -8,9 +8,10 @@ from typing import Tuple, Union
import omni.isaac.orbit.terrains.trimesh.mesh_terrains as mesh_terrains import omni.isaac.orbit.terrains.trimesh.mesh_terrains as mesh_terrains
import omni.isaac.orbit.terrains.trimesh.utils as mesh_utils_terrains import omni.isaac.orbit.terrains.trimesh.utils as mesh_utils_terrains
from omni.isaac.orbit.terrains.terrain_cfg import SubTerrainBaseCfg
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from ..terrain_generator_cfg import SubTerrainBaseCfg
""" """
Different trimesh terrain configurations. Different trimesh terrain configurations.
""" """
......
...@@ -96,13 +96,15 @@ def main(terrain_type: str): ...@@ -96,13 +96,15 @@ def main(terrain_type: str):
# Handler for terrains importing # Handler for terrains importing
terrain_importer_cfg = terrain_gen.TerrainImporterCfg( terrain_importer_cfg = terrain_gen.TerrainImporterCfg(
num_envs=2048,
env_spacing=3.0,
prim_path="/World/ground", prim_path="/World/ground",
max_init_terrain_level=None, max_init_terrain_level=None,
terrain_type=terrain_type, terrain_type=terrain_type,
terrain_generator=ROUGH_TERRAINS_CFG.replace(curriculum=True), terrain_generator=ROUGH_TERRAINS_CFG.replace(curriculum=True),
usd_path=f"{ISAAC_NUCLEUS_DIR}/Environments/Terrains/rough_plane.usd", usd_path=f"{ISAAC_NUCLEUS_DIR}/Environments/Terrains/rough_plane.usd",
) )
terrain_importer = TerrainImporter(terrain_importer_cfg, num_envs=num_balls, device=sim.device) terrain_importer = TerrainImporter(terrain_importer_cfg)
# Define the scene # Define the scene
# -- Light # -- Light
......
...@@ -110,6 +110,8 @@ class LocomotionEnv(IsaacEnv): ...@@ -110,6 +110,8 @@ class LocomotionEnv(IsaacEnv):
# terrain # terrain
self.cfg.terrain.prim_path = "/World/ground" self.cfg.terrain.prim_path = "/World/ground"
self.cfg.terrain.num_envs = self.cfg.env.num_envs
self.cfg.terrain.env_spacing = self.cfg.env.env_spacing
# check if curriculum is enabled # check if curriculum is enabled
if self.cfg.terrain.terrain_type == "generator": if self.cfg.terrain.terrain_type == "generator":
if hasattr(self.cfg.curriculum, "terrain_levels") and self.cfg.curriculum.terrain_levels is not None: if hasattr(self.cfg.curriculum, "terrain_levels") and self.cfg.curriculum.terrain_levels is not None:
...@@ -117,7 +119,7 @@ class LocomotionEnv(IsaacEnv): ...@@ -117,7 +119,7 @@ class LocomotionEnv(IsaacEnv):
else: else:
self.cfg.terrain.terrain_generator.curriculum = False self.cfg.terrain.terrain_generator.curriculum = False
# self.cfg.terrain.max_init_terrain_level = None # self.cfg.terrain.max_init_terrain_level = None
self.terrain_importer = TerrainImporter(self.cfg.terrain, self.num_envs, device=self.device) self.terrain_importer = TerrainImporter(self.cfg.terrain)
# robot # robot
self.robot.spawn(self.template_env_ns + "/Robot") self.robot.spawn(self.template_env_ns + "/Robot")
......
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