Unverified Commit e5b43e96 authored by renezurbruegg's avatar renezurbruegg Committed by GitHub

Fixes FrameTransformer sensor visualization implementation (#15)

# Description

This MR fixes:
- FrameTransformer crashing when `debug_vis` is set to true
- Hard-coding of visualization configs inside the sensor implementation

## Type of change

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

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] 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
parent ab3f3a36
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.9.36" version = "0.9.37"
# Description # Description
title = "ORBIT framework for Robot Learning" title = "ORBIT framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.9.37 (2023-11-06)
~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Fixed broken visualization in :mod:`omni.isaac.orbit.sensors.FrameTramsformer` class by overwriting the
correct ``_debug_vis_callback`` function.
* Moved the visualization marker configurations of sensors to their respective sensor configuration classes.
This allows users to set these configurations from the configuration object itself.
0.9.36 (2023-11-03) 0.9.36 (2023-11-03)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
......
...@@ -108,7 +108,7 @@ class AssetBase(ABC): ...@@ -108,7 +108,7 @@ class AssetBase(ABC):
def has_debug_vis_implementation(self) -> bool: def has_debug_vis_implementation(self) -> bool:
"""Whether the asset has a debug visualization implemented.""" """Whether the asset has a debug visualization implemented."""
# check if function raises NotImplementedError # check if function raises NotImplementedError
source_code = inspect.getsource(self._debug_vis_callback) source_code = inspect.getsource(self._set_debug_vis_impl)
return "NotImplementedError" not in source_code return "NotImplementedError" not in source_code
""" """
......
...@@ -93,7 +93,7 @@ class CommandGeneratorBase(ABC): ...@@ -93,7 +93,7 @@ class CommandGeneratorBase(ABC):
def has_debug_vis_implementation(self) -> bool: def has_debug_vis_implementation(self) -> bool:
"""Whether the command generator has a debug visualization implemented.""" """Whether the command generator has a debug visualization implemented."""
# check if function raises NotImplementedError # check if function raises NotImplementedError
source_code = inspect.getsource(self._debug_vis_callback) source_code = inspect.getsource(self._set_debug_vis_impl)
return "NotImplementedError" not in source_code return "NotImplementedError" not in source_code
""" """
......
...@@ -18,7 +18,6 @@ from pxr import PhysxSchema ...@@ -18,7 +18,6 @@ from pxr import PhysxSchema
import omni.isaac.orbit.utils.string as string_utils import omni.isaac.orbit.utils.string as string_utils
from omni.isaac.orbit.markers import VisualizationMarkers from omni.isaac.orbit.markers import VisualizationMarkers
from omni.isaac.orbit.markers.config import CONTACT_SENSOR_MARKER_CFG
from ..sensor_base import SensorBase from ..sensor_base import SensorBase
from .contact_sensor_data import ContactSensorData from .contact_sensor_data import ContactSensorData
...@@ -280,8 +279,7 @@ class ContactSensor(SensorBase): ...@@ -280,8 +279,7 @@ class ContactSensor(SensorBase):
if debug_vis: if debug_vis:
# create markers if necessary for the first tome # create markers if necessary for the first tome
if not hasattr(self, "contact_visualizer"): if not hasattr(self, "contact_visualizer"):
visualizer_cfg = CONTACT_SENSOR_MARKER_CFG.replace(prim_path="/Visuals/ContactSensor") self.contact_visualizer = VisualizationMarkers(self.cfg.visualizer_cfg)
self.contact_visualizer = VisualizationMarkers(visualizer_cfg)
# set their visibility to true # set their visibility to true
self.contact_visualizer.set_visibility(True) self.contact_visualizer.set_visibility(True)
else: else:
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
from __future__ import annotations from __future__ import annotations
from omni.isaac.orbit.markers import VisualizationMarkersCfg
from omni.isaac.orbit.markers.config import CONTACT_SENSOR_MARKER_CFG
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from ..sensor_base_cfg import SensorBaseCfg from ..sensor_base_cfg import SensorBaseCfg
...@@ -33,3 +35,10 @@ class ContactSensorCfg(SensorBaseCfg): ...@@ -33,3 +35,10 @@ class ContactSensorCfg(SensorBaseCfg):
If an empty list is provided, then only net contact forces are reported. If an empty list is provided, then only net contact forces are reported.
""" """
visualizer_cfg: VisualizationMarkersCfg = CONTACT_SENSOR_MARKER_CFG.replace(prim_path="/Visuals/ContactSensor")
"""The configuration object for the visualization markers. Defaults to CONTACT_SENSOR_MARKER_CFG.
Note:
This attribute is only used when debug visualization is enabled.
"""
...@@ -14,7 +14,6 @@ from omni.isaac.core.prims import RigidPrimView ...@@ -14,7 +14,6 @@ from omni.isaac.core.prims import RigidPrimView
from pxr import UsdPhysics from pxr import UsdPhysics
from omni.isaac.orbit.markers import VisualizationMarkers from omni.isaac.orbit.markers import VisualizationMarkers
from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG
from omni.isaac.orbit.utils.math import ( from omni.isaac.orbit.utils.math import (
combine_frame_transforms, combine_frame_transforms,
convert_quat, convert_quat,
...@@ -72,9 +71,6 @@ class FrameTransformer(SensorBase): ...@@ -72,9 +71,6 @@ class FrameTransformer(SensorBase):
# Create empty variables for storing output data # Create empty variables for storing output data
self._data: FrameTransformerData = FrameTransformerData() self._data: FrameTransformerData = FrameTransformerData()
# visualization markers
self.transform_visualizer = None
def __str__(self) -> str: def __str__(self) -> str:
"""Returns: A string containing information about the instance.""" """Returns: A string containing information about the instance."""
return ( return (
...@@ -100,11 +96,6 @@ class FrameTransformer(SensorBase): ...@@ -100,11 +96,6 @@ class FrameTransformer(SensorBase):
Operations Operations
""" """
def set_debug_vis(self, debug_vis: bool):
super().set_debug_vis(debug_vis)
if self.frame_transform_visualizer is not None:
self.frame_transform_visualizer.set_visibility(debug_vis)
def reset(self, env_ids: Sequence[int] | None = None): def reset(self, env_ids: Sequence[int] | None = None):
# reset the timers and counters # reset the timers and counters
super().reset(env_ids) super().reset(env_ids)
...@@ -341,11 +332,19 @@ class FrameTransformer(SensorBase): ...@@ -341,11 +332,19 @@ class FrameTransformer(SensorBase):
self._data.target_pos_source[:] = target_pos_source.view(-1, total_num_frames, 3) self._data.target_pos_source[:] = target_pos_source.view(-1, total_num_frames, 3)
self._data.target_rot_source[:] = target_rot_source.view(-1, total_num_frames, 4) self._data.target_rot_source[:] = target_rot_source.view(-1, total_num_frames, 4)
def _debug_vis_impl(self): def _set_debug_vis_impl(self, debug_vis: bool):
# visualize the transform # set visibility of markers
if self.transform_visualizer is None: # note: parent only deals with callbacks. not their visibility
cfg = FRAME_MARKER_CFG.replace(prim_path="/Visuals/FrameTransformer") if debug_vis:
cfg.markers["frame"].scale = (0.05, 0.05, 0.05) if not hasattr(self, "frame_visualizer"):
self.transform_visualizer = VisualizationMarkers(cfg) self.frame_visualizer = VisualizationMarkers(self.cfg.visualizer_cfg)
# set their visibility to true
self.frame_visualizer.set_visibility(True)
else:
if hasattr(self, "frame_visualizer"):
self.frame_visualizer.set_visibility(False)
self.transform_visualizer.visualize(self._data.target_pos_w.view(-1, 3), self._data.target_rot_w.view(-1, 4)) def _debug_vis_callback(self, event):
# Update the visualized markers
if self.frame_visualizer is not None:
self.frame_visualizer.visualize(self._data.target_pos_w.view(-1, 3), self._data.target_rot_w.view(-1, 4))
...@@ -7,6 +7,7 @@ from __future__ import annotations ...@@ -7,6 +7,7 @@ from __future__ import annotations
from dataclasses import MISSING from dataclasses import MISSING
from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG, VisualizationMarkersCfg
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from ..sensor_base_cfg import SensorBaseCfg from ..sensor_base_cfg import SensorBaseCfg
...@@ -60,3 +61,10 @@ class FrameTransformerCfg(SensorBaseCfg): ...@@ -60,3 +61,10 @@ class FrameTransformerCfg(SensorBaseCfg):
we can use a single FrameTransformer to track each foot's position and orientation in the body we can use a single FrameTransformer to track each foot's position and orientation in the body
frame using four frame offsets. frame using four frame offsets.
""" """
visualizer_cfg: VisualizationMarkersCfg = FRAME_MARKER_CFG.replace(prim_path="/Visuals/FrameTransformer")
"""The configuration object for the visualization markers. Defaults to FRAME_MARKER_CFG.
Note:
This attribute is only used when debug visualization is enabled.
"""
...@@ -17,7 +17,6 @@ from omni.isaac.core.prims import RigidPrimView, XFormPrimView ...@@ -17,7 +17,6 @@ from omni.isaac.core.prims import RigidPrimView, XFormPrimView
from pxr import UsdGeom, UsdPhysics from pxr import UsdGeom, UsdPhysics
from omni.isaac.orbit.markers import VisualizationMarkers from omni.isaac.orbit.markers import VisualizationMarkers
from omni.isaac.orbit.markers.config import RAY_CASTER_MARKER_CFG
from omni.isaac.orbit.terrains.trimesh.utils import make_plane from omni.isaac.orbit.terrains.trimesh.utils import make_plane
from omni.isaac.orbit.utils.math import quat_apply, quat_apply_yaw from omni.isaac.orbit.utils.math import quat_apply, quat_apply_yaw
from omni.isaac.orbit.utils.warp import convert_to_warp_mesh, raycast_mesh from omni.isaac.orbit.utils.warp import convert_to_warp_mesh, raycast_mesh
...@@ -240,8 +239,7 @@ class RayCaster(SensorBase): ...@@ -240,8 +239,7 @@ class RayCaster(SensorBase):
# note: parent only deals with callbacks. not their visibility # note: parent only deals with callbacks. not their visibility
if debug_vis: if debug_vis:
if not hasattr(self, "ray_visualizer"): if not hasattr(self, "ray_visualizer"):
visualizer_cfg = RAY_CASTER_MARKER_CFG.replace(prim_path="/Visuals/RayCaster") self.ray_visualizer = VisualizationMarkers(self.cfg.visualizer_cfg)
self.ray_visualizer = VisualizationMarkers(visualizer_cfg)
# set their visibility to true # set their visibility to true
self.ray_visualizer.set_visibility(True) self.ray_visualizer.set_visibility(True)
else: else:
......
...@@ -9,6 +9,8 @@ from __future__ import annotations ...@@ -9,6 +9,8 @@ from __future__ import annotations
from dataclasses import MISSING from dataclasses import MISSING
from omni.isaac.orbit.markers import VisualizationMarkersCfg
from omni.isaac.orbit.markers.config import RAY_CASTER_MARKER_CFG
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from ..sensor_base_cfg import SensorBaseCfg from ..sensor_base_cfg import SensorBaseCfg
...@@ -59,3 +61,10 @@ class RayCasterCfg(SensorBaseCfg): ...@@ -59,3 +61,10 @@ class RayCasterCfg(SensorBaseCfg):
For floating base robots, this is useful for simulating drift in the robot's pose estimation. For floating base robots, this is useful for simulating drift in the robot's pose estimation.
""" """
visualizer_cfg: VisualizationMarkersCfg = RAY_CASTER_MARKER_CFG.replace(prim_path="/Visuals/FrameTransformer")
"""The configuration object for the visualization markers. Defaults to RAY_CASTER_MARKER_CFG.
Note:
This attribute is only used when debug visualization is enabled.
"""
...@@ -118,8 +118,7 @@ class SensorBase(ABC): ...@@ -118,8 +118,7 @@ class SensorBase(ABC):
def has_debug_vis_implementation(self) -> bool: def has_debug_vis_implementation(self) -> bool:
"""Whether the sensor has a debug visualization implemented.""" """Whether the sensor has a debug visualization implemented."""
# check if function raises NotImplementedError # check if function raises NotImplementedError
# check if function raises NotImplementedError source_code = inspect.getsource(self._set_debug_vis_impl)
source_code = inspect.getsource(self._debug_vis_callback)
return "NotImplementedError" not in source_code return "NotImplementedError" not in source_code
""" """
......
...@@ -33,7 +33,7 @@ parser.add_argument( ...@@ -33,7 +33,7 @@ parser.add_argument(
"--visualize", "--visualize",
action="store_true", action="store_true",
help=( help=(
"Whether to enable FrameTransformer's debug_vis (True) or visualize each frame one at a" "Whether to enable FrameTransformer's debug_vis (True) or visualize each frame one at a"
" time and print to console (False)." " time and print to console (False)."
), ),
) )
...@@ -182,7 +182,7 @@ def main(): ...@@ -182,7 +182,7 @@ def main():
# to step through each frame so the user can verify that the correct frame # to step through each frame so the user can verify that the correct frame
# is being visualized as the frame names are printing to console # is being visualized as the frame names are printing to console
if not args_cli.visualize: if not args_cli.visualize:
cfg = FRAME_MARKER_CFG.replace(prim_path="/Visuals/FrameTransformer") cfg = FRAME_MARKER_CFG.replace(prim_path="/Visuals/FrameVisualizerFromScript")
cfg.markers["frame"].scale = (0.05, 0.05, 0.05) cfg.markers["frame"].scale = (0.05, 0.05, 0.05)
transform_visualizer = VisualizationMarkers(cfg) transform_visualizer = VisualizationMarkers(cfg)
else: else:
...@@ -237,6 +237,7 @@ def main(): ...@@ -237,6 +237,7 @@ def main():
print(f"Displaying {frame_index}: {frame_name}") print(f"Displaying {frame_index}: {frame_name}")
frame_index += 1 frame_index += 1
frame_index = frame_index % len(frame_names) frame_index = frame_index % len(frame_names)
# visualize frame # visualize frame
pos = scene["frame_transformer"].data.target_pos_w[:, frame_index] pos = scene["frame_transformer"].data.target_pos_w[:, frame_index]
rot = scene["frame_transformer"].data.target_rot_w[:, frame_index] rot = scene["frame_transformer"].data.target_rot_w[:, frame_index]
......
...@@ -18,7 +18,6 @@ from __future__ import annotations ...@@ -18,7 +18,6 @@ from __future__ import annotations
import argparse import argparse
# omni-isaac-orbit
from omni.isaac.kit import SimulationApp from omni.isaac.kit import SimulationApp
# add argparse arguments # add argparse arguments
...@@ -41,18 +40,17 @@ simulation_app = SimulationApp(config) ...@@ -41,18 +40,17 @@ simulation_app = SimulationApp(config)
"""Rest everything follows.""" """Rest everything follows."""
import numpy as np
import torch import torch
import traceback import traceback
import carb import carb
import omni.isaac.core.utils.prims as prim_utils import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.cloner import GridCloner from omni.isaac.cloner import GridCloner
from omni.isaac.core.objects import DynamicSphere
from omni.isaac.core.prims import RigidPrimView from omni.isaac.core.prims import RigidPrimView
from omni.isaac.core.simulation_context import SimulationContext from omni.isaac.core.simulation_context import SimulationContext
from omni.isaac.core.utils.viewports import set_camera_view from omni.isaac.core.utils.viewports import set_camera_view
import omni.isaac.orbit.sim as sim_utils
import omni.isaac.orbit.terrains as terrain_gen import omni.isaac.orbit.terrains as terrain_gen
from omni.isaac.orbit.sensors.ray_caster import RayCaster, RayCasterCfg, patterns from omni.isaac.orbit.sensors.ray_caster import RayCaster, RayCasterCfg, patterns
from omni.isaac.orbit.terrains.config.rough import ROUGH_TERRAINS_CFG from omni.isaac.orbit.terrains.config.rough import ROUGH_TERRAINS_CFG
...@@ -70,16 +68,17 @@ def design_scene(sim: SimulationContext, num_envs: int = 2048): ...@@ -70,16 +68,17 @@ def design_scene(sim: SimulationContext, num_envs: int = 2048):
prim_utils.define_prim("/World/envs/env_0") prim_utils.define_prim("/World/envs/env_0")
# Define the scene # Define the scene
# -- Light # -- Light
prim_utils.create_prim("/World/light", "DistantLight") cfg = sim_utils.DistantLightCfg(intensity=2000)
cfg.func("/World/light", cfg)
# -- Balls # -- Balls
# -- Ball physics cfg = sim_utils.SphereCfg(
DynamicSphere(
prim_path="/World/envs/env_0/ball",
translation=np.array([0.0, 0.0, 5.0]),
mass=0.5,
radius=0.25, radius=0.25,
color=np.asarray((0.0, 0.0, 1.0)), rigid_props=sim_utils.RigidBodyPropertiesCfg(),
mass_props=sim_utils.MassPropertiesCfg(mass=0.5),
collision_props=sim_utils.CollisionPropertiesCfg(),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 1.0)),
) )
cfg.func("/World/envs/env_0/ball", cfg, translation=(0.0, 0.0, 5.0))
# Clone the scene # Clone the scene
cloner.define_base_env("/World/envs") cloner.define_base_env("/World/envs")
envs_prim_paths = cloner.generate_paths("/World/envs/env", num_paths=num_envs) envs_prim_paths = cloner.generate_paths("/World/envs/env", num_paths=num_envs)
......
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