Skip to content

Commit 4876327

Browse files
committed
Refactor warp bridge into pluggable rule pipeline; rename to --frontend
The adapter is now a sequence of CompatRule objects (resolve preset, drop sensors, promote SceneEntityCfg, swap mdp funcs, swap action class). New incompatibilities are added by writing a small rule subclass instead of editing the dispatcher. The CLI flag is renamed --manager → --frontend because the dispatch also covers direct envs: a stable manager-based cfg is adapted onto ManagerBasedRLEnvWarp; a direct task is verified to point at a warp env class and dispatched via gym.make. A stable direct cfg + --frontend=warp raises IncompatibleEnvError with the offending entry_point and a hint at the *-Direct-Warp-v0 alternative. Other fixes: - Forward render_mode through build() so --video keeps working. - Attach the CompatReport on env.unwrapped.warp_compat_report so callers can inspect what was dropped or left unresolved. - Assert the warp SceneEntityCfg subclasses the stable one before doing the in-place __class__ promotion; the rule fails loudly if the hierarchy is ever broken. - Narrow the bare except in mdp-module discovery so real ImportErrors from broken cfgs propagate. - presets=newton is now only auto-injected for stable manager-based tasks; direct warp tasks (which don't carry presets) are left alone. - Warn when the user passes presets=<other> with --frontend=warp. - Add the commands group to the rule that promotes SceneEntityCfg.
1 parent 1cab702 commit 4876327

3 files changed

Lines changed: 517 additions & 278 deletions

File tree

scripts/reinforcement_learning/rsl_rl/train.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@
6868
)
6969
parser.add_argument("--external_callback", default=None, help="Fully qualified path to an externally defined callback.")
7070
parser.add_argument(
71-
"--manager",
71+
"--frontend",
7272
type=str,
7373
default="stable",
7474
choices=["stable", "warp"],
7575
help=(
76-
"Manager-based env runtime. 'stable' uses isaaclab.envs.ManagerBasedRLEnv (torch);"
77-
" 'warp' adapts the same task cfg via isaaclab_experimental.envs.warp_frontend.WarpFrontend"
78-
" and runs on isaaclab_experimental.envs.ManagerBasedRLEnvWarp."
76+
"Runtime backend for the env. 'stable' uses isaaclab.envs.* (torch);"
77+
" 'warp' routes through isaaclab_experimental.envs.warp_frontend.WarpFrontend,"
78+
" which adapts a manager-based stable cfg onto ManagerBasedRLEnvWarp or dispatches"
79+
" a direct task to its registered warp env class."
7980
),
8081
)
8182
cli_args.add_rsl_rl_args(parser)
@@ -98,12 +99,29 @@
9899
# argparser and (optionally) the external callback function.
99100
remaining_args = list_intersection(remaining_args, remaining_args_env_registration)
100101

101-
# When the warp manager runtime is selected, the env cfg must resolve any
102-
# PresetCfg wrappers to their `newton` field (Hydra preset resolution runs
103-
# *before* the WarpFrontend adapter, so we inject the override here unless
104-
# the user already passed one explicitly).
105-
if args_cli.manager == "warp" and not any(a.startswith("presets=") for a in remaining_args):
106-
remaining_args.append("presets=newton")
102+
# When the warp frontend is selected on a stable manager-based task, the cfg
103+
# must resolve any PresetCfg wrappers to their ``newton`` field. Hydra
104+
# resolves presets *before* the WarpFrontend runs, so we inject
105+
# ``presets=newton`` here. We only inject for tasks registered under
106+
# ``isaaclab_tasks.manager_based`` — direct tasks and pre-warp registrations
107+
# don't carry a preset system, and injecting ``presets=newton`` against them
108+
# causes Hydra to error before the frontend can produce its own diagnostic.
109+
if args_cli.frontend == "warp" and args_cli.task is not None:
110+
try:
111+
_spec = gym.spec(args_cli.task)
112+
except gym.error.NameNotFound:
113+
_spec = None
114+
_entry = _spec.entry_point if _spec is not None else None
115+
_is_stable_manager = isinstance(_entry, str) and _entry.startswith("isaaclab_tasks.manager_based")
116+
_explicit_preset = next((a for a in remaining_args if a.startswith("presets=")), None)
117+
if _is_stable_manager and _explicit_preset is None:
118+
remaining_args.append("presets=newton")
119+
elif _is_stable_manager and _explicit_preset != "presets=newton":
120+
logger.warning(
121+
"--frontend=warp on %r expects presets=newton; got %r — adapter may fail to find a Newton physics cfg.",
122+
args_cli.task,
123+
_explicit_preset,
124+
)
107125

108126
sys.argv = [sys.argv[0]] + remaining_args
109127

@@ -190,14 +208,15 @@ def main(env_cfg: ManagerBasedRLEnvCfg | DirectRLEnvCfg | DirectMARLEnvCfg, agen
190208
env_cfg.log_dir = log_dir
191209

192210
# create isaac environment
193-
if args_cli.manager == "warp":
194-
# Lazy: this is the first warp-side import. Calling it after
195-
# SimulationApp is already alive avoids racing pxr extension init.
211+
render_mode = "rgb_array" if args_cli.video else None
212+
if args_cli.frontend == "warp":
213+
# Lazy: first warp-side import. Calling this after SimulationApp
214+
# is already alive avoids racing pxr extension init.
196215
from isaaclab_experimental.envs.warp_frontend import WarpFrontend
197216

198-
env = WarpFrontend().build(env_cfg, task_id=args_cli.task)
217+
env = WarpFrontend().build(env_cfg, task_id=args_cli.task, render_mode=render_mode)
199218
else:
200-
env = gym.make(args_cli.task, cfg=env_cfg, render_mode="rgb_array" if args_cli.video else None)
219+
env = gym.make(args_cli.task, cfg=env_cfg, render_mode=render_mode)
201220

202221
# convert to single-agent instance if required by the RL algorithm
203222
if isinstance(env.unwrapped.cfg, DirectMARLEnvCfg):

source/isaaclab_experimental/changelog.d/warp-manager-bridge.rst

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ Added
33

44
* Added :class:`~isaaclab_experimental.envs.warp_frontend.WarpFrontend`, a
55
runtime adapter that lets any stable manager-based RL task config run on the
6-
experimental warp manager runtime (:class:`~isaaclab_experimental.envs.ManagerBasedRLEnvWarp`)
7-
without a parallel ``-Warp-v0`` registration. The adapter resolves
8-
:class:`~isaaclab_physx.preset.PresetCfg` to its ``newton`` field, swaps
9-
``term.func`` references to same-named warp twins discovered in the warp
10-
``mdp`` modules (skipping stable re-exports), promotes ``SceneEntityCfg``
11-
instances in-place to the warp variant, and reports any missing twins
12-
before the env is built.
6+
experimental warp runtime (:class:`~isaaclab_experimental.envs.ManagerBasedRLEnvWarp`)
7+
without a parallel ``-Warp-v0`` registration. The adapter is built on a
8+
pluggable :class:`~isaaclab_experimental.envs.warp_frontend.CompatRule`
9+
pipeline; new incompatibilities (sensor types, term-cfg fields, action
10+
classes) are added by writing a small rule subclass instead of editing the
11+
dispatcher. The default rules cover physics-preset resolution, dropping
12+
unsupported sensors, in-place :class:`SceneEntityCfg` promotion, mdp
13+
function swaps, and action-class swaps. The frontend also dispatches
14+
direct envs by verifying their registered entry-point class lives under
15+
``isaaclab_experimental`` / ``isaaclab_tasks_experimental`` and routing
16+
through :func:`gym.make` unchanged.
1317

14-
* Added a ``--manager={stable,warp}`` flag to ``rsl_rl/train.py``. When set
18+
* Added a ``--frontend={stable,warp}`` flag to ``rsl_rl/train.py``. When set
1519
to ``warp`` the script auto-injects ``presets=newton`` (so Hydra picks the
16-
Newton physics preset before the adapter runs) and dispatches the env
17-
through ``WarpFrontend`` instead of ``gym.make``.
20+
Newton physics preset before the adapter runs), warns on conflicting
21+
``presets=`` overrides, and dispatches the env through ``WarpFrontend``
22+
instead of :func:`gym.make`. ``render_mode`` is forwarded so ``--video``
23+
keeps working under the warp frontend.
1824

1925
Fixed
2026
^^^^^

0 commit comments

Comments
 (0)