Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds body tracking option to ViewerCfg #1620

Merged
merged 8 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/extensions/omni.isaac.lab/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "0.30.2"
version = "0.30.3"

# Description
title = "Isaac Lab framework for Robot Learning"
Expand Down
9 changes: 9 additions & 0 deletions source/extensions/omni.isaac.lab/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Changelog
---------

0.30.3 (2025-01-02)
~~~~~~~~~~~~~~~~~~~

Added
^^^^^

* Added body tracking as an origin type to :class:`omni.isaac.lab.envs.ViewerCfg` and :class:`omni.isaac.lab.envs.ui.ViewportCameraController`.


0.30.2 (2024-12-22)
~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def body_state_w(self):
@property
def body_link_state_w(self):
"""State of all bodies `[pos, quat, lin_vel, ang_vel]` in simulation world frame.
Shape is (num_instances,1, 13).
Shape is (num_instances, 1, 13).

The position, quaternion, and linear/angular velocity are of the body's link frame relative to the world.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ class ViewerCfg:
Default is (1280, 720).
"""

origin_type: Literal["world", "env", "asset_root"] = "world"
origin_type: Literal["world", "env", "asset_root", "asset_body"] = "world"
"""The frame in which the camera position (eye) and target (lookat) are defined in. Default is "world".

Available options are:

* ``"world"``: The origin of the world.
* ``"env"``: The origin of the environment defined by :attr:`env_index`.
* ``"asset_root"``: The center of the asset defined by :attr:`asset_name` in environment :attr:`env_index`.
* ``"asset_body"``: The center of the body defined by :attr:`body_name` in asset defined by :attr:`asset_name` in environment :attr:`env_index`.
"""

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

body_name: str | None = None
"""The name of the body in :attr:`asset_name` in the interactive scene for the frame origin. Default is None.

This quantity is only effective if :attr:`origin` is set to "asset_body".
"""


##
# Types.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import omni.kit.app
import omni.timeline

from omni.isaac.lab.assets.articulation.articulation import Articulation

if TYPE_CHECKING:
from omni.isaac.lab.envs import DirectRLEnv, ManagerBasedEnv, ViewerCfg

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

def update_view_to_asset_body(self, asset_name: str, body_name: str):
"""Updates the viewer's origin based upon the body of an asset in the scene.

Args:
asset_name: The name of the asset in the scene. The name should match the name of the
asset in the scene.
body_name: The name of the body in the asset.

Raises:
ValueError: If the asset is not in the scene or the body is not valid.
"""
# check if the asset is in the scene
if self.cfg.asset_name != asset_name:
asset_entities = [*self._env.scene.rigid_objects.keys(), *self._env.scene.articulations.keys()]
if asset_name not in asset_entities:
raise ValueError(f"Asset '{asset_name}' is not in the scene. Available entities: {asset_entities}.")
# check if the body is in the asset
asset: Articulation = self._env.scene[asset_name]
if body_name not in asset.body_names:
raise ValueError(
f"'{body_name}' is not a body of Asset '{asset_name}'. Available bodies: {asset.body_names}."
)
# get the body index
body_id, _ = asset.find_bodies(body_name)
# update the asset name
self.cfg.asset_name = asset_name
# set origin type to asset_body
self.cfg.origin_type = "asset_body"
# update the camera origins
self.viewer_origin = (
self._env.scene[self.cfg.asset_name].data.body_link_pos_w[self.cfg.env_index, body_id].view(3)
)
# update the camera view
self.update_view_location()

def update_view_location(self, eye: Sequence[float] | None = None, lookat: Sequence[float] | None = None):
"""Updates the camera view pose based on the current viewer origin and the eye and lookat positions.

Expand Down Expand Up @@ -190,3 +230,5 @@ def _update_tracking_callback(self, event):
# in other cases, the camera view is static and does not need to be updated continuously
if self.cfg.origin_type == "asset_root" and self.cfg.asset_name is not None:
self.update_view_to_asset_root(self.cfg.asset_name)
if self.cfg.origin_type == "asset_body" and self.cfg.asset_name is not None and self.cfg.body_name is not None:
self.update_view_to_asset_body(self.cfg.asset_name, self.cfg.body_name)
Loading