Skip to content

Port examples to CloudXRLauncher#703

Merged
nv-jakob merged 1 commit into
NVIDIA:mainfrom
nv-jakob:jakob/port-examples-to-cloudxrlauncher
Jul 6, 2026
Merged

Port examples to CloudXRLauncher#703
nv-jakob merged 1 commit into
NVIDIA:mainfrom
nv-jakob:jakob/port-examples-to-cloudxrlauncher

Conversation

@nv-jakob

@nv-jakob nv-jakob commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #(issue)

Type of change

  • New feature (non-breaking change which adds functionality)

Testing

Checklist

  • I have read and understood the contribution guidelines
  • I have run the linter and formatter with SKIP=check-copyright-year pre-commit run --all-files
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix/feature works (or explained why not)
  • I have signed off all my commits (git commit -s) per the DCO

Summary by CodeRabbit

  • New Features

    • Added CloudXR launcher support across multiple examples, so live teleoperation and tracking flows can start and stop the required runtime automatically.
    • Added CLI options to control CloudXR startup behavior, including choosing an install directory and disabling automatic runtime launch.
    • Improved Windows support for shutting down CloudXR runtime processes cleanly.
  • Documentation

    • Updated example guidance to reflect the new automatic CloudXR startup flow.

@github-actions

Copy link
Copy Markdown
Contributor

📝 Docs preview is not auto-deployed for fork PRs.

A maintainer with write access to NVIDIA/IsaacTeleop can deploy a preview by
commenting /preview-docs on this PR. Once deployed, the preview
will live at:

https://nvidia.github.io/IsaacTeleop/preview/pr-703/

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f20ed021-bf97-4e74-b48c-98fea5705ef7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

CloudXRLauncher now exposes CLI helper methods and a launch_context(args) helper, and its shutdown path branches on Windows with a new direct-process terminator. Multiple example scripts now import the launcher and run their existing OpenXR or teleoperation flows inside with CloudXRLauncher(): or CloudXRLauncher.launch_context(args), and one example updates its runtime docs and timeout message. Tests cover the new argument helpers and Windows stop behavior.

Sequence Diagram(s)

sequenceDiagram
  participant ExampleMain as "main()"
  participant CloudXRLauncher
  participant CloudXRRuntime as "CloudXR runtime"
  participant TeleopSession
  participant OpenXRSession as "oxr.OpenXRSession"

  ExampleMain->>CloudXRLauncher: launch_context(args)
  CloudXRLauncher->>CloudXRRuntime: start runtime
  alt teleop example
    ExampleMain->>TeleopSession: run session loop
  else OpenXR example
    ExampleMain->>OpenXRSession: create and run session
  end
  ExampleMain->>CloudXRLauncher: exit context
  CloudXRLauncher->>CloudXRRuntime: stop runtime
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: updating examples to use CloudXRLauncher.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/teleop/python/joint_space_device_example.py (1)

217-229: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Start CloudXR before spawning the synthetic plugin.

The default flow now launches so101_leader_plugin before entering CloudXRLauncher.launch_context(args), so the plugin is asked to create/push against an OpenXR runtime that is not running yet. That makes --launch-plugin race or time out unless the user manually disables launcher startup and pre-starts CloudXR.

Suggested fix
     plugin_proc = None
-    if args.launch_plugin:
-        if not Path(args.plugin_bin).exists():
-            raise SystemExit(
-                f"plugin binary not found: {args.plugin_bin} (build it first)"
-            )
-        print(f"launching plugin: {args.plugin_bin}")
-        # Empty device_path -> synthetic backend; collection id must match the source.
-        plugin_proc = subprocess.Popen([args.plugin_bin, "", _COLLECTION_ID])
-        time.sleep(1.5)  # let it create its OpenXR session and start pushing
     try:
         with CloudXRLauncher.launch_context(args):
+            if args.launch_plugin:
+                if not Path(args.plugin_bin).exists():
+                    raise SystemExit(
+                        f"plugin binary not found: {args.plugin_bin} (build it first)"
+                    )
+                print(f"launching plugin: {args.plugin_bin}")
+                plugin_proc = subprocess.Popen([args.plugin_bin, "", _COLLECTION_ID])
+                time.sleep(1.5)
             run_live(args.mode, args.frames, args.urdf, args.ee_link, args.timeout)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/teleop/python/joint_space_device_example.py` around lines 217 - 229,
Move the CloudXR startup in joint_space_device_example.py so
CloudXRLauncher.launch_context(args) is entered before spawning the synthetic
plugin process. The current launch order in the main flow starts plugin_proc via
subprocess.Popen before the OpenXR runtime is available, which can make
--launch-plugin fail or race. Keep the existing plugin launch logic and cleanup,
but wrap the plugin startup and subsequent run_live call inside the
CloudXRLauncher.launch_context(args) block so the plugin sees a running
CloudXR/OpenXR session.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/oxr/python/modular_example.py`:
- Around line 80-108: The hand and head pose printing in modular_example.py only
checks data is not None, which still leaves possible missing joints or invalid
poses; update the left_tracked, right_tracked, and head_tracker handling to
verify the relevant pose/joints validity before dereferencing. Use the existing
tracker access points and the schema.HeadPoseTrackedT / hand tracking objects to
add the same stricter guard pattern used elsewhere, then only read pose.position
and print coordinates when the pose is valid.

---

Outside diff comments:
In `@examples/teleop/python/joint_space_device_example.py`:
- Around line 217-229: Move the CloudXR startup in joint_space_device_example.py
so CloudXRLauncher.launch_context(args) is entered before spawning the synthetic
plugin process. The current launch order in the main flow starts plugin_proc via
subprocess.Popen before the OpenXR runtime is available, which can make
--launch-plugin fail or race. Keep the existing plugin launch logic and cleanup,
but wrap the plugin startup and subsequent run_live call inside the
CloudXRLauncher.launch_context(args) block so the plugin sees a running
CloudXR/OpenXR session.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 72b405bd-aa93-41ce-9e26-419f3684510e

📥 Commits

Reviewing files that changed from the base of the PR and between 3276b5c and 84970ea.

📒 Files selected for processing (16)
  • examples/haptic_feedback/python/controller_haptic_example.py
  • examples/lerobot/record.py
  • examples/oxr/python/modular_example.py
  • examples/oxr/python/modular_example_with_mcap.py
  • examples/retargeting/python/dual_source_teleop_example.py
  • examples/retargeting/python/sharpa_hand_retargeter_demo.py
  • examples/retargeting/python/sources_example.py
  • examples/teleop/python/dex_bimanual_example.py
  • examples/teleop/python/full_bimanual_reordering_example.py
  • examples/teleop/python/isaac_lab_gripper_example.py
  • examples/teleop/python/joint_space_device_example.py
  • examples/teleop/python/se3_retargeting_example.py
  • examples/teleop_session_manager/python/message_channel_example.py
  • examples/teleop_session_manager/python/teleop_controls_simple_example.py
  • src/core/cloudxr/python/launcher.py
  • src/core/cloudxr_tests/python/test_launcher.py

Comment thread examples/oxr/python/modular_example.py
@nv-jakob nv-jakob force-pushed the jakob/port-examples-to-cloudxrlauncher branch 2 times, most recently from caba58a to 83a8409 Compare July 2, 2026 13:27
@nv-jakob nv-jakob changed the title Jakob/port examples to cloudxrlauncher Port examples to CloudXRLauncher Jul 2, 2026
@nv-jakob nv-jakob force-pushed the jakob/port-examples-to-cloudxrlauncher branch from 83a8409 to b08ccd5 Compare July 2, 2026 14:35
Wrap examples that need a running CloudXR runtime with CloudXRLauncher,
using the new --launch-cloudxr-runtime / --no-launch-cloudxr-runtime flags
where argparse is already present. Skips synthetic-plugin and mcap replay
examples that do not require a live runtime.

Signed-off-by: Jakob Bornecrantz <tbornecrantz@nvidia.com>
@nv-jakob nv-jakob force-pushed the jakob/port-examples-to-cloudxrlauncher branch from b08ccd5 to 6eceb26 Compare July 6, 2026 17:16
@nv-jakob nv-jakob enabled auto-merge (squash) July 6, 2026 17:17
@nv-jakob nv-jakob merged commit deba990 into NVIDIA:main Jul 6, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants