Jakob/port examples to cloudxrlauncher#703
Conversation
Expose argparse helpers so embedding apps and examples can default to launching the CloudXR runtime and WSS proxy, with --no-launch-cloudxr-runtime for environments where the runtime is already running. Signed-off-by: Jakob Bornecrantz <tbornecrantz@nvidia.com>
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>
|
📝 Docs preview is not auto-deployed for fork PRs. A maintainer with write access to |
📝 WalkthroughWalkthroughCloudXRLauncher now exposes CLI helper methods and a 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 winStart CloudXR before spawning the synthetic plugin.
The default flow now launches
so101_leader_pluginbefore enteringCloudXRLauncher.launch_context(args), so the plugin is asked to create/push against an OpenXR runtime that is not running yet. That makes--launch-pluginrace 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
📒 Files selected for processing (16)
examples/haptic_feedback/python/controller_haptic_example.pyexamples/lerobot/record.pyexamples/oxr/python/modular_example.pyexamples/oxr/python/modular_example_with_mcap.pyexamples/retargeting/python/dual_source_teleop_example.pyexamples/retargeting/python/sharpa_hand_retargeter_demo.pyexamples/retargeting/python/sources_example.pyexamples/teleop/python/dex_bimanual_example.pyexamples/teleop/python/full_bimanual_reordering_example.pyexamples/teleop/python/isaac_lab_gripper_example.pyexamples/teleop/python/joint_space_device_example.pyexamples/teleop/python/se3_retargeting_example.pyexamples/teleop_session_manager/python/message_channel_example.pyexamples/teleop_session_manager/python/teleop_controls_simple_example.pysrc/core/cloudxr/python/launcher.pysrc/core/cloudxr_tests/python/test_launcher.py
| if left_tracked.data is not None: | ||
| pos = left_tracked.data.joints.poses( | ||
| deviceio.JOINT_WRIST | ||
| ).pose.position | ||
| print( | ||
| f" Left wrist: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]" | ||
| ) | ||
| else: | ||
| print(" Left hand: inactive") | ||
|
|
||
| if right_tracked.data is not None: | ||
| pos = right_tracked.data.joints.poses( | ||
| deviceio.JOINT_WRIST | ||
| ).pose.position | ||
| print( | ||
| f" Right wrist: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]" | ||
| ) | ||
| else: | ||
| print(" Right hand: inactive") | ||
|
|
||
| # Get head data | ||
| head_tracked: schema.HeadPoseTrackedT = head_tracker.get_head( | ||
| session | ||
| ) | ||
| if head_tracked.data is not None: | ||
| pos = head_tracked.data.pose.position | ||
| print( | ||
| f" Head pos: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]" | ||
| ) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the reviewed file and the comparison file, then inspect relevant ranges.
git ls-files 'examples/oxr/python/modular_example.py' 'examples/lerobot/record.py' | cat
echo '--- modular_example.py ---'
wc -l examples/oxr/python/modular_example.py
sed -n '1,220p' examples/oxr/python/modular_example.py | cat -n | sed -n '1,180p'
echo '--- record.py ---'
wc -l examples/lerobot/record.py
sed -n '1,260p' examples/lerobot/record.py | cat -n | sed -n '1,220p'Repository: NVIDIA/IsaacTeleop
Length of output: 15884
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for the tracker and pose API definitions / usage to understand validity semantics.
rg -n "class .*HeadPoseTracked|class .*HandPoseTracked|def poses\(|is_valid|joints" \
examples src . -g '!**/.git/**' | sed -n '1,220p'Repository: NVIDIA/IsaacTeleop
Length of output: 25636
Guard invalid hand/head poses before reading them. data is not None still allows missing joints or invalid wrist/head poses, so these dereferences can raise or print bogus coordinates. Check joints/is_valid first, matching the stricter tracker handling used elsewhere.
🤖 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/oxr/python/modular_example.py` around lines 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.
Description
Fixes #(issue)
Type of change
Testing
Checklist
SKIP=check-copyright-year pre-commit run --all-filesgit commit -s) per the DCOSummary by CodeRabbit
New Features
Documentation