From a25b994cb4835dc156a5e3d8675b8e88c21b2408 Mon Sep 17 00:00:00 2001 From: Neeraj Cherakara <35414531+iamnambiar@users.noreply.github.com> Date: Mon, 16 Sep 2024 06:09:56 +0100 Subject: [PATCH 1/5] Fixes typo in the Environment ID of the unitree robots in the `environments.rst` file (#986) # Description The links to the environment IDs in `docs/environments.rst` for the Unitree Go1, A1, and Go2 (both rough and flat) were incorrect. I have fixed them by providing the correct links. ## Type of change - This change requires a documentation update ## Checklist - [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [ ] I have added my name to the `CONTRIBUTORS.md` or my name already exists there --- docs/source/features/environments.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/features/environments.rst b/docs/source/features/environments.rst index 7e9c142b63..ee083cded9 100644 --- a/docs/source/features/environments.rst +++ b/docs/source/features/environments.rst @@ -165,14 +165,14 @@ Environments based on legged locomotion tasks. .. |velocity-flat-anymal-d-link| replace:: `Isaac-Velocity-Flat-Anymal-D-v0 `__ .. |velocity-rough-anymal-d-link| replace:: `Isaac-Velocity-Rough-Anymal-D-v0 `__ -.. |velocity-flat-unitree-a1-link| replace:: `Isaac-Velocity-Flat-Unitree-A1-v0 `__ -.. |velocity-rough-unitree-a1-link| replace:: `Isaac-Velocity-Rough-Unitree-A1-v0 `__ +.. |velocity-flat-unitree-a1-link| replace:: `Isaac-Velocity-Flat-Unitree-A1-v0 `__ +.. |velocity-rough-unitree-a1-link| replace:: `Isaac-Velocity-Rough-Unitree-A1-v0 `__ -.. |velocity-flat-unitree-go1-link| replace:: `Isaac-Velocity-Flat-Unitree-Go1-v0 `__ -.. |velocity-rough-unitree-go1-link| replace:: `Isaac-Velocity-Rough-Unitree-Go1-v0 `__ +.. |velocity-flat-unitree-go1-link| replace:: `Isaac-Velocity-Flat-Unitree-Go1-v0 `__ +.. |velocity-rough-unitree-go1-link| replace:: `Isaac-Velocity-Rough-Unitree-Go1-v0 `__ -.. |velocity-flat-unitree-go2-link| replace:: `Isaac-Velocity-Flat-Unitree-Go2-v0 `__ -.. |velocity-rough-unitree-go2-link| replace:: `Isaac-Velocity-Rough-Unitree-Go2-v0 `__ +.. |velocity-flat-unitree-go2-link| replace:: `Isaac-Velocity-Flat-Unitree-Go2-v0 `__ +.. |velocity-rough-unitree-go2-link| replace:: `Isaac-Velocity-Rough-Unitree-Go2-v0 `__ .. |velocity-flat-spot-link| replace:: `Isaac-Velocity-Flat-Spot-v0 `__ From ac4751fe9b49f54c6d7d6d9c895e93a6d3fa79d9 Mon Sep 17 00:00:00 2001 From: Mayank Mittal <12863862+Mayankm96@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:30:21 +0200 Subject: [PATCH 2/5] Adds flag to recompute inertia when randomizing the mass of a rigid body (#989) # Description Previously, the method for randomizing masses of rigid bodies only set the masses. However, the inertia tensors were not automatically updated, and their original values were used inside the solver. This MR adds a flag to recompute the inertia when mass is randomized by assuming a uniform-density object. We make this an optional flag in case users want to handle inertia tensors explicitly on their own. ## Type of change - Bug fix (non-breaking change which fixes an issue) - 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 `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] 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 --- .../lab/assets/articulation/articulation.py | 1 + .../assets/articulation/articulation_data.py | 7 +++++ .../lab/assets/rigid_object/rigid_object.py | 1 + .../assets/rigid_object/rigid_object_data.py | 7 +++++ .../omni/isaac/lab/envs/mdp/events.py | 27 +++++++++++++++++++ .../test/assets/test_articulation.py | 24 +++++++++++++++++ .../test/assets/test_rigid_object.py | 2 ++ 7 files changed, 69 insertions(+) diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py index 350134222f..f3fc6e72dc 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation.py @@ -954,6 +954,7 @@ def _create_buffers(self): # -- bodies self._data.default_mass = self.root_physx_view.get_masses().clone() + self._data.default_inertia = self.root_physx_view.get_inertias().clone() # -- default joint state self._data.default_joint_pos = torch.zeros(self.num_instances, self.num_joints, device=self.device) diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation_data.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation_data.py index b738cd0c37..81fc5efbea 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation_data.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/articulation/articulation_data.py @@ -104,6 +104,13 @@ def update(self, dt: float): default_mass: torch.Tensor = None """Default mass read from the simulation. Shape is (num_instances, num_bodies).""" + default_inertia: torch.Tensor = None + """Default inertia read from the simulation. Shape is (num_instances, num_bodies, 9). + + The inertia is the inertia tensor relative to the center of mass frame. The values are stored in + the order :math:`[I_{xx}, I_{xy}, I_{xz}, I_{yx}, I_{yy}, I_{yz}, I_{zx}, I_{zy}, I_{zz}]`. + """ + default_joint_pos: torch.Tensor = None """Default joint positions of all joints. Shape is (num_instances, num_joints).""" diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object.py index f0b37703e5..328a3e76c6 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object.py @@ -327,6 +327,7 @@ def _create_buffers(self): # set information about rigid body into data self._data.body_names = self.body_names self._data.default_mass = self.root_physx_view.get_masses().clone() + self._data.default_inertia = self.root_physx_view.get_inertias().clone() def _process_cfg(self): """Post processing of configuration parameters.""" diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object_data.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object_data.py index c2c20382a0..63d7be943d 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object_data.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object_data.py @@ -96,6 +96,13 @@ def update(self, dt: float): default_mass: torch.Tensor = None """Default mass read from the simulation. Shape is (num_instances, 1).""" + default_inertia: torch.Tensor = None + """Default inertia tensor read from the simulation. Shape is (num_instances, 9). + + The inertia is the inertia tensor relative to the center of mass frame. The values are stored in + the order :math:`[I_{xx}, I_{xy}, I_{xz}, I_{yx}, I_{yy}, I_{yz}, I_{zx}, I_{zy}, I_{zz}]`. + """ + ## # Properties. ## diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/events.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/events.py index 437afd1255..a931498a83 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/events.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/events.py @@ -132,12 +132,18 @@ def randomize_rigid_body_mass( mass_distribution_params: tuple[float, float], operation: Literal["add", "scale", "abs"], distribution: Literal["uniform", "log_uniform", "gaussian"] = "uniform", + recompute_inertia: bool = True, ): """Randomize the mass of the bodies by adding, scaling, or setting random values. This function allows randomizing the mass of the bodies of the asset. The function samples random values from the given distribution parameters and adds, scales, or sets the values into the physics simulation based on the operation. + If the ``recompute_inertia`` flag is set to ``True``, the function recomputes the inertia tensor of the bodies + after setting the mass. This is useful when the mass is changed significantly, as the inertia tensor depends + on the mass. It assumes the body is a uniform density object. If the body is not a uniform density object, + the inertia tensor may not be accurate. + .. tip:: This function uses CPU tensors to assign the body masses. It is recommended to use this function only during the initialization of the environment. @@ -159,7 +165,10 @@ def randomize_rigid_body_mass( # get the current masses of the bodies (num_assets, num_bodies) masses = asset.root_physx_view.get_masses() + # apply randomization on default values + # this is to make sure when calling the function multiple times, the randomization is applied on the + # default values and not the previously randomized values masses[env_ids[:, None], body_ids] = asset.data.default_mass[env_ids[:, None], body_ids].clone() # sample from the given range @@ -172,6 +181,24 @@ def randomize_rigid_body_mass( # set the mass into the physics simulation asset.root_physx_view.set_masses(masses, env_ids) + # recompute inertia tensors if needed + if recompute_inertia: + # compute the ratios of the new masses to the initial masses + ratios = masses[env_ids[:, None], body_ids] / asset.data.default_mass[env_ids[:, None], body_ids] + # scale the inertia tensors by the the ratios + # since mass randomization is done on default values, we can use the default inertia tensors + inertias = asset.root_physx_view.get_inertias() + if isinstance(asset, Articulation): + # inertia has shape: (num_envs, num_bodies, 9) for articulation + inertias[env_ids[:, None], body_ids] = ( + asset.data.default_inertia[env_ids[:, None], body_ids] * ratios[..., None] + ) + else: + # inertia has shape: (num_envs, 9) for rigid object + inertias[env_ids] = asset.data.default_inertia[env_ids] * ratios + # set the inertia tensors into the physics simulation + asset.root_physx_view.set_inertias(inertias, env_ids) + def randomize_physics_scene_gravity( env: ManagerBasedEnv, diff --git a/source/extensions/omni.isaac.lab/test/assets/test_articulation.py b/source/extensions/omni.isaac.lab/test/assets/test_articulation.py index 5cd67dfa52..2fc0910ee9 100644 --- a/source/extensions/omni.isaac.lab/test/assets/test_articulation.py +++ b/source/extensions/omni.isaac.lab/test/assets/test_articulation.py @@ -199,6 +199,12 @@ def test_initialization_floating_base(self): self.assertEqual(articulation.data.root_pos_w.shape, (num_articulations, 3)) self.assertEqual(articulation.data.root_quat_w.shape, (num_articulations, 4)) self.assertEqual(articulation.data.joint_pos.shape, (num_articulations, 12)) + self.assertEqual( + articulation.data.default_mass.shape, (num_articulations, articulation.num_bodies) + ) + self.assertEqual( + articulation.data.default_inertia.shape, (num_articulations, articulation.num_bodies, 9) + ) # Check some internal physx data for debugging # -- joint related @@ -246,6 +252,12 @@ def test_initialization_fixed_base(self): self.assertEqual(articulation.data.root_pos_w.shape, (num_articulations, 3)) self.assertEqual(articulation.data.root_quat_w.shape, (num_articulations, 4)) self.assertEqual(articulation.data.joint_pos.shape, (num_articulations, 9)) + self.assertEqual( + articulation.data.default_mass.shape, (num_articulations, articulation.num_bodies) + ) + self.assertEqual( + articulation.data.default_inertia.shape, (num_articulations, articulation.num_bodies, 9) + ) # Check some internal physx data for debugging # -- joint related @@ -299,6 +311,12 @@ def test_initialization_fixed_base_single_joint(self): self.assertEqual(articulation.data.root_pos_w.shape, (num_articulations, 3)) self.assertEqual(articulation.data.root_quat_w.shape, (num_articulations, 4)) self.assertEqual(articulation.data.joint_pos.shape, (num_articulations, 1)) + self.assertEqual( + articulation.data.default_mass.shape, (num_articulations, articulation.num_bodies) + ) + self.assertEqual( + articulation.data.default_inertia.shape, (num_articulations, articulation.num_bodies, 9) + ) # Check some internal physx data for debugging # -- joint related @@ -352,6 +370,12 @@ def test_initialization_hand_with_tendons(self): self.assertTrue(articulation.data.root_pos_w.shape == (num_articulations, 3)) self.assertTrue(articulation.data.root_quat_w.shape == (num_articulations, 4)) self.assertTrue(articulation.data.joint_pos.shape == (num_articulations, 24)) + self.assertEqual( + articulation.data.default_mass.shape, (num_articulations, articulation.num_bodies) + ) + self.assertEqual( + articulation.data.default_inertia.shape, (num_articulations, articulation.num_bodies, 9) + ) # Check some internal physx data for debugging # -- joint related diff --git a/source/extensions/omni.isaac.lab/test/assets/test_rigid_object.py b/source/extensions/omni.isaac.lab/test/assets/test_rigid_object.py index 549e7801fd..429264c2c3 100644 --- a/source/extensions/omni.isaac.lab/test/assets/test_rigid_object.py +++ b/source/extensions/omni.isaac.lab/test/assets/test_rigid_object.py @@ -108,6 +108,8 @@ def test_initialization(self): # Check buffers that exists and have correct shapes self.assertEqual(cube_object.data.root_pos_w.shape, (num_cubes, 3)) self.assertEqual(cube_object.data.root_quat_w.shape, (num_cubes, 4)) + self.assertEqual(cube_object.data.default_mass.shape, (num_cubes, 1)) + self.assertEqual(cube_object.data.default_inertia.shape, (num_cubes, 9)) # Simulate physics for _ in range(2): From e83f79e350ea3c53c372c97a4aead67258838e82 Mon Sep 17 00:00:00 2001 From: Mayank Mittal <12863862+Mayankm96@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:36:07 +0200 Subject: [PATCH 3/5] Switches to events for Anymal-C direct environment (#990) # Description The previous implementation in ANYmal-C environment randomly sampled the friction material. This sometimes led to an overflow of a number of materials possible from the PhysX side. This MR switches to using events for the ANYmal Direct RL environment implementation. Fixes [#941](https://github.com/isaac-sim/IsaacLab/issues/941) ## 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 `./isaaclab.sh --format` - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] 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 --- .../lab_tasks/direct/anymal_c/anymal_c_env.py | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py index badd2fa53a..f51e645711 100644 --- a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py +++ b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py @@ -7,7 +7,10 @@ import torch +import omni.isaac.lab.envs.mdp as mdp import omni.isaac.lab.sim as sim_utils +from omni.isaac.lab.managers import EventTermCfg as EventTerm +from omni.isaac.lab.managers import SceneEntityCfg from omni.isaac.lab.assets import Articulation, ArticulationCfg from omni.isaac.lab.envs import DirectRLEnv, DirectRLEnvCfg from omni.isaac.lab.scene import InteractiveSceneCfg @@ -23,6 +26,33 @@ from omni.isaac.lab.terrains.config.rough import ROUGH_TERRAINS_CFG # isort: skip +@configclass +class EventCfg: + """Configuration for randomization.""" + + physics_material = EventTerm( + func=mdp.randomize_rigid_body_material, + mode="startup", + params={ + "asset_cfg": SceneEntityCfg("robot", body_names=".*"), + "static_friction_range": (0.8, 0.8), + "dynamic_friction_range": (0.6, 0.6), + "restitution_range": (0.0, 0.0), + "num_buckets": 64, + }, + ) + + add_base_mass = EventTerm( + func=mdp.randomize_rigid_body_mass, + mode="startup", + params={ + "asset_cfg": SceneEntityCfg("robot", body_names="base"), + "mass_distribution_params": (-5.0, 5.0), + "operation": "add", + }, + ) + + @configclass class AnymalCFlatEnvCfg(DirectRLEnvCfg): # env @@ -63,6 +93,9 @@ class AnymalCFlatEnvCfg(DirectRLEnvCfg): # scene scene: InteractiveSceneCfg = InteractiveSceneCfg(num_envs=4096, env_spacing=4.0, replicate_physics=True) + # events + events: EventCfg = EventCfg() + # robot robot: ArticulationCfg = ANYMAL_C_CFG.replace(prim_path="/World/envs/env_.*/Robot") contact_sensor: ContactSensorCfg = ContactSensorCfg( @@ -152,19 +185,7 @@ def __init__(self, cfg: AnymalCFlatEnvCfg | AnymalCRoughEnvCfg, render_mode: str # Get specific body indices self._base_id, _ = self._contact_sensor.find_bodies("base") self._feet_ids, _ = self._contact_sensor.find_bodies(".*FOOT") - self._underisred_contact_body_ids, _ = self._contact_sensor.find_bodies(".*THIGH") - - # Randomize robot friction - env_ids = self._robot._ALL_INDICES - mat_props = self._robot.root_physx_view.get_material_properties() - mat_props[:, :, :2].uniform_(0.6, 0.8) - self._robot.root_physx_view.set_material_properties(mat_props, env_ids.cpu()) - - # Randomize base mass - base_id, _ = self._robot.find_bodies("base") - masses = self._robot.root_physx_view.get_masses() - masses[:, base_id] += torch.zeros_like(masses[:, base_id]).uniform_(-5.0, 5.0) - self._robot.root_physx_view.set_masses(masses, env_ids.cpu()) + self._undesired_contact_body_ids, _ = self._contact_sensor.find_bodies(".*THIGH") def _setup_scene(self): self._robot = Articulation(self.cfg.robot) @@ -245,7 +266,7 @@ def _get_rewards(self) -> torch.Tensor: # undersired contacts net_contact_forces = self._contact_sensor.data.net_forces_w_history is_contact = ( - torch.max(torch.norm(net_contact_forces[:, :, self._underisred_contact_body_ids], dim=-1), dim=1)[0] > 1.0 + torch.max(torch.norm(net_contact_forces[:, :, self._undesired_contact_body_ids], dim=-1), dim=1)[0] > 1.0 ) contacts = torch.sum(is_contact, dim=1) # flat orientation From 52af899614318a25404677bd7b754d867e743c45 Mon Sep 17 00:00:00 2001 From: Masoud Moghani Date: Thu, 19 Sep 2024 06:24:32 -0400 Subject: [PATCH 4/5] Adds visualization markers customization for the MDP command terms (#841) # Description This MR allows users to customize the visualization markers for the MDP command terms. It puts them in the command term configuration file instead of hard-coding them into the code. ## Type of change - New feature (non-breaking change which adds functionality) ## Checklist - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] 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 - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there --- .../omni.isaac.lab/config/extension.toml | 2 +- .../omni.isaac.lab/docs/CHANGELOG.rst | 10 ++++++ .../lab/envs/mdp/commands/commands_cfg.py | 36 +++++++++++++++++++ .../lab/envs/mdp/commands/pose_2d_command.py | 16 ++++----- .../lab/envs/mdp/commands/pose_command.py | 15 +++----- .../lab/envs/mdp/commands/velocity_command.py | 29 ++++++--------- .../lab_tasks/direct/anymal_c/anymal_c_env.py | 4 +-- .../inhand/mdp/commands/commands_cfg.py | 4 +-- .../mdp/commands/orientation_command.py | 12 +++---- 9 files changed, 79 insertions(+), 49 deletions(-) diff --git a/source/extensions/omni.isaac.lab/config/extension.toml b/source/extensions/omni.isaac.lab/config/extension.toml index 18e5941c45..f7efe39c04 100644 --- a/source/extensions/omni.isaac.lab/config/extension.toml +++ b/source/extensions/omni.isaac.lab/config/extension.toml @@ -1,7 +1,7 @@ [package] # Note: Semantic Versioning is used: https://semver.org/ -version = "0.22.11" +version = "0.22.12" # Description title = "Isaac Lab framework for Robot Learning" diff --git a/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst b/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst index 4b45490da6..9e9c1c82a5 100644 --- a/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst +++ b/source/extensions/omni.isaac.lab/docs/CHANGELOG.rst @@ -1,6 +1,16 @@ Changelog --------- +0.22.12 (2024-09-08) +~~~~~~~~~~~~~~~~~~~~ + +Changed +^^^^^^^ + +* Moved the configuration of visualization markers for the command terms to their respective configuration classes. + This allows users to modify the markers for the command terms without having to modify the command term classes. + + 0.22.11 (2024-09-10) ~~~~~~~~~~~~~~~~~~~~ diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/commands_cfg.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/commands_cfg.py index f4a8e16a0c..d548f554db 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/commands_cfg.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/commands_cfg.py @@ -7,6 +7,8 @@ from dataclasses import MISSING from omni.isaac.lab.managers import CommandTermCfg +from omni.isaac.lab.markers import VisualizationMarkersCfg +from omni.isaac.lab.markers.config import BLUE_ARROW_X_MARKER_CFG, FRAME_MARKER_CFG, GREEN_ARROW_X_MARKER_CFG from omni.isaac.lab.utils import configclass from .null_command import NullCommand @@ -62,6 +64,20 @@ class Ranges: ranges: Ranges = MISSING """Distribution ranges for the velocity commands.""" + goal_vel_visualizer_cfg: VisualizationMarkersCfg = GREEN_ARROW_X_MARKER_CFG.replace( + prim_path="/Visuals/Command/velocity_goal" + ) + """The configuration for the goal velocity visualization marker. Defaults to GREEN_ARROW_X_MARKER_CFG.""" + + current_vel_visualizer_cfg: VisualizationMarkersCfg = BLUE_ARROW_X_MARKER_CFG.replace( + prim_path="/Visuals/Command/velocity_current" + ) + """The configuration for the current velocity visualization marker. Defaults to BLUE_ARROW_X_MARKER_CFG.""" + + # Set the scale of the visualization markers to (0.5, 0.5, 0.5) + goal_vel_visualizer_cfg.markers["arrow"].scale = (0.5, 0.5, 0.5) + current_vel_visualizer_cfg.markers["arrow"].scale = (0.5, 0.5, 0.5) + @configclass class NormalVelocityCommandCfg(UniformVelocityCommandCfg): @@ -125,6 +141,18 @@ class Ranges: ranges: Ranges = MISSING """Ranges for the commands.""" + goal_pose_visualizer_cfg: VisualizationMarkersCfg = FRAME_MARKER_CFG.replace(prim_path="/Visuals/Command/goal_pose") + """The configuration for the goal pose visualization marker. Defaults to FRAME_MARKER_CFG.""" + + current_pose_visualizer_cfg: VisualizationMarkersCfg = FRAME_MARKER_CFG.replace( + prim_path="/Visuals/Command/body_pose" + ) + """The configuration for the current pose visualization marker. Defaults to FRAME_MARKER_CFG.""" + + # Set the scale of the visualization markers to (0.1, 0.1, 0.1) + goal_pose_visualizer_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) + current_pose_visualizer_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) + @configclass class UniformPose2dCommandCfg(CommandTermCfg): @@ -158,6 +186,14 @@ class Ranges: ranges: Ranges = MISSING """Distribution ranges for the position commands.""" + goal_pose_visualizer_cfg: VisualizationMarkersCfg = GREEN_ARROW_X_MARKER_CFG.replace( + prim_path="/Visuals/Command/pose_goal" + ) + """The configuration for the goal pose visualization marker. Defaults to GREEN_ARROW_X_MARKER_CFG.""" + + # Set the scale of the visualization markers to (0.2, 0.2, 0.8) + goal_pose_visualizer_cfg.markers["arrow"].scale = (0.2, 0.2, 0.8) + @configclass class TerrainBasedPose2dCommandCfg(UniformPose2dCommandCfg): diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_2d_command.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_2d_command.py index 9b5e91491b..f933760e07 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_2d_command.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_2d_command.py @@ -14,7 +14,6 @@ from omni.isaac.lab.assets import Articulation from omni.isaac.lab.managers import CommandTerm from omni.isaac.lab.markers import VisualizationMarkers -from omni.isaac.lab.markers.config import GREEN_ARROW_X_MARKER_CFG from omni.isaac.lab.terrains import TerrainImporter from omni.isaac.lab.utils.math import quat_from_euler_xyz, quat_rotate_inverse, wrap_to_pi, yaw_quat @@ -124,20 +123,17 @@ def _update_command(self): def _set_debug_vis_impl(self, debug_vis: bool): # create markers if necessary for the first tome if debug_vis: - if not hasattr(self, "arrow_goal_visualizer"): - marker_cfg = GREEN_ARROW_X_MARKER_CFG.copy() - marker_cfg.markers["arrow"].scale = (0.2, 0.2, 0.8) - marker_cfg.prim_path = "/Visuals/Command/pose_goal" - self.arrow_goal_visualizer = VisualizationMarkers(marker_cfg) + if not hasattr(self, "goal_pose_visualizer"): + self.goal_pose_visualizer = VisualizationMarkers(self.cfg.goal_pose_visualizer_cfg) # set their visibility to true - self.arrow_goal_visualizer.set_visibility(True) + self.goal_pose_visualizer.set_visibility(True) else: - if hasattr(self, "arrow_goal_visualizer"): - self.arrow_goal_visualizer.set_visibility(False) + if hasattr(self, "goal_pose_visualizer"): + self.goal_pose_visualizer.set_visibility(False) def _debug_vis_callback(self, event): # update the box marker - self.arrow_goal_visualizer.visualize( + self.goal_pose_visualizer.visualize( translations=self.pos_command_w, orientations=quat_from_euler_xyz( torch.zeros_like(self.heading_command_w), diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_command.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_command.py index fdf3ead774..328834540e 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_command.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/pose_command.py @@ -14,7 +14,6 @@ from omni.isaac.lab.assets import Articulation from omni.isaac.lab.managers import CommandTerm from omni.isaac.lab.markers import VisualizationMarkers -from omni.isaac.lab.markers.config import FRAME_MARKER_CFG from omni.isaac.lab.utils.math import combine_frame_transforms, compute_pose_error, quat_from_euler_xyz, quat_unique if TYPE_CHECKING: @@ -131,21 +130,17 @@ def _set_debug_vis_impl(self, debug_vis: bool): # create markers if necessary for the first tome if debug_vis: if not hasattr(self, "goal_pose_visualizer"): - marker_cfg = FRAME_MARKER_CFG.copy() - marker_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) # -- goal pose - marker_cfg.prim_path = "/Visuals/Command/goal_pose" - self.goal_pose_visualizer = VisualizationMarkers(marker_cfg) + self.goal_pose_visualizer = VisualizationMarkers(self.cfg.goal_pose_visualizer_cfg) # -- current body pose - marker_cfg.prim_path = "/Visuals/Command/body_pose" - self.body_pose_visualizer = VisualizationMarkers(marker_cfg) + self.current_pose_visualizer = VisualizationMarkers(self.cfg.current_pose_visualizer_cfg) # set their visibility to true self.goal_pose_visualizer.set_visibility(True) - self.body_pose_visualizer.set_visibility(True) + self.current_pose_visualizer.set_visibility(True) else: if hasattr(self, "goal_pose_visualizer"): self.goal_pose_visualizer.set_visibility(False) - self.body_pose_visualizer.set_visibility(False) + self.current_pose_visualizer.set_visibility(False) def _debug_vis_callback(self, event): # check if robot is initialized @@ -157,4 +152,4 @@ def _debug_vis_callback(self, event): self.goal_pose_visualizer.visualize(self.pose_command_w[:, :3], self.pose_command_w[:, 3:]) # -- current body pose body_pose_w = self.robot.data.body_state_w[:, self.body_idx] - self.body_pose_visualizer.visualize(body_pose_w[:, :3], body_pose_w[:, 3:7]) + self.current_pose_visualizer.visualize(body_pose_w[:, :3], body_pose_w[:, 3:7]) diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/velocity_command.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/velocity_command.py index 20c88dada8..4a35adc5fd 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/velocity_command.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/commands/velocity_command.py @@ -15,7 +15,6 @@ from omni.isaac.lab.assets import Articulation from omni.isaac.lab.managers import CommandTerm from omni.isaac.lab.markers import VisualizationMarkers -from omni.isaac.lab.markers.config import BLUE_ARROW_X_MARKER_CFG, GREEN_ARROW_X_MARKER_CFG if TYPE_CHECKING: from omni.isaac.lab.envs import ManagerBasedEnv @@ -148,24 +147,18 @@ def _set_debug_vis_impl(self, debug_vis: bool): # note: parent only deals with callbacks. not their visibility if debug_vis: # create markers if necessary for the first tome - if not hasattr(self, "base_vel_goal_visualizer"): + if not hasattr(self, "goal_vel_visualizer"): # -- goal - marker_cfg = GREEN_ARROW_X_MARKER_CFG.copy() - marker_cfg.prim_path = "/Visuals/Command/velocity_goal" - marker_cfg.markers["arrow"].scale = (0.5, 0.5, 0.5) - self.base_vel_goal_visualizer = VisualizationMarkers(marker_cfg) + self.goal_vel_visualizer = VisualizationMarkers(self.cfg.goal_vel_visualizer_cfg) # -- current - marker_cfg = BLUE_ARROW_X_MARKER_CFG.copy() - marker_cfg.prim_path = "/Visuals/Command/velocity_current" - marker_cfg.markers["arrow"].scale = (0.5, 0.5, 0.5) - self.base_vel_visualizer = VisualizationMarkers(marker_cfg) + self.current_vel_visualizer = VisualizationMarkers(self.cfg.current_vel_visualizer_cfg) # set their visibility to true - self.base_vel_goal_visualizer.set_visibility(True) - self.base_vel_visualizer.set_visibility(True) + self.goal_vel_visualizer.set_visibility(True) + self.current_vel_visualizer.set_visibility(True) else: - if hasattr(self, "base_vel_goal_visualizer"): - self.base_vel_goal_visualizer.set_visibility(False) - self.base_vel_visualizer.set_visibility(False) + if hasattr(self, "goal_vel_visualizer"): + self.goal_vel_visualizer.set_visibility(False) + self.current_vel_visualizer.set_visibility(False) def _debug_vis_callback(self, event): # check if robot is initialized @@ -180,8 +173,8 @@ def _debug_vis_callback(self, event): vel_des_arrow_scale, vel_des_arrow_quat = self._resolve_xy_velocity_to_arrow(self.command[:, :2]) vel_arrow_scale, vel_arrow_quat = self._resolve_xy_velocity_to_arrow(self.robot.data.root_lin_vel_b[:, :2]) # display markers - self.base_vel_goal_visualizer.visualize(base_pos_w, vel_des_arrow_quat, vel_des_arrow_scale) - self.base_vel_visualizer.visualize(base_pos_w, vel_arrow_quat, vel_arrow_scale) + self.goal_vel_visualizer.visualize(base_pos_w, vel_des_arrow_quat, vel_des_arrow_scale) + self.current_vel_visualizer.visualize(base_pos_w, vel_arrow_quat, vel_arrow_scale) """ Internal helpers. @@ -190,7 +183,7 @@ def _debug_vis_callback(self, event): def _resolve_xy_velocity_to_arrow(self, xy_velocity: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: """Converts the XY base velocity command to arrow direction rotation.""" # obtain default scale of the marker - default_scale = self.base_vel_goal_visualizer.cfg.markers["arrow"].scale + default_scale = self.goal_vel_visualizer.cfg.markers["arrow"].scale # arrow-scale arrow_scale = torch.tensor(default_scale, device=self.device).repeat(xy_velocity.shape[0], 1) arrow_scale[:, 0] *= torch.linalg.norm(xy_velocity, dim=1) * 3.0 diff --git a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py index f51e645711..5490bb0dd3 100644 --- a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py +++ b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/direct/anymal_c/anymal_c_env.py @@ -9,10 +9,10 @@ import omni.isaac.lab.envs.mdp as mdp import omni.isaac.lab.sim as sim_utils -from omni.isaac.lab.managers import EventTermCfg as EventTerm -from omni.isaac.lab.managers import SceneEntityCfg from omni.isaac.lab.assets import Articulation, ArticulationCfg from omni.isaac.lab.envs import DirectRLEnv, DirectRLEnvCfg +from omni.isaac.lab.managers import EventTermCfg as EventTerm +from omni.isaac.lab.managers import SceneEntityCfg from omni.isaac.lab.scene import InteractiveSceneCfg from omni.isaac.lab.sensors import ContactSensor, ContactSensorCfg, RayCaster, RayCasterCfg, patterns from omni.isaac.lab.sim import SimulationCfg diff --git a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/commands_cfg.py b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/commands_cfg.py index d60eb96059..82826b7e46 100644 --- a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/commands_cfg.py +++ b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/commands_cfg.py @@ -55,7 +55,7 @@ class InHandReOrientationCommandCfg(CommandTermCfg): Otherwise, the marker may occlude the object in the visualization. """ - visualizer_cfg: VisualizationMarkersCfg = VisualizationMarkersCfg( + goal_pose_visualizer_cfg: VisualizationMarkersCfg = VisualizationMarkersCfg( prim_path="/Visuals/Command/goal_marker", markers={ "goal": sim_utils.UsdFileCfg( @@ -64,4 +64,4 @@ class InHandReOrientationCommandCfg(CommandTermCfg): ), }, ) - """Configuration for the visualization markers. Default is a cube marker.""" + """The configuration for the goal pose visualization marker. Defaults to a DexCube marker.""" diff --git a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/orientation_command.py b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/orientation_command.py index da6b6ba1ea..153127c45c 100644 --- a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/orientation_command.py +++ b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/manipulation/inhand/mdp/commands/orientation_command.py @@ -128,17 +128,17 @@ def _set_debug_vis_impl(self, debug_vis: TYPE_CHECKING): # note: parent only deals with callbacks. not their visibility if debug_vis: # create markers if necessary for the first time - if not hasattr(self, "goal_marker_visualizer"): - self.goal_marker_visualizer = VisualizationMarkers(self.cfg.visualizer_cfg) + if not hasattr(self, "goal_pose_visualizer"): + self.goal_pose_visualizer = VisualizationMarkers(self.cfg.goal_pose_visualizer_cfg) # set visibility - self.goal_marker_visualizer.set_visibility(True) + self.goal_pose_visualizer.set_visibility(True) else: - if hasattr(self, "goal_marker_visualizer"): - self.goal_marker_visualizer.set_visibility(False) + if hasattr(self, "goal_pose_visualizer"): + self.goal_pose_visualizer.set_visibility(False) def _debug_vis_callback(self, event): # add an offset to the marker position to visualize the goal marker_pos = self.pos_command_w + torch.tensor(self.cfg.marker_pos_offset, device=self.device) marker_quat = self.quat_command_w # visualize the goal marker - self.goal_marker_visualizer.visualize(translations=marker_pos, orientations=marker_quat) + self.goal_pose_visualizer.visualize(translations=marker_pos, orientations=marker_quat) From 55ab94793083afc411bc3a1df38026eb9c1b62e0 Mon Sep 17 00:00:00 2001 From: Pascal Roth <57946385+pascal-roth@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:08:56 +0200 Subject: [PATCH 5/5] Adds test for camera to check that different image sizes work (#964) # Description Adds test to check that different image sizes are respected by the camera implementation. Fixes #165 ## Type of change - New feature (non-breaking change which adds functionality) ## Checklist - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.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 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 --- .../test/sensors/test_camera.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/source/extensions/omni.isaac.lab/test/sensors/test_camera.py b/source/extensions/omni.isaac.lab/test/sensors/test_camera.py index a0befeb75b..2e2166fc3d 100644 --- a/source/extensions/omni.isaac.lab/test/sensors/test_camera.py +++ b/source/extensions/omni.isaac.lab/test/sensors/test_camera.py @@ -231,6 +231,39 @@ def test_multi_camera_init(self): for im_data in cam.data.output.to_dict().values(): self.assertEqual(im_data.shape, (1, self.camera_cfg.height, self.camera_cfg.width)) + def test_multi_camera_with_different_resolution(self): + """Test multi-camera initialization with cameras having different image resolutions.""" + # create two cameras with different prim paths + # -- camera 1 + cam_cfg_1 = copy.deepcopy(self.camera_cfg) + cam_cfg_1.prim_path = "/World/Camera_1" + cam_1 = Camera(cam_cfg_1) + # -- camera 2 + cam_cfg_2 = copy.deepcopy(self.camera_cfg) + cam_cfg_2.prim_path = "/World/Camera_2" + cam_cfg_2.height = 240 + cam_cfg_2.width = 320 + cam_2 = Camera(cam_cfg_2) + + # play sim + self.sim.reset() + + # Simulate for a few steps + # note: This is a workaround to ensure that the textures are loaded. + # Check "Known Issues" section in the documentation for more details. + for _ in range(5): + self.sim.step() + # perform rendering + self.sim.step() + # update camera + cam_1.update(self.dt) + cam_2.update(self.dt) + # check image sizes + self.assertEqual( + cam_1.data.output["distance_to_image_plane"].shape, (1, self.camera_cfg.height, self.camera_cfg.width) + ) + self.assertEqual(cam_2.data.output["distance_to_image_plane"].shape, (1, cam_cfg_2.height, cam_cfg_2.width)) + def test_camera_init_intrinsic_matrix(self): """Test camera initialization from intrinsic matrix.""" # get the first camera