UWLab / scripts_v2 /tools /record_reset_states.py
Xinyi0214's picture
Upload UWLab (code, datasets, checkpoints, eval outputs)
0037d53 verified
Raw
History Blame Contribute Delete
7.03 kB
# Copyright (c) 2024-2026, The UW Lab Project Developers. (https://github.com/uw-lab/UWLab/blob/main/CONTRIBUTORS.md).
# All Rights Reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""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
# add argparse arguments
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()
# Launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
"""Rest everything else."""
import gymnasium as gym
import time
import isaaclab_tasks # noqa: F401
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 # noqa: F401
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."""
# create directory if it does not exist
if not os.path.exists(args_cli.dataset_dir):
os.makedirs(args_cli.dataset_dir, exist_ok=True)
# override configurations with non-hydra CLI arguments
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
# make sure environment is non-deterministic for diverse pose discovery
env_cfg.seed = None
# Derive pair directory and reset type for output path
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)
# Auto-infer reset_type from task name if not provided
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}")
# Setup recording configuration
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
# create environment
env = cast(ManagerBasedRLEnv, gym.make(args_cli.task, cfg=env_cfg)).unwrapped
env.reset()
# Run reset state sampling
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
) # Randomly choose between -1 and 1
# Create progress bar
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:
# Step environment (this will evaluate grasps in parallel across environments)
_, _, terminated, truncated, _ = env.step(actions)
dones = terminated | truncated
done_idx = torch.where(dones)[0]
# Reset actions for environments that are done
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
)
# Update progress based on successful reset conditions
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)
# Count total reset conditions evaluated (sum across all environments)
num_reset_conditions_evaluated += dones.sum().item()
if env.sim.is_stopped():
break
pbar.close()
# Get final statistics
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()