Skip to content

Support Demo Scripts With Multiple Backends#5771

Open
YizeWang wants to merge 11 commits into
isaac-sim:developfrom
YizeWang:yizew/minimal-change-demo-scripts-with-helper
Open

Support Demo Scripts With Multiple Backends#5771
YizeWang wants to merge 11 commits into
isaac-sim:developfrom
YizeWang:yizew/minimal-change-demo-scripts-with-helper

Conversation

@YizeWang
Copy link
Copy Markdown

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
List any dependencies that are required for this change.

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (existing functionality will not work without user modification)
  • Documentation update

Screenshots

Please attach before and after screenshots of the change if applicable.

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the changelog and the corresponding version in the extension's config/extension.toml file
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

Signed-off-by: Yize Wang <yizew@nvidia.com>
@YizeWang YizeWang requested a review from ooctipus as a code owner May 25, 2026 16:53
@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label May 25, 2026
Copy link
Copy Markdown

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Choose a reason for hiding this comment

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


Follow-up Review (a427283): New commits address several concerns and add new features.

✅ Issues Resolved

  1. has_no_alive_visualizer_window infinite loop — FIXED 🎉

    • Old: bool(sim.visualizers and not any(v.is_running() and not v.is_closed for v in sim.visualizers))
    • New: visualizers = sim.visualizers or () + return not any(...)
    • Empty/None visualizers now correctly return True ("no alive windows"), allowing the loop to exit. This was the most critical issue from the previous review.
  2. PhysX + Newton visualizer combination — NOW SUPPORTED

    • Previous TODO ("Not supported yet. Investigation needed.") has been implemented
    • Comment clarifies: "PhysX still launches Isaac Sim Kit headless because it depends on Kit extensions"
    • The if viz_type == "kit" or args.physics == "physx" condition correctly handles this case
  3. Code simplification

    • dt folded directly into SimulationCfg(dt=0.005, ...) — cleaner
    • Articulation instantiation simplified: Articulation(CFG.replace(...)) instead of intermediate _cfg variables
    • Loop condition cleaner: while not has_no_alive_visualizer_window(sim): instead of break-inside-while-True

🆕 New Additions

  1. get_usage_examples() helper function — Extracts bash examples from docstrings for argparse epilog. Nice UX improvement for --help output.

  2. Expanded docstring examples — More usage combinations documented (physx+kit, physx+newton, newton_mjwarp+kit, etc.)

  3. Stricter visualizer validationif not isinstance(args.visualizer, list) or len(args.visualizer) != 1: raise ValueError(...) — Explicit error instead of silent fallback

⚠️ Remaining Concerns (from original review)

  1. Relative import from demo_helper import ... — Still assumes working directory is scripts/demos/. This may break if invoked from a different directory.

  2. args.visualizer = [viz_type] mutation — Still present in resolve_backend_and_visualizer (L65). The helper mutates the args namespace before passing to AppLauncher.

  3. conflict_handler="resolve" removal — Good: this was removed. But parser.set_defaults(visualizer=["kit"]) now sets a default that may conflict with AppLauncher's --visualizer handling. Worth verifying this doesn't cause issues.

  4. No tests added — PR still lacks unit tests for the new helper functions.

📋 Summary

Previous Issues Status
Infinite loop in has_no_alive_visualizer_window ✅ Fixed
PhysX + Newton visualizer unsupported ✅ Fixed
Relative import fragility ⏳ Not addressed
Args mutation side-effect ⏳ Not addressed
No tests ⏳ Not addressed

Verdict: The critical infinite loop bug is fixed 🎉. The remaining concerns are minor/stylistic. This looks much better than before.


🤖 Follow-up review by Isaac Lab Review Bot


Update (b20cdab): New commits add two documentation comments to scripts/demos/quadrupeds.py:

  • Comment explaining why Kit visualizer is the default
  • Comment before main() call

These are purely cosmetic changes — no functional code modified. Previous concerns remain unchanged (see summary table above). No new issues.


Update (5e57982): Added physx_cfg parameter to resolve_backend_and_visualizer(), allowing callers to pass custom PhysX configuration instead of always using default PhysxCfg(). Clean enhancement with backward compatibility (parameter is optional). No new issues.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR extracts a demo_helper.py module and updates quadrupeds.py to allow demo scripts to select a physics backend (physx or newton_mjwarp) and visualizer (kit or newton) independently via CLI flags, deferring Kit launch until the context manager decides it is required.

  • demo_helper.py (new): introduces resolve_backend_and_visualizer (a context manager that resolves physics/visualizer configs and conditionally launches Kit), has_no_alive_visualizer_window (loop-exit predicate), and get_usage_examples (argparse epilog helper).
  • quadrupeds.py: removes the hard-coded AppLauncher startup at module level and replaces the while simulation_app.is_running() loop with the backend-agnostic while not has_no_alive_visualizer_window(sim) condition, wrapping simulation setup inside the new context manager.

Confidence Score: 5/5

Safe to merge — the changes are additive, the loop-exit predicate is consistent with existing scripts, and the context manager correctly defers Kit launch without leaking resources.

The refactoring is narrowly scoped to the demo layer. is_closed is a @property on BaseVisualizer so the predicate in has_no_alive_visualizer_window is correct. The or () fallback for an empty visualizers list correctly lets the loop exit, matching the pattern in zero_agent.py and random_agent.py. AppLauncher is kept alive by the signal handlers it registers during construction, so the immediate discard of the instance after capturing .app.close does not cause premature cleanup. No wrong-data, stale-state, or resource-leak paths were found.

No files require special attention.

Important Files Changed

Filename Overview
scripts/demos/demo_helper.py New helper module: resolve_backend_and_visualizer context manager, has_no_alive_visualizer_window predicate (is_closed is correctly a @Property), and get_usage_examples parser helper. Logic is sound and consistent with existing codebase patterns.
scripts/demos/quadrupeds.py Updated to use the new helper; Kit launch deferred into the context manager, loop-exit predicate replaced, imports of sim-extension types moved inside functions so they load only after Kit (or Newton) is ready.

Reviews (2): Last reviewed commit: "Recover 2 Comments" | Re-trigger Greptile

Comment thread scripts/demos/demo_helper.py Outdated
Comment thread scripts/demos/demo_helper.py Outdated
Comment on lines +57 to +61
if needs_kit:
from isaaclab.app import AppLauncher

args.visualizer = [viz_type]
close_fn = AppLauncher(args).app.close
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.

P2 Mutable side-effect on caller's args namespace

args.visualizer is mutated in-place from a str (as parsed by the script's own --visualizer argument) to a list before AppLauncher is constructed. This leaks into the caller's namespace after the context manager exits and makes resolve_backend_and_visualizer non-reentrant. Using a shallow copy of the namespace would contain the mutation to the helper.

Suggested change
if needs_kit:
from isaaclab.app import AppLauncher
args.visualizer = [viz_type]
close_fn = AppLauncher(args).app.close
if needs_kit:
from isaaclab.app import AppLauncher
import copy
kit_args = copy.copy(args)
kit_args.visualizer = [viz_type]
close_fn = AppLauncher(kit_args).app.close

Signed-off-by: Yize Wang <yizew@nvidia.com>
Copy link
Copy Markdown
Collaborator

@hujc7 hujc7 left a comment

Choose a reason for hiding this comment

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

Maybe need to add some smoke test generally for demos?

Comment thread scripts/demos/quadrupeds.py
Comment thread scripts/demos/quadrupeds.py Outdated
return scene_entities, origins


def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, Articulation], origins: torch.Tensor):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Any reason to remove the type hint here?

Copy link
Copy Markdown
Author

@YizeWang YizeWang May 27, 2026

Choose a reason for hiding this comment

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

Same reason as my last comment: https://github.com/isaac-sim/IsaacLab/pull/5771/changes#r3310474409. These types are not defined yet (these packages not imported). Let me know if my understanding in the previous comment is wrong.

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.

I think we can use from __future__ import annotations and type checking for this. shouldn't be necessary to remove the type hints

Comment thread scripts/demos/quadrupeds.py
Comment thread scripts/demos/quadrupeds.py Outdated
Yize Wang added 2 commits May 27, 2026 16:33
Signed-off-by: Yize Wang <yizew@nvidia.com>
Signed-off-by: Yize Wang <yizew@nvidia.com>
Comment thread scripts/demos/quadrupeds.py Outdated
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics newton_mjwarp --visualizer newton

# Usage with the PhysX backend without Kit (launches Newton visualizer).
# TODO(yizew@nvidia.com): Not supported yet. Investigation needed.
Copy link
Copy Markdown
Author

@YizeWang YizeWang May 27, 2026

Choose a reason for hiding this comment

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

Is physx + newton expected to work by design? physx seems dependent on IsaacSim. I need to properly resolve this dependency if we want this pair to work.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Was it just the kit launch? or there are other issues?

Copy link
Copy Markdown
Collaborator

@hujc7 hujc7 May 27, 2026

Choose a reason for hiding this comment

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

nit: ideally this help message should also show up when run with -h/--help

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added help messages in the "Append Usage Examples to Help Menu" commit.

Comment thread scripts/demos/quadrupeds.py Outdated
Comment thread scripts/demos/quadrupeds.py
Yize Wang added 3 commits May 27, 2026 19:20
Signed-off-by: Yize Wang <yizew@nvidia.com>
Signed-off-by: Yize Wang <yizew@nvidia.com>
Signed-off-by: Yize Wang <yizew@nvidia.com>
Comment thread scripts/demos/quadrupeds.py
Comment thread scripts/demos/demo_helper.py Outdated
Comment thread scripts/demos/demo_helper.py Outdated
Comment thread scripts/demos/quadrupeds.py Outdated
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics newton_mjwarp --visualizer newton

# Usage with the PhysX backend without Kit (launches Newton visualizer).
# TODO(yizew@nvidia.com): Not supported yet. Investigation needed.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Was it just the kit launch? or there are other issues?

Yize Wang added 3 commits May 28, 2026 10:07
Signed-off-by: Yize Wang <yizew@nvidia.com>
Signed-off-by: Yize Wang <yizew@nvidia.com>
Signed-off-by: Yize Wang <yizew@nvidia.com>
Comment thread scripts/demos/demo_helper.py Outdated


@contextmanager
def resolve_backend_and_visualizer(args, newton_cfg=None):
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The option is limited inside ["kit", "newton"], to avoid dealing with rerun or vizer and to minimize the branches in demo_helper.py. Please let me know if these 2 visualizers are also supposed to be supported.

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.

I think it'd be nice to also support rerun and viser so that we can be consistent across all the scripts

@hujc7
Copy link
Copy Markdown
Collaborator

hujc7 commented May 28, 2026

@greptileai review

# Resolve visualizer cfg
if not isinstance(args.visualizer, list) or len(args.visualizer) != 1:
raise ValueError("Demos support exactly one --visualizer value: kit or newton.")
viz_type = args.visualizer[0]
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.

why do we only parse the first element? is there a limitation to supporting multiple visualizers like the training scripts?

elif args.physics == "newton_mjwarp":
from isaaclab_newton.physics import MJWarpSolverCfg, NewtonCfg

DEFAULT_NEWTON_CFG = NewtonCfg(
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.

how generalizable is this cfg? do we expect this to work for most scripts? if not, it may be better to just keep this as a default MjWarpSolverCfg() object.

Comment thread scripts/demos/demo_helper.py Outdated


@contextmanager
def resolve_backend_and_visualizer(args, newton_cfg=None):
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.

I think it'd be nice to also support rerun and viser so that we can be consistent across all the scripts

# Simulate physics
while simulation_app.is_running():
# Exit when every visualizer window has been closed (works for kit and newton)
while not has_no_alive_visualizer_window(sim):
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.

the double negative can be a bit confusing. would it make sense to make the utility has_alive_visualizer_window instead?

Comment thread scripts/demos/quadrupeds.py
return scene_entities, origins


def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, Articulation], origins: torch.Tensor):
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.

I think we can use from __future__ import annotations and type checking for this. shouldn't be necessary to remove the type hints

Comment on lines +11 to +26
# Usage with the default PhysX backend (launches Isaac Sim Kit by default).
./isaaclab.sh -p scripts/demos/quadrupeds.py
./isaaclab.sh -p scripts/demos/quadrupeds.py --visualizer kit
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics physx
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics physx --visualizer kit

# Usage with the kit-less Newton (MJWarp) backend (launches Isaac Sim Kit by default).
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics newton_mjwarp
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics newton_mjwarp --visualizer kit

# Usage with the Newton (MJWarp) backend without Kit (launches Newton visualizer).
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics newton_mjwarp --visualizer newton

# Usage with the PhysX backend and Newton visualizer.
# PhysX still launches Isaac Sim Kit headless because it depends on Kit extensions.
./isaaclab.sh -p scripts/demos/quadrupeds.py --physics physx --visualizer newton
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this could be simplified a bit to avoid duplicates

Signed-off-by: Yize Wang <yizew@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants