-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Support Multi-Backend for Demo Scripts #5938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
367804d
20100eb
49c5927
0679143
0b7e5eb
cc2b00b
02f996c
28fb841
e822c26
a93be33
13ec175
b0847bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,49 +13,60 @@ | |
|
|
||
| .. code-block:: bash | ||
|
|
||
| # Usage | ||
| ./isaaclab.sh -p scripts/demos/bin_packing.py --num_envs 32 | ||
| # Usage with default PhysX physics and default kit visualizer. | ||
| ./isaaclab.sh -p scripts/demos/bin_packing.py | ||
|
|
||
| # Usage with Newton visualizer and default PhysX physics. | ||
| ./isaaclab.sh -p scripts/demos/bin_packing.py --visualizer newton | ||
|
|
||
| # Usage with Newton (MJWarp) physics and default kit visualizer. | ||
| ./isaaclab.sh -p scripts/demos/bin_packing.py --physics newton_mjwarp | ||
|
|
||
| # Usage with Newton visualizer and Newton (MJWarp) physics. | ||
| ./isaaclab.sh -p scripts/demos/bin_packing.py --visualizer newton --physics newton_mjwarp | ||
|
|
||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| """Launch Isaac Sim Simulator first.""" | ||
|
|
||
| """Parse CLI first so we can decide whether to launch Isaac Sim Kit.""" | ||
|
|
||
| import argparse | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| from isaaclab.app import AppLauncher | ||
| from isaaclab.app import add_launcher_args, launch_simulation | ||
|
|
||
| # add argparse arguments | ||
| parser = argparse.ArgumentParser(description="Demo usage of RigidObjectCollection through bin packing example") | ||
| parser = argparse.ArgumentParser( | ||
| description="Demo usage of RigidObjectCollection through bin packing example", | ||
| conflict_handler="resolve", | ||
| ) | ||
| parser.add_argument("--num_envs", type=int, default=16, help="Number of environments to spawn.") | ||
| # append AppLauncher cli args | ||
| AppLauncher.add_app_launcher_args(parser) | ||
| # demos should open Kit visualizer by default | ||
| parser.add_argument("--physics", default="physx", choices=["physx", "newton_mjwarp"], help="Physics backend.") | ||
| add_launcher_args(parser) | ||
| parser.set_defaults(visualizer=["kit"]) | ||
| # parse the arguments | ||
| args_cli = parser.parse_args() | ||
|
|
||
| # launch omniverse app | ||
| app_launcher = AppLauncher(args_cli) | ||
| simulation_app = app_launcher.app | ||
|
|
||
| """Rest everything follows.""" | ||
|
|
||
| import math | ||
|
|
||
| import torch | ||
|
|
||
| ## | ||
| # Pre-defined configs | ||
| ## | ||
| from isaaclab_newton.physics import MJWarpSolverCfg, NewtonCfg | ||
|
|
||
| import isaaclab.sim as sim_utils | ||
| import isaaclab.utils.math as math_utils | ||
| from isaaclab.assets import AssetBaseCfg, RigidObjectCfg, RigidObjectCollection, RigidObjectCollectionCfg | ||
| from isaaclab.assets import AssetBaseCfg, RigidObjectCfg, RigidObjectCollectionCfg | ||
|
YizeWang marked this conversation as resolved.
|
||
| from isaaclab.physics import PhysicsCfg | ||
| from isaaclab.scene import InteractiveScene, InteractiveSceneCfg | ||
| from isaaclab.sim import SimulationContext | ||
| from isaaclab.utils import Timer | ||
| from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR | ||
| from isaaclab.utils.configclass import configclass | ||
|
|
||
| if TYPE_CHECKING: | ||
| from isaaclab.assets import RigidObjectCollection | ||
|
|
||
| ## | ||
| # Scene Configuration | ||
| ## | ||
|
|
@@ -131,7 +142,7 @@ class MultiObjectSceneCfg(InteractiveSceneCfg): | |
| # Instantiate four grocery variants per layer and replicate across all layers in each environment. | ||
| rigid_objects={ | ||
| f"Object_{label}_Layer{layer}": RigidObjectCfg( | ||
| prim_path=f"/World/envs/env_.*/Object_{label}_Layer{layer}", | ||
| prim_path=f"/World/envs/env_.*/Groceries/Object_{label}_Layer{layer}", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 Low: Prim path hierarchy change The prim path changed from This is fine for a fresh run, but could break:
Is there a corresponding change that creates the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Newton visualizer needs this change. Otherwise, objects cannot be properly visualized.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the clarification! That makes sense — if Newton visualizer requires this hierarchy for proper object rendering, then this is the right approach. The Good to go 👍
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the clarification! That makes sense — the Newton visualizer likely needs the intermediate Since this is a new demo script (not modifying an existing one), there are no pre-existing saved stages or path references to worry about. My concern about backward compatibility doesn't apply here. 👍 No further concerns on this change. |
||
| init_state=RigidObjectCfg.InitialStateCfg(pos=(x, y, 0.2 + (layer) * 0.2)), | ||
| spawn=GROCERIES.get(f"OBJECT_{label}"), | ||
| ) | ||
|
|
@@ -263,7 +274,7 @@ def build_grocery_defaults( | |
| ## | ||
|
|
||
|
|
||
| def run_simulator(sim: SimulationContext, scene: InteractiveScene) -> None: | ||
| def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene) -> None: | ||
| """Runs the simulation loop that coordinates spawn randomization and stepping. | ||
|
|
||
| Returns: | ||
|
|
@@ -295,8 +306,8 @@ def run_simulator(sim: SimulationContext, scene: InteractiveScene) -> None: | |
| # Precompute a helper mask to toggle objects between active and cached sets. | ||
| # Precompute XY bounds [[x_min,y_min],[x_max,y_max]] | ||
| bounds_xy = torch.as_tensor(BIN_XY_BOUND, device=device, dtype=spawn_poses_w.dtype) | ||
| # Simulation loop | ||
| while simulation_app.is_running(): | ||
| # Step while a visualizer window is still open (or none exist, e.g. headless); works for kit and newton. | ||
| while sim.is_headless_or_exist_active_visualizer(): | ||
| # Reset | ||
| if count % 250 == 0: | ||
| # reset counter | ||
|
|
@@ -343,27 +354,32 @@ def main() -> None: | |
| Returns: | ||
| None: The function drives the simulation for its side-effects. | ||
| """ | ||
| # Load kit helper | ||
| sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device) | ||
| sim = SimulationContext(sim_cfg) | ||
| # Set main camera | ||
| sim.set_camera_view((2.5, 0.0, 4.0), (0.0, 0.0, 2.0)) | ||
|
|
||
| # Design scene | ||
| scene_cfg = MultiObjectSceneCfg(num_envs=args_cli.num_envs, env_spacing=1.0, replicate_physics=True) | ||
| with Timer("[INFO] Time to create scene: "): | ||
| scene = InteractiveScene(scene_cfg) | ||
|
|
||
| # Play the simulator | ||
| sim.reset() | ||
| # Now we are ready! | ||
| print("[INFO]: Setup complete...") | ||
| # Run the simulator | ||
| run_simulator(sim, scene) | ||
| with launch_simulation(cfg=PhysicsCfg(), launcher_args=args_cli) as physics_cfg: | ||
| # The default newton mjwarp solver configuration needs to be tuned for this demo. | ||
| if isinstance(physics_cfg, NewtonCfg) and isinstance(physics_cfg.solver_cfg, MJWarpSolverCfg): | ||
| physics_cfg.solver_cfg.nconmax = 128 | ||
| physics_cfg.solver_cfg.naconmax = 2048 | ||
| physics_cfg.solver_cfg.njmax = 512 | ||
|
|
||
| # Load kit helper | ||
| sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device, physics=physics_cfg) | ||
| sim = sim_utils.SimulationContext(sim_cfg) | ||
| # Set main camera | ||
| sim.set_camera_view((2.5, 0.0, 4.0), (0.0, 0.0, 2.0)) | ||
|
|
||
| # Design scene | ||
| scene_cfg = MultiObjectSceneCfg(num_envs=args_cli.num_envs, env_spacing=1.0, replicate_physics=True) | ||
| with Timer("[INFO] Time to create scene: "): | ||
| scene = scene_cfg.class_type(scene_cfg) | ||
|
|
||
| # Play the simulator | ||
| sim.reset() | ||
| # Now we are ready! | ||
| print("[INFO]: Setup complete...") | ||
| # Run the simulator | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium: Indirect construction via Using
Is there a specific reason from isaaclab.scene import InteractiveScene
scene = InteractiveScene(scene_cfg)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ooctipus Could you please take a look here? I tried to avoid local imports. Not sure if there exists a better way to achieve.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for raising this @YizeWang — happy to share my thoughts while you wait for @ooctipus. Looking at the file, from isaaclab.scene import InteractiveScene, InteractiveSceneCfgSo unless there's a runtime reason the import needs to be deferred (e.g., the class identity changes depending on the active physics backend), you could simply use: scene = InteractiveScene(scene_cfg)…which would be consistent with the existing import and easier to follow. If there is a backend-aware dispatch happening (where # Use string_to_callable to allow backend-specific scene class resolution at runtime.
scene = string_to_callable("isaaclab.scene:InteractiveScene")(scene_cfg)Deferring to @ooctipus on whether the multi-backend machinery requires this indirection here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improved in the latest commit "Remove string_to_callable"
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, thanks for removing it! 👍
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, using |
||
| run_simulator(sim, scene) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| # run the main execution | ||
| main() | ||
| # close sim app | ||
| simulation_app.close() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 Low: Duplicated solver tuning configuration
This identical MJWarp solver configuration block (njmax, nconmax, ls_iterations, cone, impratio, ls_parallel, integrator, num_substeps) is repeated verbatim across
arms.py,bipeds.py, andhands.py.Consider extracting a shared helper or preset:
This reduces the maintenance burden when solver defaults change and makes it obvious which demos share physics characteristics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we want to expose the way to tune parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense — for demo scripts, having the tuning parameters explicit and self-contained is more instructive for users learning how to configure the solver. Keeping each demo standalone avoids an extra indirection that could obscure the workflow.
No objection from me. Thanks for clarifying!