Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
23a0eb8
fix(cloudxr): refuse to start over a live runtime; explain -35
jiwenc-nv Aug 5, 2026
1c2b928
refactor(cloudxr): extract CloudXRService as the runtime's sole owner
jiwenc-nv Aug 8, 2026
c54b4ef
feat(cloudxr): add the service CLI and its systemd user service
jiwenc-nv Aug 8, 2026
a76d946
refactor(cloudxr): detach the service with setsid instead of systemd
jiwenc-nv Aug 8, 2026
81d2826
feat(cloudxr): give start and status the same summary as run
jiwenc-nv Aug 8, 2026
efebaf4
fix(cloudxr): stop status choking on the service's own command line
jiwenc-nv Aug 8, 2026
f27feef
feat(cloudxr): make CloudXRLauncher attach rather than own
jiwenc-nv Aug 8, 2026
922702d
feat(cloudxr): start a detached service when none is running
jiwenc-nv Aug 8, 2026
21bd532
refactor(cloudxr): retire --no-launch-cloudxr-runtime, and stop telli…
jiwenc-nv Aug 8, 2026
a3602bd
refactor(rig): let the CloudXR service own the runtime
jiwenc-nv Aug 8, 2026
a27d629
feat(teleop_ros2): own the CloudXR runtime with run_embedded
jiwenc-nv Aug 8, 2026
fc47f8c
fix(rig): stub CloudXR by injecting the module, not patching it
jiwenc-nv Aug 8, 2026
d8d9705
test(cloudxr): keep the service CLI tests off the GPU driver
jiwenc-nv Aug 8, 2026
15c43f8
refactor(cloudxr): point the live-runtime error at the service CLI
jiwenc-nv Aug 8, 2026
20d3725
docs(cloudxr): point the device and example guides at the service CLI
jiwenc-nv Aug 8, 2026
70709f9
docs(oglo_tactile): make the runtime a setup step, not a terminal
jiwenc-nv Aug 8, 2026
4e440f1
docs(cloudxr): make the runtime a service the docs can point at
jiwenc-nv Aug 8, 2026
7b9f91f
docs(cloudxr): refresh the startup screenshot for the service CLI
jiwenc-nv Aug 8, 2026
e6be203
feat(cloudxr): name the settings an ignored env config would have cha…
jiwenc-nv Aug 8, 2026
1ebb1f8
feat(cloudxr): hold the terminal when an env config is ignored
jiwenc-nv Aug 8, 2026
1dca64a
feat(cloudxr): animate the env-config pause so it reads as a wait
jiwenc-nv Aug 8, 2026
152cfe6
fix(cloudxr): stop the container images riding the deprecated entry p…
jiwenc-nv Aug 9, 2026
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: 4 additions & 1 deletion deps/cloudxr/runtime/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ set -e
mkdir -p /openxr/.cloudxr/run
printf 'accepted\n' > /openxr/.cloudxr/run/eula_accepted

exec python -m isaacteleop.cloudxr
# `run`, not `start`: the service must stay in the foreground as the
# container's main process. `start` detaches and returns, which would exit
# the container and take the runtime with it.
exec python -m isaacteleop.cloudxr.service run
4 changes: 2 additions & 2 deletions docs/source/_static/cloudxr-run-output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/source/device/body_tracking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ 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``. Running
``python -m isaacteleop.rig rigs/full_body.yaml`` starts the CloudXR runtime,
this printer, and the C++ MCAP recorder together in one tmux window (see
:ref:`rig-launcher`).
``python -m isaacteleop.rig rigs/full_body.yaml`` runs this printer and the C++
MCAP recorder together in one tmux window, against the CloudXR runtime it makes
sure is serving first (see :ref:`rig-launcher`).

Troubleshooting
~~~~~~~~~~~~~~~
Expand Down
7 changes: 4 additions & 3 deletions docs/source/device/haptic_feedback.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ a single controller tracker and there is no OpenXR action-set contention.
Running
-------

The example connects through the CloudXR / OpenXR runtime, so start the runtime
first (see :ref:`run-cloudxr-server`) and run the example from the
``examples/haptic_feedback/python`` directory:
The example connects through the CloudXR / OpenXR runtime, which it starts
itself if nothing is serving (see :ref:`dedicated-cloudxr-runtime` to manage
that service yourself). Run it from the ``examples/haptic_feedback/python``
directory:

.. code-block:: bash

Expand Down
6 changes: 3 additions & 3 deletions docs/source/device/haptikos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ Step 4: Run the plugin

The Haptikos plugin connects to the Teleop session through the CloudXR / OpenXR runtime, so the runtime must be running and its environment sourced in the shell that launches the plugin.

In one terminal, start the CloudXR runtime (keep it running for the duration of the session):
Start the CloudXR runtime. It runs as a background service that outlives this shell, until you stop it with ``python -m isaacteleop.cloudxr.service stop``:

.. code-block:: bash

source isaac_teleop_env/bin/activate
python -m isaacteleop.cloudxr
python -m isaacteleop.cloudxr.service start

In a second terminal, source the environment file that the runtime writes on startup. This points the OpenXR loader at CloudXR:
In the shell that runs the plugin, source the environment file that the runtime writes on startup. This points the OpenXR loader at CloudXR:

.. code-block:: bash

Expand Down
16 changes: 8 additions & 8 deletions docs/source/device/manus.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,23 +128,23 @@ The MANUS plugin connects to the Teleop session through the CloudXR / OpenXR
runtime, so the runtime must be running and its environment sourced in the
shell that launches the plugin.

In one terminal, start the CloudXR runtime (keep it running for the duration
of the session):
Start the CloudXR runtime. It runs as a background service that outlives
this shell, until you stop it with ``python -m isaacteleop.cloudxr.service stop``:

.. code-block:: bash

python -m isaacteleop.cloudxr
python -m isaacteleop.cloudxr.service start

In the terminal you will use to run the plugin, source the environment file
In the shell you will use to run the plugin, source the environment file
that the runtime writes on startup. This points the OpenXR loader at CloudXR:

.. code-block:: bash

source ~/.cloudxr/run/cloudxr.env

See :ref:`run-cloudxr-server` and :ref:`whitelist-firewall-ports`
in the Quick Start for the full CloudXR runtime setup, including EULA
acceptance and firewall configuration.
See :ref:`dedicated-cloudxr-runtime` for the full CloudXR service setup,
including EULA acceptance, and :ref:`whitelist-firewall-ports` in the Quick
Start for firewall configuration.

2. Verify with the CLI tool
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -269,7 +269,7 @@ Troubleshooting
* - No data received
- Ensure MANUS Core is running and the gloves are connected and calibrated.
* - CloudXR runtime errors
- Make sure the CloudXR runtime is running (``python -m isaacteleop.cloudxr``)
- Check that a runtime is serving with ``python -m isaacteleop.cloudxr.service status``,
and that ``~/.cloudxr/run/cloudxr.env`` has been sourced in the same
terminal as the plugin.
* - Permission denied for USB devices
Expand Down
11 changes: 4 additions & 7 deletions docs/source/device/wuji_glove.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,12 @@ the plugin:

.. code-block:: bash

python -m isaacteleop.cloudxr # terminal 1, keep running

.. code-block:: bash

source ~/.cloudxr/run/cloudxr.env # terminal 2
python -m isaacteleop.cloudxr.service start # runs in the background
source ~/.cloudxr/run/cloudxr.env
./build/src/plugins/wuji_glove/wuji_glove_plugin

See :ref:`run-cloudxr-server` and :ref:`load-cloudxr-environment-variables` for
the full runtime setup. The plugin resolves each glove's side from device
See :ref:`dedicated-cloudxr-runtime` and
:ref:`load-cloudxr-environment-variables` for the full service setup. The plugin resolves each glove's side from device
metadata and reconnects automatically after a disconnect; applications can also
launch it through its ``plugin.yaml`` using ``TeleopSession``.

Expand Down
6 changes: 3 additions & 3 deletions docs/source/getting_started/lerobot/data_collection_real.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ Follow the necessary one-time steps to set up your environment and hardware:

hf auth login

#. Accept the CloudXR EULA once. The runtime auto-launches on connect and prompts for the EULA on
stdin, which would hang a headless run, so accept it ahead of time:
#. Accept the CloudXR EULA once and start the runtime. The EULA prompts on stdin, which would hang
a headless run, so do both ahead of time; the service outlives each script you run below:

.. code-block:: bash

python -m isaacteleop.cloudxr --accept-eula
python -m isaacteleop.cloudxr.service start --accept-eula

Teleop and data recording
-------------------------
Expand Down
40 changes: 22 additions & 18 deletions docs/source/getting_started/quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,33 @@ See :doc:`build_from_source/index` for more details.
3. Configure CloudXR (optional)
-------------------------------

The teleop examples in this guide auto-launch the CloudXR runtime and its WSS
proxy for you through ``CloudXRLauncher`` when they connect — you do **not**
need to start the runtime in a separate terminal or source any environment file.
The teleop examples in this guide bring CloudXR up for you when they connect —
you do **not** need to start the runtime in a separate terminal or source any
environment file. If nothing is serving yet, the example starts a CloudXR
service in the background and prints how to stop it; that service outlives the
example, so the headset stays connected from one run to the next.
The first launch downloads the CloudXR Web Client SDK and asks you to review and
accept the EULA on the terminal; answer the prompt once and the acceptance is
remembered for subsequent runs.

The CloudXR runtime uses the ``auto-webrtc`` device profile by default
(Pico & Quest). For Apple Vision Pro it defaults to ``auto-native``. To
override settings, write a ``KEY=value`` env file and pass it to the example
with ``--cloudxr-env-config``:
The CloudXR runtime uses the ``Quest3`` device profile by default; Apple Vision
Pro needs ``auto-native``. The profile is set on the *runtime*, so applications
inherit whatever the runtime they connect to was started with. To override it,
or any other setting, write a ``KEY=value`` env file and start the service with
it:

.. code-block:: bash

echo 'NV_DEVICE_PROFILE=auto-native' > custom.env
python examples/teleop/python/gripper_retargeting_example_simple.py \
--cloudxr-env-config ./custom.env

The teleop examples under ``examples/teleop/python/`` all register CloudXR's
launcher arguments through ``CloudXRLauncher.add_launcher_arguments()``, so
the same ``--cloudxr-env-config`` flag is available on each of them. (The ROS 2
example takes the equivalent ``cloudxr_env_config`` ROS parameter instead.)
python -m isaacteleop.cloudxr.service start --cloudxr-env-config ./custom.env

The same ``--cloudxr-env-config`` flag is available on the teleop examples under
``examples/teleop/python/``, which register CloudXR's launcher arguments through
``CloudXRLauncher.add_launcher_arguments()`` — but it applies only when the
example is the one starting the runtime. With a service already running the
example attaches to it instead, and prints which settings it had to ignore (see
:doc:`/references/cloudxr`). (The ROS 2 example takes the equivalent
``cloudxr_env_config`` ROS parameter instead.)
To inspect the resolved settings after startup:

.. code-block:: bash
Expand All @@ -131,9 +136,8 @@ To inspect the resolved settings after startup:

.. note::

If you prefer to run the runtime yourself in its own terminal — e.g. to keep
the headset connection alive across example restarts, or to use launch modes
like ``--host-client`` and ``--setup-oob`` — see
To manage the service yourself — check what is running, stop it, or use
launch modes like ``--host-client`` and ``--setup-oob`` — see
:doc:`/references/cloudxr`.

.. list-table:: Environment variables
Expand All @@ -145,7 +149,7 @@ To inspect the resolved settings after startup:
- Description
- Values
* - ``NV_DEVICE_PROFILE``
- ``auto-webrtc``
- ``Quest3``
- Device profile
- ``auto-webrtc``, ``auto-native``, ``Quest3``, ``AppleVisionPro``
* - ``NV_CXR_ENABLE_PUSH_DEVICES``
Expand Down
11 changes: 5 additions & 6 deletions docs/source/references/camera_streaming.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ CloudXR stream them efficiently (see
CloudXR runtime flags
---------------------

In XR mode the viewer launches the CloudXR runtime and WSS proxy itself. Useful flags:
In XR mode the viewer attaches to the running CloudXR runtime, or starts one if none is
serving. Useful flags:

- ``--no-launch-cloudxr-runtime`` — reuse an already-running runtime.
- ``--accept-eula`` — accept the CloudXR EULA non-interactively (first run only).
- ``--cloudxr-device-profile PROFILE`` — ``NV_DEVICE_PROFILE`` (default ``Quest3``).

Expand Down Expand Up @@ -351,10 +351,9 @@ YAML per source kind.
Troubleshooting
---------------

- **The XR session fails to create** — the viewer launches the CloudXR runtime itself; check
``~/.cloudxr/logs/cxr_server.*.log`` and ``runtime_stderr.log`` for the startup failure. If a
runtime is already running from another app, pass ``--no-launch-cloudxr-runtime``. Pass
``--mode window`` to render to a desktop window instead (no runtime involved).
- **The XR session fails to create** — check ``~/.cloudxr/logs/cxr_server.*.log`` and
``runtime_stderr.log`` for the startup failure. Pass ``--mode window`` to render to a
desktop window instead (no runtime involved).
- **No window appears over SSH** — ``--mode window`` needs a local display; run on the machine
you're sitting at, or use a video-capable remote desktop.
- **"video source: no such file"** — relative ``path:`` values resolve against the YAML's
Expand Down
Loading
Loading