Unverified Commit 0fd5e134 authored by Mayank Mittal's avatar Mayank Mittal Committed by GitHub

Adds additional parameters and utility functions to Orbit's SimulationContext class (#115)

# Description

* Added new parameters to the `SimulationContext` for setting other
quantities that can be set using the `PhyxSceneAPI`
* Added compatibility check to support flatcache/fabric naming in Isaac
Sim 2022.2 and 2023.1 versions

## Type of change

- Bug fix (non-breaking change which fixes an issue)
- This change requires a documentation update

## 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
- [ ] 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

---------
Signed-off-by: 's avatarMayank Mittal <12863862+Mayankm96@users.noreply.github.com>
Co-authored-by: 's avatarPascal Roth <57946385+pascal-roth@users.noreply.github.com>
Co-authored-by: 's avatarjsmith-bdai <142246516+jsmith-bdai@users.noreply.github.com>
parent af9bc561
[package]
# Note: Semantic Versioning is used: https://semver.org/
version = "0.8.11"
version = "0.8.12"
# Description
title = "ORBIT framework for Robot Learning"
......
Changelog
---------
0.8.11 (2023-08-18)
0.8.12 (2023-08-18)
~~~~~~~~~~~~~~~~~~
Added
^^^^^
* Added other properties provided by ``PhysicsScene`` to the :class:`omni.isaac.orbit.sim.SimulationContext`
class to allow setting CCD, solver iterations, etc.
* Added commonly used functions to the :class:`SimulationContext` class itself to avoid having additional
imports from Isaac Sim when doing simple tasks such as setting camera view or retrieving the simulation settings.
Fixed
^^^^^
* Switched the notations of default buffer values in :class:`omni.isaac.orbit.sim.PhysxCfg` from multiplication
to scientific notation to avoid confusion with the values.
0.8.11 (2023-08-18)
~~~~~~~~~~~~~~~~~~~
Added
^^^^^
* Adds utility functions and configuration objects in the :mod:`omni.isaac.orbit.sim.spawners`
to create the following prims in the scene:
......
......@@ -10,13 +10,12 @@ configuring the environment instances, viewer settings, and simulation parameter
"""
from typing import Tuple
from typing_extensions import Literal
from omni.isaac.orbit.utils import configclass
from .spawners.materials import RigidBodyMaterialCfg
__all__ = ["PhysxCfg", "SimulationCfg"]
@configclass
class PhysxCfg:
......@@ -42,7 +41,7 @@ class PhysxCfg:
shape and body management, and constrained solver.
"""
solver_type: int = 1
solver_type: Literal[0, 1] = 1
"""The type of solver to use.Default is 1 (TGS).
Available solvers:
......@@ -51,6 +50,66 @@ class PhysxCfg:
* :obj:`1`: TGS (Truncated Gauss-Seidel)
"""
min_position_iteration_count: int = 1
"""Minimum number of solver position iterations (rigid bodies, cloth, particles etc.). Default is 1.
.. note::
Each physics actor in Omniverse specifies its own solver iteration count. The solver takes
the number of iterations specified by the actor with the highest iteration and clamps it to
the range ``[min_position_iteration_count, max_position_iteration_count]``.
.. versionchanged:: 2022.2
In Isaac Sim 2022.2.0, this parameter is used for setting both position and velocity iterations count.
"""
max_position_iteration_count: int = 255
"""Maximum number of solver position iterations (rigid bodies, cloth, particles etc.). Default is 255.
.. note::
Each physics actor in Omniverse specifies its own solver iteration count. The solver takes
the number of iterations specified by the actor with the highest iteration and clamps it to
the range ``[min_position_iteration_count, max_position_iteration_count]``.
.. versionchanged:: 2022.2
In Isaac Sim 2022.2.0, this parameter is used for setting both position and velocity iterations count.
"""
min_velocity_iteration_count: int = 0
"""Minimum number of solver position iterations (rigid bodies, cloth, particles etc.). Default is 0.
.. note::
Each physics actor in Omniverse specifies its own solver iteration count. The solver takes
the number of iterations specified by the actor with the highest iteration and clamps it to
the range ``[min_velocity_iteration_count, max_velocity_iteration_count]``.
.. versionadded:: 2023.1
This parameter is introduced in 2023.1.0. For older versions, please use :obj:`min_position_iteration_count`.
"""
max_velocity_iteration_count: int = 255
"""Maximum number of solver position iterations (rigid bodies, cloth, particles etc.). Default is 255.
.. note::
Each physics actor in Omniverse specifies its own solver iteration count. The solver takes
the number of iterations specified by the actor with the highest iteration and clamps it to
the range ``[min_velocity_iteration_count, max_velocity_iteration_count]``.
.. versionadded:: 2023.1
This parameter is introduced in 2023.1.0. For older versions, please use :obj:`max_position_iteration_count`.
"""
enable_ccd: bool = False
"""Enable a second broad-phase pass that makes it possible to prevent objects from tunneling through each other.
Default is False."""
enable_stabilization: bool = True
"""Enable/disable additional stabilization pass in solver. Default is True."""
......@@ -63,33 +122,36 @@ class PhysxCfg:
friction_correlation_distance: float = 0.025
"""Distance threshold for merging contacts into a single friction anchor point (in m). Default is 0.025 m."""
gpu_max_rigid_contact_count: int = 1024 * 1024
"""Size of rigid contact stream buffer allocated in pinned host memory. Default is 2 ** 20."""
gpu_max_rigid_contact_count: int = 2**23
"""Size of rigid contact stream buffer allocated in pinned host memory. Default is 2 ** 23."""
gpu_max_rigid_patch_count: int = 80 * 1024 * 2
"""Size of the rigid contact patch stream buffer allocated in pinned host memory. Default is 80 * 2 ** 11."""
gpu_max_rigid_patch_count: int = 5 * 2**15
"""Size of the rigid contact patch stream buffer allocated in pinned host memory. Default is 5 * 2 ** 15."""
gpu_found_lost_pairs_capacity: int = 1024 * 1024 * 2
gpu_found_lost_pairs_capacity: int = 2**21
"""Capacity of found and lost buffers allocated in GPU global memory. Default is 2 ** 21.
This is used for the found/lost pair reports in the BP.
"""
gpu_found_lost_aggregate_pairs_capacity: int = 1024 * 1024 * 32
gpu_found_lost_aggregate_pairs_capacity: int = 2**25
"""Capacity of found and lost buffers in aggregate system allocated in GPU global memory.
Default is 2 ** 21.
Default is 2 ** 25.
This is used for the found/lost pair reports in AABB manager.
"""
gpu_total_aggregate_pairs_capacity: int = 1024 * 1024 * 2
gpu_total_aggregate_pairs_capacity: int = 2**21
"""Capacity of total number of aggregate pairs allocated in GPU global memory. Default is 2 ** 21."""
gpu_heap_capacity: int = 64 * 1024 * 1024
gpu_collision_stack_size: int = 2**26
"""Size of the collision stack buffer allocated in pinned host memory. Default is 2 ** 26."""
gpu_heap_capacity: int = 2**26
"""Initial capacity of the GPU and pinned host memory heaps. Additional memory will be allocated
if more memory is required. Default is 2 ** 26."""
gpu_temp_buffer_capacity: int = 16 * 1024 * 1024
gpu_temp_buffer_capacity: int = 2**24
"""Capacity of temp buffer allocated in pinned host memory. Default is 2 ** 24."""
gpu_max_num_partitions: int = 8
......@@ -98,10 +160,10 @@ class PhysxCfg:
This variable must be power of 2. A value greater than 32 is currently not supported. Range: (1, 32)
"""
gpu_max_soft_body_contacts: int = 1024 * 1024
gpu_max_soft_body_contacts: int = 2**20
"""Size of soft body contacts stream buffer allocated in pinned host memory. Default is 2 ** 20."""
gpu_max_particle_contacts: int = 1024 * 1024
gpu_max_particle_contacts: int = 2**20
"""Size of particle contacts stream buffer allocated in pinned host memory. Default is 2 ** 20."""
......@@ -136,7 +198,7 @@ class SimulationCfg:
with the GUI enabled. This is to allow certain GUI features to work properly.
"""
use_flatcache: bool = True
use_fabric: bool = True
"""Enable/disable reading of physics buffers directly. Default is True.
When running the simulation, updates in the states in the scene is normally synchronized with USD.
......@@ -149,6 +211,18 @@ class SimulationCfg:
Note:
When enabled, the GUI will not update the physics parameters in real-time. To enable real-time
updates, please set this flag to :obj:`False`.
.. versionadded:: 2023.1
This flag is introduced in 2023.1.0. For older versions, please use :obj:`use_flatcache` instead.
"""
use_flatcache: bool = True
"""Enable/disable reading of physics buffers directly. Default is True.
.. deprecated:: 2023.1
This flag is deprecated and will be removed in the future. Please use :obj:`use_fabric` instead.
"""
disable_contact_processing: bool = False
......
......@@ -3,10 +3,18 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import numpy as np
from typing import Any
import carb
import omni.isaac.core.utils.stage as stage_utils
import omni.physx
from omni.isaac.core.simulation_context import SimulationContext as _SimulationContext
from omni.isaac.core.utils.viewports import set_camera_view
from omni.isaac.version import get_version
from pxr import Gf, Usd
from .simulation_cfg import SimulationCfg
from .utils import bind_physics_material
......@@ -15,15 +23,51 @@ from .utils import bind_physics_material
class SimulationContext(_SimulationContext):
"""A class to control simulation-related events such as physics stepping and rendering.
It wraps the ``SimulationContext`` class from ``omni.isaac.core`` and adds some additional
functionality such as setting up the simulation context with a configuration object.
The simulation context helps control various simulation aspects. This includes:
* configure the simulator with different settings such as the physics timestep, the number of physics substeps,
and the physics solver parameters (for more information, see :class:`omni.isaac.orbit.sim.SimulationCfg`)
* playing, pausing, stepping and stopping the simulation
* adding and removing callbacks to different simulation events such as physics stepping, rendering, etc.
This class inherits from the `omni.isaac.core.simulation_context.SimulationContext`_ class and
adds additional functionalities such as setting up the simulation context with a configuration object,
exposing other commonly used simulator-related functions, and performing version checks of Isaac Sim
to ensure compatibility between releases.
The simulation context is a singleton object. This means that there can only be one instance
of the simulation context at any given time. This is enforced by the parent class. Therefore, it is
not possible to create multiple instances of the simulation context. Instead, the simulation context
can be accessed using the ``instance()`` method.
.. attention::
Since we only support the ``torch <https://pytorch.org/>``_ backend for simulation, the
simulation context is configured to use the ``torch`` backend by default. This means that
all the data structures used in the simulation are ``torch.Tensor`` objects.
The simulation context can be used in two different modes of operations:
1. **Standalone python script**: In this mode, the user has full control over the simulation and
can trigger stepping events synchronously (i.e. as a blocking call). In this case the user
has to manually call :meth:`step` step the physics simulation and :meth:`render` to
render the scene.
2. **Omniverse extension**: In this mode, the user has limited control over the simulation stepping
and all the simulation events are triggered asynchronously (i.e. as a non-blocking call). In this
case, the user can only trigger the simulation to start, pause, and stop. The simulation takes
care of stepping the physics simulation and rendering the scene.
Based on above, for most functions in this class there is an equivalent function that is suffixed
with ``_async``. The ``_async`` functions are used in the Omniverse extension mode and
the non-``_async`` functions are used in the standalone python script mode.
.. _omni.isaac.core.simulation_context.SimulationContext: https://docs.omniverse.nvidia.com/py/isaacsim/source/extensions/omni.isaac.core/docs/index.html#module-omni.isaac.core.simulation_context
"""
def __init__(self, cfg: SimulationCfg = None):
def __init__(self, cfg: SimulationCfg | None = None):
"""Creates a simulation context to control the simulator.
Args:
cfg (SimulationCfg, optional): The configuration of the simulation. Defaults to None,
cfg (SimulationCfg | None, optional): The configuration of the simulation. Defaults to None,
in which case the default configuration is used.
"""
# store input
......@@ -55,9 +99,14 @@ class SimulationContext(_SimulationContext):
# this is needed for some GUI features
if not self._is_headless:
self.cfg.enable_scene_query_support = True
# set up flatcache interface (default is None)
# set up flatcache/fabric interface (default is None)
# this is needed to flush the flatcache data into Hydra manually when calling `render()`
# ref: https://docs.omniverse.nvidia.com/prod_extensions/prod_extensions/ext_physics.html
# note: need to do this here because super().__init__ calls render and this variable is needed
self._flatcache_iface = None
self._fabric_iface = None
# read isaac sim version (this includes build tag, release tag etc.)
# note: we do it once here because it reads the VERSION file from disk and is not expected to change.
self._isaacsim_version = get_version()
# flatten out the simulation dictionary
sim_params = self.cfg.to_dict()
......@@ -75,25 +124,86 @@ class SimulationContext(_SimulationContext):
physics_prim_path=self.cfg.physics_prim_path,
device=self.cfg.device,
)
# create the default physics material
# this material is used when no material is specified for a primitive
# check: https://docs.omniverse.nvidia.com/extensions/latest/ext_physics/simulation-control/physics-settings.html#physics-materials
material_path = f"{self.cfg.physics_prim_path}/defaultMaterial"
self.cfg.physics_material.func(material_path, self.cfg.physics_material)
# bind the physics material to the scene
bind_physics_material(self.cfg.physics_prim_path, material_path)
# check if flatcache is enabled
# this is needed to flush the flatcache data into Hydra manually when calling `render()`
# ref: https://docs.omniverse.nvidia.com/prod_extensions/prod_extensions/ext_physics.html
if self.cfg.use_flatcache:
from omni.physxflatcache import get_physx_flatcache_interface
"""
Operations - New.
"""
# acquire flatcache interface
self._flatcache_iface = get_physx_flatcache_interface()
def is_headless(self) -> bool:
"""Returns whether the simulation is running in headless mode.
Note:
Headless mode is enabled when the simulator is running without a GUI.
"""
return self._is_headless
def get_version(self) -> tuple[int, int, int]:
"""Returns the version of the simulator.
This is a wrapper around the ``omni.isaac.version.get_version()`` function.
The returned tuple contains the following information:
* Major version (int): This is the year of the release (e.g. 2022).
* Minor version (int): This is the half-year of the release (e.g. 1 or 2).
* Patch version (int): This is the patch number of the release (e.g. 0).
"""
return int(self._isaacsim_version[2]), int(self._isaacsim_version[3]), int(self._isaacsim_version[4])
"""
Operations - New utilities.
"""
@staticmethod
def set_camera_view(
eye: tuple[float, float, float],
target: tuple[float, float, float],
camera_prim_path: str = "/OmniverseKit_Persp",
):
"""Set the location and target of the viewport camera in the stage.
Note:
This is a wrapper around the :math:`omni.isaac.core.utils.viewports.set_camera_view` function.
It is provided here for convenience to reduce the amount of imports needed.
Args:
eye (tuple[float, float, float]): The location of the camera eye.
target (tuple[float, float, float]): The location of the camera target.
camera_prim_path (str, optional): The path to the camera primitive in the stage. Defaults to
"/OmniverseKit_Persp".
"""
set_camera_view(eye, target, camera_prim_path)
def set_setting(self, name: str, value: Any):
"""Set simulation settings using the Carbonite SDK.
.. note::
If the input setting name does not exist, it will be created. If it does exist, the value will be
overwritten. Please make sure to use the correct setting name.
To understand the settings interface, please refer to the
`Carbonite SDK <https://docs.omniverse.nvidia.com/dev-guide/latest/programmer_ref/settings.html>`_
documentation.
Args:
name (str): The name of the setting.
value (Any): The value of the setting.
"""
self._settings.set(name, value)
def get_setting(self, name: str) -> Any:
"""Read the simulation setting using the Carbonite SDK.
Args:
name (str): The name of the setting.
Returns:
Any: The value of the setting.
"""
return self._settings.get(name)
"""
Operations - Override.
Operations - Override (standalone)
"""
def reset(self, soft: bool = False):
......@@ -118,19 +228,110 @@ class SimulationContext(_SimulationContext):
flush (bool, optional): Whether to flush the flatcache data to update Hydra textures.
"""
# manually flush the flatcache data to update Hydra textures
if self._flatcache_iface is not None and flush:
self._flatcache_iface.update(0.0, 0.0)
if self._fabric_iface is not None and flush:
self._fabric_iface.update(0.0, 0.0)
# render the simulation
super().render()
"""
Operations - New.
Operations - Override (extension)
"""
def is_headless(self) -> bool:
"""Returns whether the simulation is running in headless mode.
async def reset_async(self, soft: bool = False):
# need to load all "physics" information from the USD file
if not soft:
omni.physx.acquire_physx_interface().force_load_physics_from_usd()
# play the simulation
await super().reset_async(soft=soft)
Note:
Headless mode is enabled when the simulator is running without a GUI.
"""
return self._is_headless
Initialization - Override.
"""
def _init_stage(self, *args, **kwargs) -> Usd.Stage:
_ = super()._init_stage(*args, **kwargs)
# set additional physx parameters and bind material
self._set_additional_physx_params()
# load flatcache/fabric interface
self._load_fabric_interface()
# return the stage
return self.stage
async def _initialize_stage_async(self, *args, **kwargs) -> Usd.Stage:
await super()._initialize_stage_async(*args, **kwargs)
# set additional physx parameters and bind material
self._set_additional_physx_params()
# load flatcache/fabric interface
self._load_fabric_interface()
# return the stage
return self.stage
"""
Helper Functions
"""
def _set_additional_physx_params(self):
"""Sets additional PhysX parameters that are not directly supported by the parent class."""
# obtain the physics scene api
physics_scene = self._physics_context._physics_scene # pyright: ignore [reportPrivateUsage]
physx_scene_api = self._physics_context._physx_scene_api # pyright: ignore [reportPrivateUsage]
# assert that scene api is not None
if physx_scene_api is None:
raise RuntimeError("Physics scene API is None! Please create the scene first.")
# set parameters not directly supported by the constructor
# -- Continuous Collision Detection (CCD)
# ref: https://nvidia-omniverse.github.io/PhysX/physx/5.2.1/docs/AdvancedCollisionDetection.html?highlight=ccd#continuous-collision-detection
self._physics_context.enable_ccd(self.cfg.physx.enable_ccd)
# -- GPU collision stack size
physx_scene_api.CreateGpuCollisionStackSizeAttr(self.cfg.physx.gpu_collision_stack_size)
# -- Gravity
# note: Isaac sim only takes the "up-axis" as the gravity direction. But physics allows any direction so we
# need to convert the gravity vector to a direction and magnitude pair explicitly.
gravity = np.asarray(self.cfg.gravity)
gravity_magnitude = np.linalg.norm(gravity)
gravity_direction = gravity / gravity_magnitude
physics_scene.CreateGravityDirectionAttr(Gf.Vec3f(*gravity_direction))
physics_scene.CreateGravityMagnitudeAttr(gravity_magnitude)
# simulation iteration count
if self.get_version()[0] == 2022:
# position and velocity iteration counts
physx_scene_api.CreateMinIterationCountAttr(self.cfg.physx.min_position_iteration_count)
physx_scene_api.CreateMaxIterationCountAttr(self.cfg.physx.max_position_iteration_count)
else:
# position iteration count
physx_scene_api.CreateMinPositionIterationCountsAttr(self.cfg.physx.min_position_iteration_count)
physx_scene_api.CreateMaxPositionIterationCountsAttr(self.cfg.physx.max_position_iteration_count)
# velocity iteration count
physx_scene_api.CreateMinVelocityIterationCountsAttr(self.cfg.physx.min_velocity_iteration_count)
physx_scene_api.CreateMaxVelocityIterationCountsAttr(self.cfg.physx.max_velocity_iteration_count)
# create the default physics material
# this material is used when no material is specified for a primitive
# check: https://docs.omniverse.nvidia.com/extensions/latest/ext_physics/simulation-control/physics-settings.html#physics-materials
material_path = f"{self.cfg.physics_prim_path}/defaultMaterial"
self.cfg.physics_material.func(material_path, self.cfg.physics_material)
# bind the physics material to the scene
bind_physics_material(self.cfg.physics_prim_path, material_path)
def _load_fabric_interface(self):
"""Loads the flatcache/fabric interface if enabled."""
# check isaac sim version
# note: flatcache is called fabric in isaac sim 2023.x
# in isaac sim 2022.x, we use physx-flatcache module
# in isaac sim 2023.x, we use physx-fabric module
if self.get_version()[0] == 2022:
# check if flatcache is enabled
if self.cfg.use_flatcache:
from omni.physxflatcache import get_physx_flatcache_interface
# acquire flatcache interface
self._fabric_iface = get_physx_flatcache_interface()
else:
# check if fabric is enabled
if self.cfg.use_fabric:
from omni.physxfabric import get_physx_fabric_interface
# acquire fabric interface
self._fabric_iface = get_physx_fabric_interface()
......@@ -143,7 +143,7 @@ def spawn_from_urdf(
return prim_utils.get_prim_at_path(prim_path)
def spawn_ground_plane(prim_path: str, cfg: from_files_cfg.GroundPlaneCfg, *kwargs) -> Usd.Prim:
def spawn_ground_plane(prim_path: str, cfg: from_files_cfg.GroundPlaneCfg, **kwargs) -> Usd.Prim:
"""Spawns a ground plane into the scene.
This function loads the USD file containing the grid plane asset from Isaac Sim. It may
......
......@@ -277,13 +277,15 @@ def bind_visual_material(
binding_strength = "weakerThanDescendants"
# obtain material binding API
# note: we prefer using the command here as it is more robust than the USD API
omni.kit.commands.execute(
success, _ = omni.kit.commands.execute(
"BindMaterialCommand",
prim_path=prim_path,
material_path=material_path,
strength=binding_strength,
stage=stage,
)
# return success
return success
@apply_nested
......@@ -293,7 +295,8 @@ def bind_physics_material(
"""Bind a physics material to a prim.
`Physics material`_ can be applied only to a prim with physics-enabled on them. This includes having
collision APIs, or deformable body APIs, or being a particle system.
collision APIs, or deformable body APIs, or being a particle system. In case the prim does not have
any of these APIs, the function will not apply the material and return False.
.. note::
The function is decorated with :meth:`apply_nested` to allow applying the function to a prim path
......@@ -311,7 +314,6 @@ def bind_physics_material(
Raises:
ValueError: If the provided prim paths do not exist on stage.
ValueError: When prim at specified path is not physics-enabled.
"""
# resolve stage
if stage is None:
......@@ -329,10 +331,11 @@ def bind_physics_material(
has_deformable_body = prim.HasAPI(PhysxSchema.PhysxDeformableBodyAPI)
has_particle_system = prim.IsA(PhysxSchema.PhysxParticleSystem)
if not (has_physics_scene_api or has_collider or has_deformable_body or has_particle_system):
raise ValueError(
carb.log_verbose(
f"Cannot apply physics material '{material_path}' on prim '{prim_path}'. It is neither a"
" PhysX scene, collider, a deformable body, nor a particle system."
)
return False
# obtain material binding API
if prim.HasAPI(UsdShade.MaterialBindingAPI):
......@@ -348,3 +351,5 @@ def bind_physics_material(
binding_strength = UsdShade.Tokens.weakerThanDescendants
# apply the material
material_binding_api.Bind(material, bindingStrength=binding_strength, materialPurpose="physics") # type: ignore
# return success
return True
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES, ETH Zurich, and University of Toronto
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""Launch Isaac Sim Simulator first."""
from omni.isaac.orbit.app import AppLauncher
# launch omniverse app
simulation_app = AppLauncher(headless=True).app
"""Rest everything follows."""
import numpy as np
import traceback
import unittest
import carb
import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.core.simulation_context import SimulationContext as IsaacSimulationContext
from omni.isaac.orbit.sim import SimulationCfg, SimulationContext
class TestSimulationContext(unittest.TestCase):
"""Test fixture for wrapper around simulation context."""
def setUp(self) -> None:
"""Create a blank new stage for each test."""
# Load kit helper
SimulationContext.clear_instance()
def test_singleton(self):
"""Tests that the singleton is working."""
sim1 = SimulationContext()
sim2 = SimulationContext()
sim3 = IsaacSimulationContext()
self.assertIs(sim1, sim2)
self.assertIs(sim1, sim3)
# try to delete the singleton
sim2.__del__()
self.assertTrue(sim1.instance() is None)
# create new instance
sim4 = SimulationContext()
self.assertIsNot(sim1, sim4)
self.assertIsNot(sim3, sim4)
self.assertIs(sim1.instance(), sim4.instance())
self.assertIs(sim3.instance(), sim4.instance())
# clear instance
sim3.clear_instance()
def test_initialization(self):
"""Test the simulation config."""
cfg = SimulationCfg(physics_prim_path="/Physics/PhysX", substeps=5, gravity=(0.0, -0.5, -0.5))
sim = SimulationContext(cfg)
# TODO: Figure out why keyword argument doesn't work.
# note: added a fix in Isaac Sim 2023.1 for this.
# sim = SimulationContext(cfg=cfg)
# check valid settings
self.assertEqual(sim.get_physics_dt(), cfg.dt)
self.assertEqual(sim.get_rendering_dt(), cfg.dt * cfg.substeps)
# check valid paths
self.assertTrue(prim_utils.is_prim_path_valid("/Physics/PhysX"))
self.assertTrue(prim_utils.is_prim_path_valid("/Physics/PhysX/defaultMaterial"))
# check valid gravity
gravity_dir, gravity_mag = sim.get_physics_context().get_gravity()
gravity = np.array(gravity_dir) * gravity_mag
np.testing.assert_almost_equal(gravity, cfg.gravity)
def test_sim_version(self):
"""Test obtaining the version."""
sim = SimulationContext()
version = sim.get_version()
self.assertTrue(len(version) > 0)
self.assertTrue(version[0] >= 2022)
def test_carb_setting(self):
"""Test setting carb settings."""
sim = SimulationContext()
# known carb setting
sim.set_setting("/physics/physxDispatcher", False)
self.assertEqual(sim.get_setting("/physics/physxDispatcher"), False)
# unknown carb setting
sim.set_setting("/myExt/using_omniverse_version", sim.get_version())
self.assertSequenceEqual(sim.get_setting("/myExt/using_omniverse_version"), sim.get_version())
if __name__ == "__main__":
try:
unittest.main()
except Exception as err:
carb.log_error(err)
carb.log_error(traceback.format_exc())
raise
finally:
# close sim app
simulation_app.close()
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