Skip to content

Commit a29bea0

Browse files
KyleM73kellyguo11
andauthored
Adds body tracking option to ViewerCfg (#1620)
# Description Resolves Issue #1534 by adding non-root body tracking as an option in the ViewerCfg. See the issue for justification/discussion. API as follows: - Adds origin_type "asset_body" - Adds field "body_name" When origin_type = "asset_body" and "body_name" matches a body in the asset specified in "asset_name", the viewport is configured to track the link frame of the body in world coordinates. By using the existing eye and lookat fields in ViewerCfg the additional features are enabled: - Tracking the end effector of an arm during manipulation (see below) - Tracking a fixed offset from the end effector of an arm (e.g. mimicking the view of a wrist-mounted camera) - Tracking a mobile base using the currently-supported workaround for lack of wheel physics by defining a virtual arm to mimic the motion of the robot ## Type of change - New feature (non-breaking change which adds functionality) ## Training Video from "Isaac-Lift-Cube-Franka-v0" after 1000 iterations. Viewer defined as follows: viewer = ViewerCfg(eye=(0.5, 0.5, 0.0), origin_type="asset_body", env_index=0, asset_name="robot", body_name="panda_hand") No other changes were made from the default environment definition. https://github.com/user-attachments/assets/fff24b50-c9d0-48dd-b4c2-3641a11f0d4d ## 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 - [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 --------- Signed-off-by: Kelly Guo <[email protected]> Signed-off-by: Kelly Guo <[email protected]> Co-authored-by: Kelly Guo <[email protected]> Co-authored-by: Kelly Guo <[email protected]>
1 parent 7ea72c4 commit a29bea0

File tree

5 files changed

+62
-4
lines changed

5 files changed

+62
-4
lines changed

source/extensions/omni.isaac.lab/config/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
# Note: Semantic Versioning is used: https://semver.org/
4-
version = "0.30.2"
4+
version = "0.30.3"
55

66
# Description
77
title = "Isaac Lab framework for Robot Learning"

source/extensions/omni.isaac.lab/docs/CHANGELOG.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
---------
33

4+
0.30.3 (2025-01-02)
5+
~~~~~~~~~~~~~~~~~~~
6+
7+
Added
8+
^^^^^
9+
10+
* Added body tracking as an origin type to :class:`omni.isaac.lab.envs.ViewerCfg` and :class:`omni.isaac.lab.envs.ui.ViewportCameraController`.
11+
12+
413
0.30.2 (2024-12-22)
514
~~~~~~~~~~~~~~~~~~~
615

source/extensions/omni.isaac.lab/omni/isaac/lab/assets/rigid_object/rigid_object_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def body_state_w(self):
202202
@property
203203
def body_link_state_w(self):
204204
"""State of all bodies `[pos, quat, lin_vel, ang_vel]` in simulation world frame.
205-
Shape is (num_instances,1, 13).
205+
Shape is (num_instances, 1, 13).
206206
207207
The position, quaternion, and linear/angular velocity are of the body's link frame relative to the world.
208208
"""

source/extensions/omni.isaac.lab/omni/isaac/lab/envs/common.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ class ViewerCfg:
3636
Default is (1280, 720).
3737
"""
3838

39-
origin_type: Literal["world", "env", "asset_root"] = "world"
39+
origin_type: Literal["world", "env", "asset_root", "asset_body"] = "world"
4040
"""The frame in which the camera position (eye) and target (lookat) are defined in. Default is "world".
4141
4242
Available options are:
4343
4444
* ``"world"``: The origin of the world.
4545
* ``"env"``: The origin of the environment defined by :attr:`env_index`.
4646
* ``"asset_root"``: The center of the asset defined by :attr:`asset_name` in environment :attr:`env_index`.
47+
* ``"asset_body"``: The center of the body defined by :attr:`body_name` in asset defined by :attr:`asset_name` in environment :attr:`env_index`.
4748
"""
4849

4950
env_index: int = 0
@@ -58,6 +59,12 @@ class ViewerCfg:
5859
This quantity is only effective if :attr:`origin` is set to "asset_root".
5960
"""
6061

62+
body_name: str | None = None
63+
"""The name of the body in :attr:`asset_name` in the interactive scene for the frame origin. Default is None.
64+
65+
This quantity is only effective if :attr:`origin` is set to "asset_body".
66+
"""
67+
6168

6269
##
6370
# Types.

source/extensions/omni.isaac.lab/omni/isaac/lab/envs/ui/viewport_camera_controller.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import omni.kit.app
1616
import omni.timeline
1717

18+
from omni.isaac.lab.assets.articulation.articulation import Articulation
19+
1820
if TYPE_CHECKING:
1921
from omni.isaac.lab.envs import DirectRLEnv, ManagerBasedEnv, ViewerCfg
2022

@@ -59,12 +61,15 @@ def __init__(self, env: ManagerBasedEnv | DirectRLEnv, cfg: ViewerCfg):
5961
self.set_view_env_index(self.cfg.env_index)
6062
# set the camera origin to the center of the environment
6163
self.update_view_to_env()
62-
elif self.cfg.origin_type == "asset_root":
64+
elif self.cfg.origin_type == "asset_root" or self.cfg.origin_type == "asset_body":
6365
# note: we do not yet update camera for tracking an asset origin, as the asset may not yet be
6466
# in the scene when this is called. Instead, we subscribe to the post update event to update the camera
6567
# at each rendering step.
6668
if self.cfg.asset_name is None:
6769
raise ValueError(f"No asset name provided for viewer with origin type: '{self.cfg.origin_type}'.")
70+
if self.cfg.origin_type == "asset_body":
71+
if self.cfg.body_name is None:
72+
raise ValueError(f"No body name provided for viewer with origin type: '{self.cfg.origin_type}'.")
6873
else:
6974
# set the camera origin to the center of the world
7075
self.update_view_to_world()
@@ -160,6 +165,41 @@ def update_view_to_asset_root(self, asset_name: str):
160165
# update the camera view
161166
self.update_view_location()
162167

168+
def update_view_to_asset_body(self, asset_name: str, body_name: str):
169+
"""Updates the viewer's origin based upon the body of an asset in the scene.
170+
171+
Args:
172+
asset_name: The name of the asset in the scene. The name should match the name of the
173+
asset in the scene.
174+
body_name: The name of the body in the asset.
175+
176+
Raises:
177+
ValueError: If the asset is not in the scene or the body is not valid.
178+
"""
179+
# check if the asset is in the scene
180+
if self.cfg.asset_name != asset_name:
181+
asset_entities = [*self._env.scene.rigid_objects.keys(), *self._env.scene.articulations.keys()]
182+
if asset_name not in asset_entities:
183+
raise ValueError(f"Asset '{asset_name}' is not in the scene. Available entities: {asset_entities}.")
184+
# check if the body is in the asset
185+
asset: Articulation = self._env.scene[asset_name]
186+
if body_name not in asset.body_names:
187+
raise ValueError(
188+
f"'{body_name}' is not a body of Asset '{asset_name}'. Available bodies: {asset.body_names}."
189+
)
190+
# get the body index
191+
body_id, _ = asset.find_bodies(body_name)
192+
# update the asset name
193+
self.cfg.asset_name = asset_name
194+
# set origin type to asset_body
195+
self.cfg.origin_type = "asset_body"
196+
# update the camera origins
197+
self.viewer_origin = (
198+
self._env.scene[self.cfg.asset_name].data.body_link_pos_w[self.cfg.env_index, body_id].view(3)
199+
)
200+
# update the camera view
201+
self.update_view_location()
202+
163203
def update_view_location(self, eye: Sequence[float] | None = None, lookat: Sequence[float] | None = None):
164204
"""Updates the camera view pose based on the current viewer origin and the eye and lookat positions.
165205
@@ -190,3 +230,5 @@ def _update_tracking_callback(self, event):
190230
# in other cases, the camera view is static and does not need to be updated continuously
191231
if self.cfg.origin_type == "asset_root" and self.cfg.asset_name is not None:
192232
self.update_view_to_asset_root(self.cfg.asset_name)
233+
if self.cfg.origin_type == "asset_body" and self.cfg.asset_name is not None and self.cfg.body_name is not None:
234+
self.update_view_to_asset_body(self.cfg.asset_name, self.cfg.body_name)

0 commit comments

Comments
 (0)