Skip to content

Commit 72515eb

Browse files
rwiltzhougantc-nvdakellyguo11
authored
Refactors retargeters and adds Quest retargeters for G1 tasks (#3950)
# Description This MR does the following: - Introduces Quest retargeters for G1 env loco-manipulation tasks. This enables lower body control via the quest controller joysticks, and upper body control via controller tracking. - Refactors the retargeters to *not* depend on OpenXRDevice, instead move enums into DeviceBase and allow retargeters to be used across devices. - Adds XrAnchor "pinning" to a specific robot prim so that the XR view follows the robot in the scene. Fixes # (issue) ## Type of change - New feature (non-breaking change which adds functionality) - Breaking change (existing functionality will not work without user modification) - Documentation update ## Screenshots Please attach before and after screenshots of the change if applicable. ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [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 - [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 - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there --------- Signed-off-by: Kelly Guo <kellyg@nvidia.com> Co-authored-by: Hougant Chen <hougantc@nvidia.com> Co-authored-by: Kelly Guo <kellyg@nvidia.com>
1 parent 10cf4c1 commit 72515eb

33 files changed

+1036
-121
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Guidelines for modifications:
7373
* HoJin Jeon
7474
* Hongwei Xiong
7575
* Hongyu Li
76+
* Hougant Chen
7677
* Huihua Zhao
7778
* Iretiayo Akinola
7879
* Jack Zeng

docs/source/api/lab/isaaclab.devices.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ Game Pad
4848
:members:
4949
:inherited-members:
5050
:show-inheritance:
51+
:noindex:
5152

5253
.. autoclass:: Se3Gamepad
5354
:members:
5455
:inherited-members:
5556
:show-inheritance:
57+
:noindex:
5658

5759
Keyboard
5860
--------
@@ -61,11 +63,13 @@ Keyboard
6163
:members:
6264
:inherited-members:
6365
:show-inheritance:
66+
:noindex:
6467

6568
.. autoclass:: Se3Keyboard
6669
:members:
6770
:inherited-members:
6871
:show-inheritance:
72+
:noindex:
6973

7074
Space Mouse
7175
-----------
@@ -74,11 +78,13 @@ Space Mouse
7478
:members:
7579
:inherited-members:
7680
:show-inheritance:
81+
:noindex:
7782

7883
.. autoclass:: Se3SpaceMouse
7984
:members:
8085
:inherited-members:
8186
:show-inheritance:
87+
:noindex:
8288

8389
Haply
8490
-----
@@ -87,6 +93,7 @@ Haply
8793
:members:
8894
:inherited-members:
8995
:show-inheritance:
96+
:noindex:
9097

9198
OpenXR
9299
------
@@ -95,6 +102,7 @@ OpenXR
95102
:members:
96103
:inherited-members:
97104
:show-inheritance:
105+
:noindex:
98106

99107
Manus + Vive
100108
------------
@@ -103,6 +111,7 @@ Manus + Vive
103111
:members:
104112
:inherited-members:
105113
:show-inheritance:
114+
:noindex:
106115

107116
Retargeters
108117
-----------
@@ -111,18 +120,22 @@ Retargeters
111120
:members:
112121
:inherited-members:
113122
:show-inheritance:
123+
:noindex:
114124

115125
.. autoclass:: isaaclab.devices.openxr.retargeters.Se3AbsRetargeter
116126
:members:
117127
:inherited-members:
118128
:show-inheritance:
129+
:noindex:
119130

120131
.. autoclass:: isaaclab.devices.openxr.retargeters.Se3RelRetargeter
121132
:members:
122133
:inherited-members:
123134
:show-inheritance:
135+
:noindex:
124136

125137
.. autoclass:: isaaclab.devices.openxr.retargeters.GR1T2Retargeter
126138
:members:
127139
:inherited-members:
128140
:show-inheritance:
141+
:noindex:

docs/source/how-to/cloudxr_teleoperation.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,11 @@ Here's an example of setting up hand tracking:
721721
722722
# Create retargeters
723723
position_retargeter = Se3AbsRetargeter(
724-
bound_hand=OpenXRDevice.TrackingTarget.HAND_RIGHT,
724+
bound_hand=DeviceBase.TrackingTarget.HAND_RIGHT,
725725
zero_out_xy_rotation=True,
726726
use_wrist_position=False # Use pinch position (thumb-index midpoint) instead of wrist
727727
)
728-
gripper_retargeter = GripperRetargeter(bound_hand=OpenXRDevice.TrackingTarget.HAND_RIGHT)
728+
gripper_retargeter = GripperRetargeter(bound_hand=DeviceBase.TrackingTarget.HAND_RIGHT)
729729
730730
# Create OpenXR device with hand tracking and both retargeters
731731
device = OpenXRDevice(
@@ -919,15 +919,15 @@ The retargeting system is designed to be extensible. You can create custom retar
919919
Any: The transformed control commands for the robot.
920920
"""
921921
# Access hand tracking data using TrackingTarget enum
922-
right_hand_data = data[OpenXRDevice.TrackingTarget.HAND_RIGHT]
922+
right_hand_data = data[DeviceBase.TrackingTarget.HAND_RIGHT]
923923
924924
# Extract specific joint positions and orientations
925925
wrist_pose = right_hand_data.get("wrist")
926926
thumb_tip_pose = right_hand_data.get("thumb_tip")
927927
index_tip_pose = right_hand_data.get("index_tip")
928928
929929
# Access head tracking data
930-
head_pose = data[OpenXRDevice.TrackingTarget.HEAD]
930+
head_pose = data[DeviceBase.TrackingTarget.HEAD]
931931
932932
# Process the tracking data and apply your custom logic
933933
# ...

scripts/environments/teleoperation/teleop_se3_agent.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
#
44
# SPDX-License-Identifier: BSD-3-Clause
55

6-
"""Script to run a keyboard teleoperation with Isaac Lab manipulation environments."""
6+
"""Script to run teleoperation with Isaac Lab manipulation environments.
7+
8+
Supports multiple input devices (e.g., keyboard, spacemouse, gamepad) and devices
9+
configured within the environment (including OpenXR-based hand tracking or motion
10+
controllers)."""
711

812
"""Launch Isaac Sim Simulator first."""
913

@@ -13,7 +17,7 @@
1317
from isaaclab.app import AppLauncher
1418

1519
# add argparse arguments
16-
parser = argparse.ArgumentParser(description="Keyboard teleoperation for Isaac Lab environments.")
20+
parser = argparse.ArgumentParser(description="Teleoperation for Isaac Lab environments.")
1721
parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to simulate.")
1822
parser.add_argument(
1923
"--teleop_device",
@@ -78,7 +82,7 @@
7882

7983
def main() -> None:
8084
"""
81-
Run keyboard teleoperation with Isaac Lab manipulation environment.
85+
Run teleoperation with an Isaac Lab manipulation environment.
8286
8387
Creates the environment, sets up teleoperation interfaces and callbacks,
8488
and runs the main simulation loop until the application is closed.
@@ -98,8 +102,6 @@ def main() -> None:
98102
env_cfg.terminations.object_reached_goal = DoneTerm(func=mdp.object_reached_goal)
99103

100104
if args_cli.xr:
101-
# External cameras are not supported with XR teleop
102-
# Check for any camera configs and disable them
103105
env_cfg = remove_camera_configs(env_cfg)
104106
env_cfg.sim.render.antialiasing_mode = "DLSS"
105107

@@ -204,7 +206,7 @@ def stop_teleoperation() -> None:
204206
)
205207
else:
206208
logger.error(f"Unsupported teleop device: {args_cli.teleop_device}")
207-
logger.error("Supported devices: keyboard, spacemouse, gamepad, handtracking")
209+
logger.error("Configure the teleop device in the environment config.")
208210
env.close()
209211
simulation_app.close()
210212
return
@@ -254,6 +256,7 @@ def stop_teleoperation() -> None:
254256

255257
if should_reset_recording_instance:
256258
env.reset()
259+
teleop_interface.reset()
257260
should_reset_recording_instance = False
258261
print("Environment reset complete")
259262
except Exception as e:

source/isaaclab/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.48.5"
4+
version = "0.48.6"
55

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

source/isaaclab/docs/CHANGELOG.rst

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

4+
0.48.6 (2025-11-18)
5+
~~~~~~~~~~~~~~~~~~~
6+
7+
Added
8+
^^^^^
9+
10+
* Added OpenXR motion controller support for the G1 robot locomanipulation environment
11+
``Isaac-PickPlace-Locomanipulation-G1-Abs-v0``. This enables teleoperation using XR motion controllers
12+
in addition to hand tracking.
13+
* Added :class:`OpenXRDeviceMotionController` for motion controller-based teleoperation with headset anchoring control.
14+
* Added motion controller-specific retargeters:
15+
* :class:`G1TriHandControllerUpperBodyRetargeterCfg` for upper body and hand control using motion controllers.
16+
* :class:`G1LowerBodyStandingControllerRetargeterCfg` for lower body control using motion controllers.
17+
18+
419
0.48.5 (2025-11-14)
520
~~~~~~~~~~~~~~~~~~~
621

source/isaaclab/isaaclab/devices/device_base.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from abc import ABC, abstractmethod
1010
from collections.abc import Callable
1111
from dataclasses import dataclass, field
12+
from enum import Enum
1213
from typing import Any
1314

1415
from isaaclab.devices.retargeter_base import RetargeterBase, RetargeterCfg
@@ -58,9 +59,13 @@ def __init__(self, retargeters: list[RetargeterBase] | None = None):
5859
"""
5960
# Initialize empty list if None is provided
6061
self._retargeters = retargeters or []
62+
# Aggregate required features across all retargeters
63+
self._required_features = set()
64+
for retargeter in self._retargeters:
65+
self._required_features.update(retargeter.get_requirements())
6166

6267
def __str__(self) -> str:
63-
"""Returns: A string containing the information of joystick."""
68+
"""Returns: A string identifier for the device."""
6469
return f"{self.__class__.__name__}"
6570

6671
"""
@@ -123,3 +128,32 @@ def advance(self) -> torch.Tensor:
123128
# With multiple retargeters, return a tuple of outputs
124129
# Concatenate retargeted outputs into a single tensor
125130
return torch.cat([retargeter.retarget(raw_data) for retargeter in self._retargeters], dim=-1)
131+
132+
# -----------------------------
133+
# Shared data layout helpers (for retargeters across devices)
134+
# -----------------------------
135+
class TrackingTarget(Enum):
136+
"""Standard tracking targets shared across devices."""
137+
138+
HAND_LEFT = 0
139+
HAND_RIGHT = 1
140+
HEAD = 2
141+
CONTROLLER_LEFT = 3
142+
CONTROLLER_RIGHT = 4
143+
144+
class MotionControllerDataRowIndex(Enum):
145+
"""Rows in the motion-controller 2x7 array."""
146+
147+
POSE = 0
148+
INPUTS = 1
149+
150+
class MotionControllerInputIndex(Enum):
151+
"""Indices in the motion-controller input row."""
152+
153+
THUMBSTICK_X = 0
154+
THUMBSTICK_Y = 1
155+
TRIGGER = 2
156+
SQUEEZE = 3
157+
BUTTON_0 = 4
158+
BUTTON_1 = 5
159+
PADDING = 6

source/isaaclab/isaaclab/devices/openxr/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77

88
from .manus_vive import ManusVive, ManusViveCfg
99
from .openxr_device import OpenXRDevice, OpenXRDeviceCfg
10-
from .xr_cfg import XrCfg, remove_camera_configs
10+
from .xr_cfg import XrAnchorRotationMode, XrCfg, remove_camera_configs

source/isaaclab/isaaclab/devices/openxr/manus_vive.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import numpy as np
1414
from collections.abc import Callable
1515
from dataclasses import dataclass
16-
from enum import Enum
1716

1817
import carb
1918
from isaacsim.core.version import get_version
@@ -22,7 +21,6 @@
2221
from isaaclab.devices.retargeter_base import RetargeterBase
2322

2423
from ..device_base import DeviceBase, DeviceCfg
25-
from .openxr_device import OpenXRDevice
2624
from .xr_cfg import XrCfg
2725

2826
# For testing purposes, we need to mock the XRCore
@@ -61,13 +59,6 @@ class ManusVive(DeviceBase):
6159
data is transformed into robot control commands suitable for teleoperation.
6260
"""
6361

64-
class TrackingTarget(Enum):
65-
"""Enum class specifying what to track with Manus+Vive. Consistent with :class:`OpenXRDevice.TrackingTarget`."""
66-
67-
HAND_LEFT = 0
68-
HAND_RIGHT = 1
69-
HEAD = 2
70-
7162
TELEOP_COMMAND_EVENT_TYPE = "teleop_command"
7263

7364
def __init__(self, cfg: ManusViveCfg, retargeters: list[RetargeterBase] | None = None):
@@ -192,9 +183,9 @@ def _get_raw_data(self) -> dict:
192183
joint_name = HAND_JOINT_MAP[int(index)]
193184
result[hand][joint_name] = np.array(pose["position"] + pose["orientation"], dtype=np.float32)
194185
return {
195-
OpenXRDevice.TrackingTarget.HAND_LEFT: result["left"],
196-
OpenXRDevice.TrackingTarget.HAND_RIGHT: result["right"],
197-
OpenXRDevice.TrackingTarget.HEAD: self._calculate_headpose(),
186+
DeviceBase.TrackingTarget.HAND_LEFT: result["left"],
187+
DeviceBase.TrackingTarget.HAND_RIGHT: result["right"],
188+
DeviceBase.TrackingTarget.HEAD: self._calculate_headpose(),
198189
}
199190

200191
def _calculate_headpose(self) -> np.ndarray:

0 commit comments

Comments
 (0)