| |
| |
| |
| |
|
|
| """Script to record reset states using IsaacLab framework.""" |
|
|
| from __future__ import annotations |
|
|
| """Launch Isaac Sim Simulator first.""" |
|
|
| import argparse |
| import os |
| import torch |
| from tqdm import tqdm |
| from typing import cast |
|
|
| from isaaclab.app import AppLauncher |
|
|
| |
| parser = argparse.ArgumentParser(description="Record reset states for object pairs.") |
| parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to simulate.") |
| parser.add_argument( |
| "--task", type=str, default="OmniReset-UR5eRobotiq2f85-ObjectAnywhereEEAnywhere-v0", help="Name of the task." |
| ) |
| parser.add_argument( |
| "--dataset_dir", type=str, default="./Datasets/OmniReset/", help="Root Datasets/OmniReset/ directory." |
| ) |
| parser.add_argument( |
| "--reset_type", |
| type=str, |
| default=None, |
| help="Reset type name (e.g. ObjectAnywhereEEAnywhere). Auto-inferred from --task if omitted.", |
| ) |
| parser.add_argument( |
| "--num_reset_states", type=int, default=100, help="Number of reset states to record. Set to 0 for infinite." |
| ) |
|
|
| AppLauncher.add_app_launcher_args(parser) |
| args_cli, remaining_args = parser.parse_known_args() |
|
|
| |
| app_launcher = AppLauncher(args_cli) |
| simulation_app = app_launcher.app |
|
|
| """Rest everything else.""" |
|
|
| import gymnasium as gym |
| import time |
|
|
| import isaaclab_tasks |
| from isaaclab.envs import ManagerBasedRLEnv |
| from isaaclab.managers.recorder_manager import DatasetExportMode |
|
|
| from uwlab.utils.datasets.torch_dataset_file_handler import TorchDatasetFileHandler |
|
|
| import uwlab_tasks |
| import uwlab_tasks.manager_based.manipulation.omnireset.mdp as task_mdp |
| from uwlab_tasks.utils.hydra import hydra_task_compose |
|
|
| torch.backends.cuda.matmul.allow_tf32 = True |
| torch.backends.cudnn.allow_tf32 = True |
| torch.backends.cudnn.deterministic = False |
| torch.backends.cudnn.benchmark = False |
|
|
|
|
| @hydra_task_compose(args_cli.task, "env_cfg_entry_point", hydra_args=remaining_args) |
| def main(env_cfg, agent_cfg) -> None: |
| """Main function to record reset states.""" |
| |
| if not os.path.exists(args_cli.dataset_dir): |
| os.makedirs(args_cli.dataset_dir, exist_ok=True) |
|
|
| |
| env_cfg.scene.num_envs = args_cli.num_envs if args_cli.num_envs is not None else env_cfg.scene.num_envs |
| env_cfg.sim.device = args_cli.device if args_cli.device is not None else env_cfg.sim.device |
|
|
| |
| env_cfg.seed = None |
|
|
| |
| insertive_usd_path = env_cfg.scene.insertive_object.spawn.usd_path |
| receptive_usd_path = env_cfg.scene.receptive_object.spawn.usd_path |
| pair = task_mdp.utils.compute_pair_dir(insertive_usd_path, receptive_usd_path) |
|
|
| |
| reset_type = args_cli.reset_type |
| if reset_type is None: |
| for candidate in [ |
| "ObjectAnywhereEEAnywhere", |
| "ObjectRestingEEGrasped", |
| "ObjectAnywhereEEGrasped", |
| "ObjectPartiallyAssembledEEGrasped", |
| ]: |
| if candidate in args_cli.task: |
| reset_type = candidate |
| break |
| if reset_type is None: |
| raise ValueError(f"Could not infer reset_type from task '{args_cli.task}'. Pass --reset_type explicitly.") |
|
|
| print(f"Recording reset states for: {pair} / {reset_type}") |
| print(f"Insertive: {insertive_usd_path}") |
| print(f"Receptive: {receptive_usd_path}") |
|
|
| |
| output_dir = os.path.join(args_cli.dataset_dir, "Resets", pair) |
| os.makedirs(output_dir, exist_ok=True) |
| output_file_name = f"resets_{reset_type}.pt" |
|
|
| env_cfg.recorders = task_mdp.StableStateRecorderManagerCfg() |
| env_cfg.recorders.dataset_export_dir_path = output_dir |
| env_cfg.recorders.dataset_filename = output_file_name |
| env_cfg.recorders.dataset_export_mode = DatasetExportMode.EXPORT_SUCCEEDED_ONLY |
| env_cfg.recorders.dataset_file_handler_class_type = TorchDatasetFileHandler |
|
|
| |
| env = cast(ManagerBasedRLEnv, gym.make(args_cli.task, cfg=env_cfg)).unwrapped |
| env.reset() |
|
|
| |
| num_reset_conditions_evaluated = 0 |
| current_successful_reset_conditions = 0 |
| actions = torch.zeros(env.action_space.shape, device=env.device, dtype=torch.float32) |
| if "ObjectAnywhereEEGrasped" in args_cli.task or "ObjectRestingEEGrasped" in args_cli.task: |
| actions[:, -1] = -1.0 |
| else: |
| actions[:, -1] = ( |
| torch.randint(0, 2, (env.num_envs,), device=env.device, dtype=torch.float32) * 2 - 1 |
| ) |
|
|
| |
| pbar = tqdm(total=args_cli.num_reset_states, desc="Successful reset states", unit="reset states") |
|
|
| start_time = time.time() |
|
|
| while current_successful_reset_conditions < args_cli.num_reset_states: |
| |
| _, _, terminated, truncated, _ = env.step(actions) |
| dones = terminated | truncated |
| done_idx = torch.where(dones)[0] |
|
|
| |
| if done_idx.numel() > 0 and not ( |
| "ObjectAnywhereEEGrasped" in args_cli.task or "ObjectRestingEEGrasped" in args_cli.task |
| ): |
| actions[done_idx, -1] = ( |
| torch.randint(0, 2, (done_idx.numel(),), device=env.device, dtype=torch.float32) * 2 - 1 |
| ) |
|
|
| |
| new_successful_count = env.recorder_manager.exported_successful_episode_count |
| if new_successful_count > current_successful_reset_conditions: |
| increment = new_successful_count - current_successful_reset_conditions |
| current_successful_reset_conditions = new_successful_count |
| pbar.update(increment) |
|
|
| |
| num_reset_conditions_evaluated += dones.sum().item() |
|
|
| if env.sim.is_stopped(): |
| break |
|
|
| pbar.close() |
|
|
| |
| final_successful_reset_conditions = env.recorder_manager.exported_successful_episode_count |
| print("Reset state recording complete!") |
| print(f"Total reset conditions evaluated: {num_reset_conditions_evaluated}") |
| print(f"Successful reset conditions: {final_successful_reset_conditions}") |
| if num_reset_conditions_evaluated > 0: |
| print(f"Success rate: {final_successful_reset_conditions / num_reset_conditions_evaluated:.2%}") |
| print(f"Time taken: {(time.time() - start_time) / 60:.2f} minutes") |
|
|
| env.close() |
|
|
|
|
| if __name__ == "__main__": |
| main() |
| simulation_app.close() |
|
|