diff --git a/source/isaaclab_tasks/changelog.d/jichuanh-cartpole-presets.minor.rst b/source/isaaclab_tasks/changelog.d/jichuanh-cartpole-presets.minor.rst new file mode 100644 index 000000000000..c9a1f8795734 --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/jichuanh-cartpole-presets.minor.rst @@ -0,0 +1,38 @@ +Added +^^^^^ + +* Added four consolidated Cartpole perception tasks that subsume 35 + per-variant task IDs via the typed preset CLI (#5587): + ``Isaac-Cartpole-Camera-Direct-v0``, ``Isaac-Cartpole-Camera-v0``, + ``Isaac-Cartpole-Showcase-Direct-v0``, and + ``Isaac-Cartpole-Camera-Showcase-Direct-v0``. Variant (data type, + observation pipeline, gym-space shape) selected at runtime via + ``presets=``; agent yaml selected via + ``--agent=`` for the manager perception feature + policies and all non-default showcase shapes. +* Added a ``deprecated`` convention for retired gym task registrations: + a ``gym.register`` kwarg with shape + ``{"alias": "--task=NEW [--agent=NAME] presets=NAME"}`` holding the + equivalent migration command. The dict shape is open for future + fields (``reason``, ``removed_in``, ...). :func:`isaaclab_tasks.utils.parse_cfg.load_cfg_from_registry` + reads ``kwargs["deprecated"]["alias"]`` when loading an + ``env_cfg_entry_point`` and emits a :class:`DeprecationWarning` + naming the new command. + +Deprecated +^^^^^^^^^^ + +* Deprecated 35 per-variant Cartpole task IDs (7 Direct-backend camera, + 4 manager-based camera, 15 proprioceptive showcase, 9 camera-based + showcase) in favor of the four consolidated tasks above. Each retired + ID still loads and emits a :class:`DeprecationWarning` naming the + consolidated task and the equivalent ``presets=`` (plus + ``--agent=`` where required) invocation. The + ``env_cfg_entry_point`` of each retired ID keeps pointing at the + historical per-variant cfg subclass so retired IDs stay bit-for-bit + identical to their pre-deprecation behavior; only the deprecation + warning is layered on top via the new ``deprecated`` kwarg. The historical subclasses (e.g. ``CartpoleRGBCameraEnvCfg``, + ``CartpoleAlbedoCameraEnvCfg``, ``BoxBoxEnvCfg``, ...) are kept for + one release alongside the consolidated cfgs and will be removed + together with the retired task IDs. Full migration table is in the + PR description. diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/__init__.py index b1b8fdbf35b5..0a4937d5351c 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/__init__.py @@ -28,12 +28,32 @@ }, ) +gym.register( + id="Isaac-Cartpole-Camera-Direct-v0", + entry_point=f"{__name__}.cartpole_camera_presets_env:CartpoleCameraPresetsEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": f"{__name__}.cartpole_camera_presets_env_cfg:CartpoleCameraPresetsEnvCfg", + "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", + "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", + }, +) + + +# Retired per-data-type camera task IDs. Each carries a ``deprecated`` kwarg +# whose ``alias`` field names the consolidated task with the equivalent +# ``presets=`` -- parse_cfg.load_cfg_from_registry consults that kwarg +# and emits a DeprecationWarning when the retired ID's env cfg is loaded. +# The ``env_cfg_entry_point`` keeps pointing at the historical per-variant +# cfg so the retired ID stays bit-for-bit identical to develop. + gym.register( id="Isaac-Cartpole-RGB-Camera-Direct-v0", entry_point=f"{__name__}.cartpole_camera_env:CartpoleCameraEnv", disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleRGBCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=rgb"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -45,6 +65,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleAlbedoCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=albedo"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -56,6 +77,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleSimpleShadingConstantCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=simple_shading_constant_diffuse"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -67,6 +89,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleSimpleShadingDiffuseCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=simple_shading_diffuse_mdl"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -78,6 +101,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleSimpleShadingFullCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=simple_shading_full_mdl"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -89,6 +113,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleDepthCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=depth"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, @@ -99,7 +124,11 @@ entry_point=f"{__name__}.cartpole_camera_presets_env:CartpoleCameraPresetsEnv", disable_env_checker=True, kwargs={ + # The retired catch-all points at the same consolidated cfg as the + # canonical task above; the Hydra resolver applies any user-CLI + # presets the user passes alongside this ID, matching develop. "env_cfg_entry_point": f"{__name__}.cartpole_camera_presets_env_cfg:CartpoleCameraPresetsEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", "skrl_cfg_entry_point": f"{agents.__name__}:skrl_camera_ppo_cfg.yaml", }, diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/__init__.py index 576ccc822edf..db0af4029c29 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/__init__.py @@ -15,6 +15,40 @@ # Register Gym environments ########################### +# Canonical proprioceptive showcase task -- selects the (observation, action) +# space combination via the preset CLI (#5587). The default skrl yaml matches +# the canonical ``box_box`` shape; for other variants pass the matching +# ``--agent skrl___cfg_entry_point``. Retired per-shape IDs below +# remain registered for one release as deprecation shims pointing at this task. +gym.register( + id="Isaac-Cartpole-Showcase-Direct-v0", + entry_point=f"{__name__}.cartpole_env:CartpoleShowcaseEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:CartpoleShowcasePresetsEnvCfg", + "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", + "skrl_box_box_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", + "skrl_box_discrete_cfg_entry_point": f"{agents.__name__}:skrl_box_discrete_ppo_cfg.yaml", + "skrl_box_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_box_multidiscrete_ppo_cfg.yaml", + "skrl_discrete_box_cfg_entry_point": f"{agents.__name__}:skrl_discrete_box_ppo_cfg.yaml", + "skrl_discrete_discrete_cfg_entry_point": f"{agents.__name__}:skrl_discrete_discrete_ppo_cfg.yaml", + "skrl_discrete_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_discrete_multidiscrete_ppo_cfg.yaml", + "skrl_multidiscrete_box_cfg_entry_point": f"{agents.__name__}:skrl_multidiscrete_box_ppo_cfg.yaml", + "skrl_multidiscrete_discrete_cfg_entry_point": f"{agents.__name__}:skrl_multidiscrete_discrete_ppo_cfg.yaml", + "skrl_multidiscrete_multidiscrete_cfg_entry_point": ( + f"{agents.__name__}:skrl_multidiscrete_multidiscrete_ppo_cfg.yaml" + ), + "skrl_dict_box_cfg_entry_point": f"{agents.__name__}:skrl_dict_box_ppo_cfg.yaml", + "skrl_dict_discrete_cfg_entry_point": f"{agents.__name__}:skrl_dict_discrete_ppo_cfg.yaml", + "skrl_dict_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_dict_multidiscrete_ppo_cfg.yaml", + "skrl_tuple_box_cfg_entry_point": f"{agents.__name__}:skrl_tuple_box_ppo_cfg.yaml", + "skrl_tuple_discrete_cfg_entry_point": f"{agents.__name__}:skrl_tuple_discrete_ppo_cfg.yaml", + "skrl_tuple_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_tuple_multidiscrete_ppo_cfg.yaml", + }, +) + +# -- Deprecated aliases -------------------------------------------------------- + ### # Observation space as Box ### @@ -25,6 +59,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:BoxBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 presets=box_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", }, ) @@ -35,6 +70,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:BoxDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_box_discrete_cfg_entry_point presets=box_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_discrete_ppo_cfg.yaml", }, ) @@ -45,6 +81,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:BoxMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_box_multidiscrete_cfg_entry_point presets=box_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_multidiscrete_ppo_cfg.yaml", }, ) @@ -59,6 +96,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DiscreteBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_discrete_box_cfg_entry_point presets=discrete_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_discrete_box_ppo_cfg.yaml", }, ) @@ -69,6 +107,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DiscreteDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_discrete_discrete_cfg_entry_point presets=discrete_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_discrete_discrete_ppo_cfg.yaml", }, ) @@ -79,6 +118,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DiscreteMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_discrete_multidiscrete_cfg_entry_point presets=discrete_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_discrete_multidiscrete_ppo_cfg.yaml", }, ) @@ -93,6 +133,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:MultiDiscreteBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_multidiscrete_box_cfg_entry_point presets=multidiscrete_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_multidiscrete_box_ppo_cfg.yaml", }, ) @@ -103,6 +144,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:MultiDiscreteDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_multidiscrete_discrete_cfg_entry_point presets=multidiscrete_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_multidiscrete_discrete_ppo_cfg.yaml", }, ) @@ -113,6 +155,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:MultiDiscreteMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_multidiscrete_multidiscrete_cfg_entry_point presets=multidiscrete_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_multidiscrete_multidiscrete_ppo_cfg.yaml", }, ) @@ -127,6 +170,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DictBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_dict_box_cfg_entry_point presets=dict_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_box_ppo_cfg.yaml", }, ) @@ -137,6 +181,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DictDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_dict_discrete_cfg_entry_point presets=dict_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_discrete_ppo_cfg.yaml", }, ) @@ -147,6 +192,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:DictMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_dict_multidiscrete_cfg_entry_point presets=dict_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_multidiscrete_ppo_cfg.yaml", }, ) @@ -161,6 +207,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:TupleBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_tuple_box_cfg_entry_point presets=tuple_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_box_ppo_cfg.yaml", }, ) @@ -171,6 +218,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:TupleDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_tuple_discrete_cfg_entry_point presets=tuple_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_discrete_ppo_cfg.yaml", }, ) @@ -181,6 +229,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_env_cfg:TupleMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Showcase-Direct-v0 --agent=skrl_tuple_multidiscrete_cfg_entry_point presets=tuple_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_multidiscrete_ppo_cfg.yaml", }, ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env_cfg.py index 2ff10fa8f8ab..bf47f391c554 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env_cfg.py @@ -10,6 +10,7 @@ from isaaclab.utils.configclass import configclass from isaaclab_tasks.direct.cartpole.cartpole_env_cfg import CartpoleEnvCfg +from isaaclab_tasks.utils import PresetCfg ### # Observation space as Box @@ -605,3 +606,39 @@ class TupleMultiDiscreteEnvCfg(CartpoleEnvCfg): ) ) # or for simplicity: (2, 2) action_space = spaces.MultiDiscrete([3, 2]) # or for simplicity: [{3}, {2}] + + +## +# Consolidated PresetCfg +## + + +@configclass +class CartpoleShowcasePresetsEnvCfg(PresetCfg): + """Proprioceptive cartpole showcase with selectable observation/action space. + + Each variant attribute is an instance of an existing per-shape cfg class + declared above. The hydra resolver picks one based on the + ``presets=`` CLI token; the default is ``box_box`` (matching the + canonical cartpole shape). The retired per-shape task IDs are registered + in the sibling ``__init__.py`` with a ``deprecated={"alias": ...}`` kwarg + so ``parse_cfg.load_cfg_from_registry`` emits a ``DeprecationWarning`` + when one of them is loaded. + """ + + box_box = BoxBoxEnvCfg() + box_discrete = BoxDiscreteEnvCfg() + box_multidiscrete = BoxMultiDiscreteEnvCfg() + discrete_box = DiscreteBoxEnvCfg() + discrete_discrete = DiscreteDiscreteEnvCfg() + discrete_multidiscrete = DiscreteMultiDiscreteEnvCfg() + multidiscrete_box = MultiDiscreteBoxEnvCfg() + multidiscrete_discrete = MultiDiscreteDiscreteEnvCfg() + multidiscrete_multidiscrete = MultiDiscreteMultiDiscreteEnvCfg() + dict_box = DictBoxEnvCfg() + dict_discrete = DictDiscreteEnvCfg() + dict_multidiscrete = DictMultiDiscreteEnvCfg() + tuple_box = TupleBoxEnvCfg() + tuple_discrete = TupleDiscreteEnvCfg() + tuple_multidiscrete = TupleMultiDiscreteEnvCfg() + default = box_box # canonical Cartpole shape: Box obs, Box action. diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/__init__.py index 2953ce1a29c0..b74a20e969dc 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/__init__.py @@ -15,6 +15,34 @@ # Register Gym environments ########################### +# Canonical camera-based showcase task -- selects the (observation, action) +# space combination via the preset CLI (#5587). The default skrl yaml matches +# the canonical ``box_box`` shape; for other variants pass the matching +# ``--agent skrl___cfg_entry_point``. Retired per-shape IDs below +# remain registered for one release as deprecation shims pointing at this task. +gym.register( + id="Isaac-Cartpole-Camera-Showcase-Direct-v0", + entry_point=f"{__name__}.cartpole_camera_env:CartpoleCameraShowcaseEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": ( + f"{__name__}.cartpole_camera_env_cfg:CartpoleCameraShowcasePresetsEnvCfg" + ), + "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", + "skrl_box_box_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", + "skrl_box_discrete_cfg_entry_point": f"{agents.__name__}:skrl_box_discrete_ppo_cfg.yaml", + "skrl_box_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_box_multidiscrete_ppo_cfg.yaml", + "skrl_dict_box_cfg_entry_point": f"{agents.__name__}:skrl_dict_box_ppo_cfg.yaml", + "skrl_dict_discrete_cfg_entry_point": f"{agents.__name__}:skrl_dict_discrete_ppo_cfg.yaml", + "skrl_dict_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_dict_multidiscrete_ppo_cfg.yaml", + "skrl_tuple_box_cfg_entry_point": f"{agents.__name__}:skrl_tuple_box_ppo_cfg.yaml", + "skrl_tuple_discrete_cfg_entry_point": f"{agents.__name__}:skrl_tuple_discrete_ppo_cfg.yaml", + "skrl_tuple_multidiscrete_cfg_entry_point": f"{agents.__name__}:skrl_tuple_multidiscrete_ppo_cfg.yaml", + }, +) + +# -- Deprecated aliases -------------------------------------------------------- + ### # Observation space as Box ### @@ -25,6 +53,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:BoxBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 presets=box_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_box_ppo_cfg.yaml", }, ) @@ -35,6 +64,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:BoxDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_box_discrete_cfg_entry_point presets=box_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_discrete_ppo_cfg.yaml", }, ) @@ -45,6 +75,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:BoxMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_box_multidiscrete_cfg_entry_point presets=box_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_box_multidiscrete_ppo_cfg.yaml", }, ) @@ -59,6 +90,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:DictBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_dict_box_cfg_entry_point presets=dict_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_box_ppo_cfg.yaml", }, ) @@ -69,6 +101,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:DictDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_dict_discrete_cfg_entry_point presets=dict_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_discrete_ppo_cfg.yaml", }, ) @@ -79,6 +112,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:DictMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_dict_multidiscrete_cfg_entry_point presets=dict_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_dict_multidiscrete_ppo_cfg.yaml", }, ) @@ -93,6 +127,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:TupleBoxEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_tuple_box_cfg_entry_point presets=tuple_box"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_box_ppo_cfg.yaml", }, ) @@ -103,6 +138,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:TupleDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_tuple_discrete_cfg_entry_point presets=tuple_discrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_discrete_ppo_cfg.yaml", }, ) @@ -113,6 +149,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:TupleMultiDiscreteEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Showcase-Direct-v0 --agent=skrl_tuple_multidiscrete_cfg_entry_point presets=tuple_multidiscrete"}, "skrl_cfg_entry_point": f"{agents.__name__}:skrl_tuple_multidiscrete_ppo_cfg.yaml", }, ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/cartpole_camera_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/cartpole_camera_env_cfg.py index d3e78a6bd4b7..58f48f4bc32e 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/cartpole_camera_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole_camera/cartpole_camera_env_cfg.py @@ -12,6 +12,7 @@ from isaaclab.utils.configclass import configclass from isaaclab_tasks.direct.cartpole.cartpole_camera_env_cfg import CartpoleRGBCameraEnvCfg as CartpoleCameraEnvCfg +from isaaclab_tasks.utils import PresetCfg def get_tiled_camera_cfg(data_type: str, width: int = 100, height: int = 100) -> CameraCfg: @@ -373,3 +374,33 @@ class TupleMultiDiscreteEnvCfg(CartpoleCameraEnvCfg): ) ) # or for simplicity: ([height, width, 3], 2) action_space = spaces.MultiDiscrete([3, 2]) # or for simplicity: [{3}, {2}] + + +## +# Consolidated PresetCfg +## + + +@configclass +class CartpoleCameraShowcasePresetsEnvCfg(PresetCfg): + """Camera-based cartpole showcase with selectable observation container and action space. + + Each variant attribute is an instance of an existing per-shape cfg class + declared above. The hydra resolver picks one based on ``presets=``; + the default is ``box_box`` (matching the canonical cartpole camera shape). + The retired per-shape task IDs are registered in the sibling + ``__init__.py`` with a ``deprecated={"alias": ...}`` kwarg so + ``parse_cfg.load_cfg_from_registry`` emits a ``DeprecationWarning`` when + one of them is loaded. + """ + + box_box = BoxBoxEnvCfg() + box_discrete = BoxDiscreteEnvCfg() + box_multidiscrete = BoxMultiDiscreteEnvCfg() + dict_box = DictBoxEnvCfg() + dict_discrete = DictDiscreteEnvCfg() + dict_multidiscrete = DictMultiDiscreteEnvCfg() + tuple_box = TupleBoxEnvCfg() + tuple_discrete = TupleDiscreteEnvCfg() + tuple_multidiscrete = TupleMultiDiscreteEnvCfg() + default = box_box # canonical Cartpole Camera shape: Box obs, Box action. diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/__init__.py index 68eef31a0cc8..5b7f12a6dbb5 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/__init__.py @@ -29,12 +29,39 @@ }, ) +# Canonical perception task -- selects observation pipeline (raw RGB, raw depth, +# ResNet18 features, Theia-Tiny features) via the preset CLI (#5587). Two +# rl_games agent entry points cover the image-policy and feature-policy yamls; +# pick via ``--agent rl_games_cfg_entry_point`` (image, default) or +# ``--agent rl_games_feature_cfg_entry_point`` (pretrained-feature). Old +# per-pipeline IDs below remain registered for one release as deprecation +# shims pointing at this task. +gym.register( + id="Isaac-Cartpole-Camera-v0", + entry_point="isaaclab.envs:ManagerBasedRLEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleCameraPresetsEnvCfg", + "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", + "rl_games_feature_cfg_entry_point": f"{agents.__name__}:rl_games_feature_ppo_cfg.yaml", + }, +) + +# -- Deprecated aliases -------------------------------------------------------- +# Each retired task ID carries a ``deprecated`` kwarg whose ``alias`` field +# names the consolidated task with the equivalent ``presets=`` (and +# ``--agent=`` where needed); ``parse_cfg.load_cfg_from_registry`` emits a +# DeprecationWarning when the retired ID's env cfg is loaded. The +# ``env_cfg_entry_point`` keeps pointing at the historical per-variant cfg so +# the retired ID stays bit-for-bit identical to develop. + gym.register( id="Isaac-Cartpole-RGB-v0", entry_point="isaaclab.envs:ManagerBasedRLEnv", disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleRGBCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-v0 presets=rgb"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", }, ) @@ -45,6 +72,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleDepthCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-v0 presets=depth"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_camera_ppo_cfg.yaml", }, ) @@ -55,6 +83,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleResNet18CameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-v0 --agent=rl_games_feature_cfg_entry_point presets=resnet18"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_feature_ppo_cfg.yaml", }, ) @@ -65,6 +94,7 @@ disable_env_checker=True, kwargs={ "env_cfg_entry_point": f"{__name__}.cartpole_camera_env_cfg:CartpoleTheiaTinyCameraEnvCfg", + "deprecated": {"alias": "--task=Isaac-Cartpole-Camera-v0 --agent=rl_games_feature_cfg_entry_point presets=theia_tiny"}, "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_feature_ppo_cfg.yaml", }, ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/cartpole_camera_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/cartpole_camera_env_cfg.py index 0452ca3d5996..a176515b2c5a 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/cartpole_camera_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/cartpole_camera_env_cfg.py @@ -11,6 +11,7 @@ from isaaclab.utils.configclass import configclass import isaaclab_tasks.manager_based.classic.cartpole.mdp as mdp +from isaaclab_tasks.utils import PresetCfg from .cartpole_env_cfg import CartpoleEnvCfg, CartpoleSceneCfg @@ -174,3 +175,38 @@ class CartpoleTheiaTinyCameraEnvCfg(CartpoleRGBCameraEnvCfg): """Configuration for the cartpole environment with Theia-Tiny features as observations.""" observations: TheiaTinyObservationCfg = TheiaTinyObservationCfg() + + +## +# Consolidated env configuration (canonical -- used by Isaac-Cartpole-Camera-v0) +## + + +@configclass +class CartpoleCameraPresetsEnvCfg(PresetCfg): + """Manager-based cartpole perception with selectable observation pipeline. + + Variants selected via ``presets=``: + + * ``rgb`` / ``default`` -- raw RGB camera observations. + * ``depth`` -- depth (distance-to-camera) observations. + * ``resnet18`` -- features extracted by a frozen ResNet18 backbone from + the RGB camera. + * ``theia_tiny`` -- features extracted by a frozen Theia-Tiny transformer + backbone from the RGB camera. + + Each variant is one of the existing per-pipeline subclasses above. The + framework resolver pins the selected variant at ``gym.make`` time when + the user passes ``presets=``. + + Used by the canonical :obj:`Isaac-Cartpole-Camera-v0` task. The retired + per-variant task IDs (:obj:`Isaac-Cartpole-{RGB,Depth,RGB-ResNet18,RGB-TheiaTiny}-v0`) + return the same per-variant subclasses directly via the deprecation + shims in the sibling ``__init__.py``. + """ + + rgb: CartpoleRGBCameraEnvCfg = CartpoleRGBCameraEnvCfg() + depth: CartpoleDepthCameraEnvCfg = CartpoleDepthCameraEnvCfg() + resnet18: CartpoleResNet18CameraEnvCfg = CartpoleResNet18CameraEnvCfg() + theia_tiny: CartpoleTheiaTinyCameraEnvCfg = CartpoleTheiaTinyCameraEnvCfg() + default = rgb diff --git a/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py b/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py index a843eeb3ab7e..99b8da846203 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py +++ b/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py @@ -109,6 +109,21 @@ class PhysicsCfg(PresetCfg): The preset *name* (``newton_mjwarp``) is decoupled from the config class (``NewtonCfg``): the class describes the Newton backend, while the field name labels which solver variant this entry selects. + + **Class-local helpers (underscore convention).** Names prefixed with + ``_`` and callables (nested classes, methods) are skipped by the + resolver and are NOT registered as variants. Use this to keep shared + helpers adjacent to the variants that need them, without polluting the + module namespace:: + + @configclass + class MultiBackendCameraCfg(PresetCfg): + # Class-local helper -- not a variant. + _ROTATED_OFFSET = CameraCfg.OffsetCfg(rot=(1, 0, 0, 0), ...) + + rgb = CameraCfg(data_types=["rgb"]) + albedo = CameraCfg(data_types=["albedo"], offset=_ROTATED_OFFSET) + default = rgb """ def __getattr__(self, name: str): diff --git a/source/isaaclab_tasks/isaaclab_tasks/utils/parse_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/utils/parse_cfg.py index e5e71fa06f8c..2cbb9846552a 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/utils/parse_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/utils/parse_cfg.py @@ -12,6 +12,7 @@ import inspect import os import re +import warnings from typing import TYPE_CHECKING import gymnasium as gym @@ -60,13 +61,28 @@ def load_cfg_from_registry(task_name: str, entry_point_key: str) -> dict | objec Raises: ValueError: If the entry point key is not available in the gym registry for the task. """ + spec = gym.spec(task_name.split(":")[-1]) + # Emit a DeprecationWarning when loading the env cfg for a retired task + # registered as a deprecation alias. The migration metadata lives in the + # gym.register kwargs under the ``deprecated`` key as a dict whose + # ``alias`` field is the equivalent CLI command, e.g. + # ``"deprecated": {"alias": "--task=Isaac-Cartpole-Camera-Direct-v0 presets=rgb"}``. + if entry_point_key == "env_cfg_entry_point": + deprecation = spec.kwargs.get("deprecated") or {} + new_command = deprecation.get("alias") + if new_command: + warnings.warn( + f"Task '{spec.id}' is deprecated and will be removed in a future release. Use '{new_command}'.", + DeprecationWarning, + stacklevel=2, + ) # obtain the configuration entry point - cfg_entry_point = gym.spec(task_name.split(":")[-1]).kwargs.get(entry_point_key) + cfg_entry_point = spec.kwargs.get(entry_point_key) # check if entry point exists if cfg_entry_point is None: # get existing agents and algorithms agents = collections.defaultdict(list) - for k in gym.spec(task_name.split(":")[-1]).kwargs: + for k in spec.kwargs: if k.endswith("_cfg_entry_point") and k != "env_cfg_entry_point": spec = ( k.replace("_cfg_entry_point", "")