Skip to content
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
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ project.spdx
# MuJoCo writes this to the working directory, not next to the model.
MUJOCO_LOG.TXT

# examples/mcap_record_replay, examples/noitom and examples/oglo_tactile write here
# by default (Path.cwd() / "recordings"), and their READMEs have you run from the
# repo root.
# Examples and test scripts that record write here by default
# (Path.cwd() / "recordings"), and their docs have you run from the repo root.
/recordings/

# Runtime device files injected by MCP server infrastructure
Expand Down
4 changes: 2 additions & 2 deletions deps/cloudxr/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -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

# Test container for Isaac Teleop tests (Python and native C++)
Expand All @@ -25,7 +25,7 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY install/ /app/install/

# Copy test files
COPY examples/oxr/python/ /app/tests/
COPY tests/python/xr_runtime/ /app/tests/

# Keep the exact CI wheel and its transition dependency available in one install.
WORKDIR /app/tests
Expand Down
2 changes: 1 addition & 1 deletion docs/source/device/body_tracking/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ joint ``is_valid`` flags to determine which joints have valid poses.
For a minimal C++ reader see ``examples/schemaio/full_body_printer.cpp``, which
creates the tracker, queries the required OpenXR extensions, and prints the
joint data each frame through ``DeviceIOSession``. The Python equivalent is
``examples/oxr/python/test_full_body_tracker.py``. Neither embeds
``tests/python/xr_runtime/test_full_body_tracker.py``. Neither embeds
``CloudXRLauncher``, so start the runtime first and source its environment in
the shell that launches them:

Expand Down
16 changes: 13 additions & 3 deletions docs/source/device/cameras/oak.rst
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,19 @@ controllers, etc.):
while True:
session.step() # metadata is recorded each update

See also :code-file:`examples/oxr/python/test_oak_camera.py` (``--mode
schema-pusher``) for a standalone PluginManager + DeviceIOSession example of
the same SchemaPusher flow.
The test script :code-file:`tests/python/xr_runtime/test_oak_camera.py` runs the
same SchemaPusher flow with ``PluginManager`` and ``DeviceIOSession`` directly.
It loads the plugin from ``install/plugins``, so it needs a full build and install
of the tree configured above, not only ``camera_plugin_oak``. With ``isaaccapture``
installed in the active environment (step 4 of :doc:`/development/build_from_source/index`)
and the CloudXR environment loaded (see :ref:`load-cloudxr-environment-variables`),
run from the repository root:

.. code-block:: bash

cmake --build build --parallel
cmake --install build
python tests/python/xr_runtime/test_oak_camera.py --mode schema-pusher

Configuration
-------------
Expand Down
14 changes: 7 additions & 7 deletions docs/source/device/trackers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Tracks the HMD head pose via the OpenXR view space.
- Examples:

- :code-file:`examples/oxr/cpp/oxr_simple_api_demo.cpp`
- :code-file:`examples/oxr/python/modular_example.py`
- :code-file:`examples/oxr/python/isaaccapture_examples/oxr/modular_example.py`

HandTracker
~~~~~~~~~~~
Expand All @@ -225,12 +225,12 @@ Tracks articulated hand joints (26 joints per hand, following the OpenXR

- :code-file:`tests/cpp/core/schema/test_hand.cpp`
- :code-file:`tests/python/core/schema/test_hand.py`
- :code-file:`examples/oxr/python/test_synthetic_hands.py`
- :code-file:`tests/python/xr_runtime/test_synthetic_hands.py`

- Examples:

- :code-file:`examples/oxr/cpp/oxr_simple_api_demo.cpp`
- :code-file:`examples/oxr/python/modular_example.py`
- :code-file:`examples/oxr/python/isaaccapture_examples/oxr/modular_example.py`
- :code-file:`examples/retargeting/python/isaaccapture_examples/retargeting/sources_example.py`

ControllerTracker
Expand All @@ -247,7 +247,7 @@ axis inputs. Uses standard OpenXR action bindings.

- :code-file:`tests/cpp/core/schema/test_controller.cpp`
- :code-file:`tests/python/core/schema/test_controller.py`
- :code-file:`examples/oxr/python/test_controller_tracker.py`
- :code-file:`tests/python/xr_runtime/test_controller_tracker.py`

- Examples:

Expand All @@ -273,7 +273,7 @@ reads the PICO ``XR_BD_body_tracking`` extension directly.

- :code-file:`tests/cpp/core/schema/test_full_body.cpp`
- :code-file:`tests/python/core/schema/test_full_body.py`
- :code-file:`examples/oxr/python/test_full_body_tracker.py`
- :code-file:`tests/python/xr_runtime/test_full_body_tracker.py`

- Examples:

Expand Down Expand Up @@ -409,7 +409,7 @@ utility internally.

- :code-file:`tests/cpp/core/schema/test_oak.cpp`
- :code-file:`tests/python/core/schema/test_camera.py`
- :code-file:`examples/oxr/python/test_oak_camera.py`
- :code-file:`tests/python/xr_runtime/test_oak_camera.py`

- Examples:

Expand Down Expand Up @@ -500,7 +500,7 @@ Usage Examples
For end-to-end usage patterns combining trackers with a ``DeviceIOSession``, see:

- **C++**: :code-file:`examples/oxr/cpp/oxr_simple_api_demo.cpp`
- **Python**: :code-file:`examples/oxr/python/modular_example.py`
- **Python**: :code-file:`examples/oxr/python/isaaccapture_examples/oxr/modular_example.py`

For higher-level usage with the teleop session manager and retargeting, see:

Expand Down
5 changes: 5 additions & 0 deletions docs/source/references/cloudxr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,14 @@ related environment variables unchanged. Use this when another runtime is alread
configured (for example Monado) or when a host singleton must not be duplicated
(see ``examples/robot_viz/README.md`` and ``--no-launch-cloudxr-runtime`` there).

``OpenXRSession`` refuses to start unless ``NV_CXR_RUNTIME_DIR`` and ``XR_RUNTIME_JSON``
are both set; ``ISAAC_TELEOP_DISABLE_CXR_ENV_CHECKS`` skips that check for a runtime
other than CloudXR:

.. code-block:: bash

export XR_RUNTIME_JSON=/path/to/your/openxr.json
export ISAAC_TELEOP_DISABLE_CXR_ENV_CHECKS=1
python examples/teleop/python/gripper_retargeting_example_simple.py --no-launch-cloudxr-runtime

Run the service in a container or CI
Expand Down
4 changes: 2 additions & 2 deletions examples/oxr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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

cmake_minimum_required(VERSION 3.20)
Expand All @@ -7,4 +7,4 @@ cmake_minimum_required(VERSION 3.20)
add_subdirectory(cpp)

include(${CMAKE_SOURCE_DIR}/cmake/InstallPythonExample.cmake)
install_python_example(DESTINATION examples/oxr/python)
install_python_example(DESTINATION examples/oxr)
73 changes: 42 additions & 31 deletions examples/oxr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,44 +31,48 @@ examples/oxr/
│ ├── CMakeLists.txt
│ ├── oxr_session_sharing.cpp
│ └── oxr_simple_api_demo.cpp
└── python/ # Python examples
├── pyproject.toml # uv configuration
├── pyproject.toml # the distribution
└── python/isaaccapture_examples/oxr/
├── __init__.py
├── modular_example.py
├── test_modular.py
├── test_extensions.py
└── test_session_sharing.py
└── modular_example_with_mcap.py
```

## Python Examples
The `test_*.py` scripts in [`tests/python/xr_runtime/`](../../tests/python/xr_runtime/)
exercise the same API. CloudXR GPU CI runs the ones listed in
[`scripts/run_tests_with_cloudxr.sh`](../../scripts/run_tests_with_cloudxr.sh).
To run one by hand, use `python tests/python/xr_runtime/<script>.py` from the
project root, sourcing the CloudXR environment first as for the C++ examples.
The scripts that start a plugin look in `install/plugins` after
`cmake --install build`, or pass `--plugin-root`.

Python examples use `uv` for dependency management and execution.
## Python Examples

### Running Python Examples

After building and installing, navigate to the installed examples:
Install `isaaccapture` from this build into a virtual environment made with the
build's Python and activated, as in
[Build from source, step 4](https://nvidia.github.io/IsaacCapture/main/development/build_from_source/index.html#install-the-isaaccapture-pip-package).
Then, from the project root, with `X.Y` the first two numbers of `VERSION`:

```bash
# From install directory (recommended)
cd install/examples/oxr/python
export XR_RUNTIME_JSON=/path/to/cloudxr/openxr_cloudxr-dev.json
uv run test_modular.py
uv pip install "isaaccapture[cloudxr]==X.Y+local" --find-links=./install/wheels/ --reinstall-package isaaccapture
uv pip install -e ./examples/oxr
python -m isaaccapture_examples.oxr.modular_example
python -m isaaccapture_examples.oxr.modular_example_with_mcap # writes recordings/tracking_recording_<timestamp>.mcap
```

Or run from source directory:

```bash
# From source directory (requires build to be complete)
cd examples/oxr/python
export XR_RUNTIME_JSON=/path/to/cloudxr/openxr_cloudxr-dev.json
uv run test_modular.py
```
Each module attaches to the running CloudXR runtime, or starts one in the
background and leaves it running; stop it with
`python -m isaaccapture.cloudxr.service stop`. The first start asks you to
accept the CloudXR EULA, and `--accept-eula` accepts it without the prompt. To
use a different OpenXR runtime, pass `--no-launch-cloudxr-runtime` as in
[Use a system OpenXR runtime](https://nvidia.github.io/IsaacCapture/main/references/cloudxr.html#use-a-system-openxr-runtime-no-cloudxr-attach).

### Available Python Examples

- **modular_example.py** - Basic hand + head tracking
- **test_modular.py** - Complete API test
- **test_extensions.py** - Extension query demonstration
- **test_session_sharing.py** - Session sharing between DeviceIOSession instances
- **modular_example** - Basic hand + head tracking
- **modular_example_with_mcap** - The same trackers recorded to an MCAP file, then replayed

## C++ Examples

Expand All @@ -88,8 +92,12 @@ cmake --install build
**oxr_session_sharing** - Demonstrates session sharing between multiple DeviceIOSession instances
**oxr_simple_api_demo** - Demonstrates the simple API

They do not start CloudXR. With the service running
(`python -m isaaccapture.cloudxr.service start --accept-eula`), source its
environment, which sets `XR_RUNTIME_JSON` and the `NV_CXR_*` variables:

```bash
export XR_RUNTIME_JSON=/path/to/cloudxr/openxr_cloudxr-dev.json
source ~/.cloudxr/run/cloudxr.env

# From build directory
./build/examples/oxr/cpp/oxr_session_sharing
Expand All @@ -109,10 +117,13 @@ cmake -B build
cmake --build build
cmake --install build

# Run Python example
cd install/examples/oxr/python
export XR_RUNTIME_JSON=/path/to/cloudxr/openxr_cloudxr-dev.json
uv run test_modular.py
# Run Python example. Replace 3.11 with your ISAAC_TELEOP_PYTHON_VERSION and
# X.Y with the first two numbers of VERSION.
uv venv --python 3.11 --seed .venv
source .venv/bin/activate
uv pip install "isaaccapture[cloudxr]==X.Y+local" --find-links=./install/wheels/ --reinstall-package isaaccapture
uv pip install -e ./examples/oxr
python -m isaaccapture_examples.oxr.modular_example
```

### C++ Example
Expand All @@ -121,8 +132,8 @@ uv run test_modular.py
cmake -B build
cmake --build build

# Run C++ example
export XR_RUNTIME_JSON=/path/to/cloudxr/openxr_cloudxr-dev.json
# Run C++ example, with the CloudXR service running
source ~/.cloudxr/run/cloudxr.env
./build/examples/oxr/cpp/oxr_session_sharing
```

Expand Down
23 changes: 23 additions & 0 deletions examples/oxr/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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 = "isaaccapture-examples-oxr"
version = "0.0.0" # Internal examples - not versioned
description = "OpenXR Tracking Python Examples"
requires-python = ">=3.11,<3.14"
dependencies = [
"isaaccapture[cloudxr]",
]

# `only-include` + `sources`, not `packages`, and no __init__.py above
# oxr -- see the packaging rules in examples/README.md.
[tool.hatch.build.targets.wheel]
only-include = ["python/isaaccapture_examples/oxr"]
sources = ["python"]
100 changes: 0 additions & 100 deletions examples/oxr/python/README.md

This file was deleted.

2 changes: 2 additions & 0 deletions examples/oxr/python/isaaccapture_examples/oxr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
Loading
Loading