Commit a90ddb94 authored by CY Chen's avatar CY Chen Committed by Kelly Guo

Adds support to record additional steps in record_demos.py (#224)

Adds support to record additional steps after task success is detected
in record_demos.py.
This helps record demos with sufficient lengths to be used for training.

<!-- As you go through the list, delete the ones that are not
applicable. -->

- Bug fix (non-breaking change which fixes an issue)

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
parent fe8c263a
...@@ -19,6 +19,7 @@ optional arguments: ...@@ -19,6 +19,7 @@ optional arguments:
--dataset_file File path to export recorded demos. (default: "./datasets/dataset.hdf5") --dataset_file File path to export recorded demos. (default: "./datasets/dataset.hdf5")
--step_hz Environment stepping rate in Hz. (default: 30) --step_hz Environment stepping rate in Hz. (default: 30)
--num_demos Number of demonstrations to record. (default: 0) --num_demos Number of demonstrations to record. (default: 0)
--num_success_steps Number of continuous steps with task success for concluding a demo as successful. (default: 10)
""" """
"""Launch Isaac Sim Simulator first.""" """Launch Isaac Sim Simulator first."""
...@@ -39,6 +40,12 @@ parser.add_argument("--step_hz", type=int, default=30, help="Environment steppin ...@@ -39,6 +40,12 @@ parser.add_argument("--step_hz", type=int, default=30, help="Environment steppin
parser.add_argument( parser.add_argument(
"--num_demos", type=int, default=0, help="Number of demonstrations to record. Set to 0 for infinite." "--num_demos", type=int, default=0, help="Number of demonstrations to record. Set to 0 for infinite."
) )
parser.add_argument(
"--num_success_steps",
type=int,
default=10,
help="Number of continuous steps with task success for concluding a demo as successful. Default is 10.",
)
# append AppLauncher cli args # append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser) AppLauncher.add_app_launcher_args(parser)
# parse the arguments # parse the arguments
...@@ -58,6 +65,8 @@ import gymnasium as gym ...@@ -58,6 +65,8 @@ import gymnasium as gym
import time import time
import torch import torch
import omni.log
from isaaclab.devices import Se3HandTracking, Se3Keyboard, Se3SpaceMouse from isaaclab.devices import Se3HandTracking, Se3Keyboard, Se3SpaceMouse
from isaaclab.envs import ViewerCfg from isaaclab.envs import ViewerCfg
from isaaclab.envs.mdp.recorders.recorders_cfg import ActionStateRecorderManagerCfg from isaaclab.envs.mdp.recorders.recorders_cfg import ActionStateRecorderManagerCfg
...@@ -127,8 +136,19 @@ def main(): ...@@ -127,8 +136,19 @@ def main():
env_cfg = parse_env_cfg(args_cli.task, device=args_cli.device, num_envs=1) env_cfg = parse_env_cfg(args_cli.task, device=args_cli.device, num_envs=1)
env_cfg.env_name = args_cli.task env_cfg.env_name = args_cli.task
# modify configuration such that the environment runs indefinitely # extract success checking function to invoke in the main loop
# until goal is reached success_term = None
if hasattr(env_cfg.terminations, "success"):
success_term = env_cfg.terminations.success
env_cfg.terminations.success = None
else:
omni.log.warn(
"No success termination term was found in the environment."
" Will not be able to mark recorded demos as successful."
)
# modify configuration such that the environment runs indefinitely until
# the goal is reached or other termination conditions are met
env_cfg.terminations.time_out = None env_cfg.terminations.time_out = None
env_cfg.observations.policy.concatenate_terms = False env_cfg.observations.policy.concatenate_terms = False
...@@ -173,6 +193,7 @@ def main(): ...@@ -173,6 +193,7 @@ def main():
# simulate environment -- run everything in inference mode # simulate environment -- run everything in inference mode
current_recorded_demo_count = 0 current_recorded_demo_count = 0
success_step_count = 0
with contextlib.suppress(KeyboardInterrupt) and torch.inference_mode(): with contextlib.suppress(KeyboardInterrupt) and torch.inference_mode():
while True: while True:
# get keyboard command # get keyboard command
...@@ -187,15 +208,29 @@ def main(): ...@@ -187,15 +208,29 @@ def main():
# perform action on environment # perform action on environment
env.step(actions) env.step(actions)
if success_term is not None:
if bool(success_term.func(env, **success_term.params)[0]):
success_step_count += 1
if success_step_count >= args_cli.num_success_steps:
env.recorder_manager.record_pre_reset([0], force_export_or_skip=False)
env.recorder_manager.set_success_to_episodes(
[0], torch.tensor([[True]], dtype=torch.bool, device=env.unwrapped.device)
)
env.recorder_manager.export_episodes([0])
should_reset_recording_instance = True
else:
success_step_count = 0
if should_reset_recording_instance: if should_reset_recording_instance:
env.unwrapped.recorder_manager.reset() env.unwrapped.recorder_manager.reset()
env.reset() env.reset()
should_reset_recording_instance = False should_reset_recording_instance = False
success_step_count = 0
# print out the current demo count if it has changed # print out the current demo count if it has changed
if env.unwrapped.recorder_manager.exported_successful_episode_count > current_recorded_demo_count: if env.unwrapped.recorder_manager.exported_successful_episode_count > current_recorded_demo_count:
current_recorded_demo_count = env.unwrapped.recorder_manager.exported_successful_episode_count current_recorded_demo_count = env.unwrapped.recorder_manager.exported_successful_episode_count
print(f"Recorded {current_recorded_demo_count} demonstrations.") print(f"Recorded {current_recorded_demo_count} successful demonstrations.")
if ( if (
args_cli.num_demos > 0 args_cli.num_demos > 0
......
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.33.6" version = "0.33.7"
# Description # Description
title = "Isaac Lab framework for Robot Learning" title = "Isaac Lab framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.33.6 (2025-01-30) 0.33.7 (2025-01-30)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
Fixed Fixed
...@@ -12,7 +12,7 @@ Fixed ...@@ -12,7 +12,7 @@ Fixed
to the event being triggered at the wrong time after the reset. to the event being triggered at the wrong time after the reset.
0.33.5 (2025-01-17) 0.33.6 (2025-01-17)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
Fixed Fixed
...@@ -42,7 +42,7 @@ Fixed ...@@ -42,7 +42,7 @@ Fixed
the :class:`omni.isaac.lab.assets.RigidObjectCollection` class. the :class:`omni.isaac.lab.assets.RigidObjectCollection` class.
0.33.4 (2025-01-14) 0.33.5 (2025-01-14)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
Fixed Fixed
...@@ -51,6 +51,16 @@ Fixed ...@@ -51,6 +51,16 @@ Fixed
* Fixed the respawn of only wrong object samples in :func:`repeated_objects_terrain` of :mod:`omni.isaac.lab.terrains.trimesh` module. Previously, the function was respawning all objects in the scene instead of only the wrong object samples, which in worst case could lead to infinite respawn loop. * Fixed the respawn of only wrong object samples in :func:`repeated_objects_terrain` of :mod:`omni.isaac.lab.terrains.trimesh` module. Previously, the function was respawning all objects in the scene instead of only the wrong object samples, which in worst case could lead to infinite respawn loop.
0.33.4 (2025-01-10)
~~~~~~~~~~~~~~~~~~~
Changed
^^^^^^^
* Added an optional parameter in the :meth:`record_pre_reset` method in
:class:`~isaaclab.managers.RecorderManager` to override the export config upon invoking.
0.33.3 (2025-01-08) 0.33.3 (2025-01-08)
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
......
...@@ -359,7 +359,7 @@ class RecorderManager(ManagerBase): ...@@ -359,7 +359,7 @@ class RecorderManager(ManagerBase):
key, value = term.record_post_step() key, value = term.record_post_step()
self.add_to_episodes(key, value) self.add_to_episodes(key, value)
def record_pre_reset(self, env_ids: Sequence[int] | None) -> None: def record_pre_reset(self, env_ids: Sequence[int] | None, force_export_or_skip=None) -> None:
"""Trigger recorder terms for pre-reset functions. """Trigger recorder terms for pre-reset functions.
Args: Args:
...@@ -385,7 +385,7 @@ class RecorderManager(ManagerBase): ...@@ -385,7 +385,7 @@ class RecorderManager(ManagerBase):
success_results |= self._env.termination_manager.get_term("success")[env_ids] success_results |= self._env.termination_manager.get_term("success")[env_ids]
self.set_success_to_episodes(env_ids, success_results) self.set_success_to_episodes(env_ids, success_results)
if self.cfg.export_in_record_pre_reset: if force_export_or_skip or (force_export_or_skip is None and self.cfg.export_in_record_pre_reset):
self.export_episodes(env_ids) self.export_episodes(env_ids)
def record_post_reset(self, env_ids: Sequence[int] | None) -> None: def record_post_reset(self, env_ids: Sequence[int] | None) -> None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment