diff --git a/docs/source/device/trackers.rst b/docs/source/device/trackers.rst index d32b6cd101..ba6bbfcfed 100644 --- a/docs/source/device/trackers.rst +++ b/docs/source/device/trackers.rst @@ -212,7 +212,7 @@ Tracks articulated hand joints (26 joints per hand, following the OpenXR - :code-file:`examples/oxr/cpp/oxr_simple_api_demo.cpp` - :code-file:`examples/oxr/python/modular_example.py` - - :code-file:`examples/retargeting/python/sources_example.py` + - :code-file:`examples/retargeting/python/isaacteleop_examples/retargeting/sources_example.py` ControllerTracker ~~~~~~~~~~~~~~~~~ @@ -232,7 +232,7 @@ axis inputs. Uses standard OpenXR action bindings. - Examples: - - :code-file:`examples/retargeting/python/sources_example.py` + - :code-file:`examples/retargeting/python/isaacteleop_examples/retargeting/sources_example.py` - :code-file:`examples/teleop/python/locomotion_retargeting_example.py` - :code-file:`examples/teleop/python/gripper_retargeting_example_simple.py` @@ -382,6 +382,6 @@ For end-to-end usage patterns combining trackers with a ``DeviceIOSession``, see For higher-level usage with the teleop session manager and retargeting, see: -- :code-file:`examples/retargeting/python/sources_example.py` +- :code-file:`examples/retargeting/python/isaacteleop_examples/retargeting/sources_example.py` - :code-file:`examples/teleop/python/gripper_retargeting_example_simple.py` - :code-file:`examples/teleop/python/locomotion_retargeting_example.py` diff --git a/docs/source/references/retargeting/sharpa.rst b/docs/source/references/retargeting/sharpa.rst index ae53362362..3e8f508b29 100644 --- a/docs/source/references/retargeting/sharpa.rst +++ b/docs/source/references/retargeting/sharpa.rst @@ -125,19 +125,20 @@ produced in your target joint order. Run the example --------------- -The repo ships a bimanual demo at -``examples/retargeting/python/sharpa_hand_retargeter_demo.py``: +The repo ships a bimanual demo in ``examples/retargeting``: .. code-block:: console + $ uv pip install -e ./examples/retargeting + # Synthetic curl animation (no headset, no GUI required): - $ python examples/retargeting/python/sharpa_hand_retargeter_demo.py --synthetic + $ python -m isaacteleop_examples.retargeting.sharpa_hand_retargeter_demo --synthetic # Live bimanual from a connected Quest headset: - $ python examples/retargeting/python/sharpa_hand_retargeter_demo.py + $ python -m isaacteleop_examples.retargeting.sharpa_hand_retargeter_demo # Custom MJCFs (e.g. the mesh-bearing variants): - $ python examples/retargeting/python/sharpa_hand_retargeter_demo.py \ + $ python -m isaacteleop_examples.retargeting.sharpa_hand_retargeter_demo \ --left-mjcf /path/to/left_sharpawave.xml \ --right-mjcf /path/to/right_sharpawave.xml diff --git a/docs/source/references/retargeting/wuji.rst b/docs/source/references/retargeting/wuji.rst index 0c95cb45fc..08201fa3c9 100644 --- a/docs/source/references/retargeting/wuji.rst +++ b/docs/source/references/retargeting/wuji.rst @@ -69,16 +69,18 @@ real Wuji hand: .. code-block:: console + $ uv pip install -e ./examples/retargeting + # Device-free smoke test - $ python examples/retargeting/python/wuji_hand_retargeter_demo.py \ + $ python -m isaacteleop_examples.retargeting.wuji_hand_retargeter_demo \ --mode synthetic --model wuji_hand_2 --hand right # Replay MediaPipe-format keypoints - $ python examples/retargeting/python/wuji_hand_retargeter_demo.py \ + $ python -m isaacteleop_examples.retargeting.wuji_hand_retargeter_demo \ --mode replay --replay my_take.pkl --model wuji_hand_2 --hand right # Drive real hardware and let TeleopSession launch the Wuji glove plugin - $ python examples/retargeting/python/wuji_hand_retargeter_demo.py \ + $ python -m isaacteleop_examples.retargeting.wuji_hand_retargeter_demo \ --mode drive --hand right --plugin-path build/src/plugins Drive mode needs a running CloudXR runtime, an OpenXR hand-tracking source, and diff --git a/examples/retargeting/CMakeLists.txt b/examples/retargeting/CMakeLists.txt index 1286a8b55c..1e42335683 100644 --- a/examples/retargeting/CMakeLists.txt +++ b/examples/retargeting/CMakeLists.txt @@ -1,7 +1,7 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 cmake_minimum_required(VERSION 3.20) include(${CMAKE_SOURCE_DIR}/cmake/InstallPythonExample.cmake) -install_python_example(DESTINATION examples/retargeting/python) +install_python_example(DESTINATION examples/retargeting) diff --git a/examples/retargeting/README.md b/examples/retargeting/README.md new file mode 100644 index 0000000000..7cb862fe86 --- /dev/null +++ b/examples/retargeting/README.md @@ -0,0 +1,25 @@ + + +# Retargeting engine examples + +Standalone demos of the retargeting engine. Install once, then run whichever +one you want: + +```bash +uv pip install -e ./examples/retargeting +python -m isaacteleop_examples.retargeting.sources_example +``` + +| Module | What it shows | +| --- | --- | +| `sources_example` | Wiring DeviceIO sources into a retargeting graph | +| `dual_source_teleop_example` | Two input sources driving one session | +| `example_retargeters` | `GainOffsetRetargeter`, a minimal custom retargeter | +| `multi_retargeter_tuning_demo_imgui` | Tuning several retargeters live, with an ImGui panel | +| `sharpa_hand_retargeter_demo` | Bimanual Sharpa hands; `--synthetic` needs no headset | +| `wuji_hand_retargeter_demo` | Wuji hand, in `synthetic` / `replay` / `drive` modes | + +Docs: `docs/source/references/retargeting/`. diff --git a/examples/retargeting/pyproject.toml b/examples/retargeting/pyproject.toml new file mode 100644 index 0000000000..e23a686158 --- /dev/null +++ b/examples/retargeting/pyproject.toml @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +# The dist name mirrors the import path, so an installed example claims no bare +# top-level name in site-packages. +name = "isaacteleop-examples-retargeting" +version = "0.0.0" # Internal examples - not versioned +description = "Retargeting Engine Python Examples" +requires-python = ">=3.11,<3.14" +dependencies = [ + "isaacteleop[ui,retargeters-lite]", + "numpy>=1.23.0", +] + +# `isaacteleop_examples` is a PEP 420 namespace shared by every example dist and +# must stay without an __init__.py. `only-include` + `sources`, not `packages`: +# the latter keeps only the last path component and would root the wheel at a +# bare top-level `retargeting/`. +[tool.hatch.build.targets.wheel] +only-include = ["python/isaacteleop_examples/retargeting"] +sources = ["python"] diff --git a/examples/retargeting/python/isaacteleop_examples/retargeting/__init__.py b/examples/retargeting/python/isaacteleop_examples/retargeting/__init__.py new file mode 100644 index 0000000000..52a7a9daf0 --- /dev/null +++ b/examples/retargeting/python/isaacteleop_examples/retargeting/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/examples/retargeting/python/dual_source_teleop_example.py b/examples/retargeting/python/isaacteleop_examples/retargeting/dual_source_teleop_example.py similarity index 98% rename from examples/retargeting/python/dual_source_teleop_example.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/dual_source_teleop_example.py index 97d5632756..8f2e60a711 100644 --- a/examples/retargeting/python/dual_source_teleop_example.py +++ b/examples/retargeting/python/isaacteleop_examples/retargeting/dual_source_teleop_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 """ diff --git a/examples/retargeting/python/example_retargeters.py b/examples/retargeting/python/isaacteleop_examples/retargeting/example_retargeters.py similarity index 98% rename from examples/retargeting/python/example_retargeters.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/example_retargeters.py index 66e0a7e216..6b867162f9 100644 --- a/examples/retargeting/python/example_retargeters.py +++ b/examples/retargeting/python/isaacteleop_examples/retargeting/example_retargeters.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 """ diff --git a/examples/retargeting/python/multi_retargeter_tuning_demo_imgui.py b/examples/retargeting/python/isaacteleop_examples/retargeting/multi_retargeter_tuning_demo_imgui.py similarity index 96% rename from examples/retargeting/python/multi_retargeter_tuning_demo_imgui.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/multi_retargeter_tuning_demo_imgui.py index a3236636cb..ad7049f957 100755 --- a/examples/retargeting/python/multi_retargeter_tuning_demo_imgui.py +++ b/examples/retargeting/python/isaacteleop_examples/retargeting/multi_retargeter_tuning_demo_imgui.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 """ @@ -25,7 +25,7 @@ import numpy as np -from example_retargeters import GainOffsetRetargeter +from .example_retargeters import GainOffsetRetargeter from isaacteleop.retargeting_engine.interface import TensorGroup from isaacteleop.retargeting_engine_ui import ( MultiRetargeterTuningUIImGui, diff --git a/examples/retargeting/python/sharpa_hand_retargeter_demo.py b/examples/retargeting/python/isaacteleop_examples/retargeting/sharpa_hand_retargeter_demo.py similarity index 100% rename from examples/retargeting/python/sharpa_hand_retargeter_demo.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/sharpa_hand_retargeter_demo.py diff --git a/examples/retargeting/python/sources_example.py b/examples/retargeting/python/isaacteleop_examples/retargeting/sources_example.py similarity index 100% rename from examples/retargeting/python/sources_example.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/sources_example.py diff --git a/examples/retargeting/python/wuji_hand_retargeter_demo.py b/examples/retargeting/python/isaacteleop_examples/retargeting/wuji_hand_retargeter_demo.py similarity index 100% rename from examples/retargeting/python/wuji_hand_retargeter_demo.py rename to examples/retargeting/python/isaacteleop_examples/retargeting/wuji_hand_retargeter_demo.py diff --git a/examples/retargeting/python/pyproject.toml b/examples/retargeting/python/pyproject.toml deleted file mode 100644 index 6eff918fc4..0000000000 --- a/examples/retargeting/python/pyproject.toml +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -[project] -name = "retargeting-examples" -version = "0.0.0" # Internal examples - not versioned -description = "Retargeting Engine Python Examples" -requires-python = ">=3.11,<3.14" -dependencies = [ - "isaacteleop[ui,retargeters-lite]", - "numpy>=1.23.0", -]