"""This script demonstrates how to use the interactive scene interface to setup a scene with multiple prims. .. code-block:: bash # Usage python replay_motion.py --motion_file dataset/xxxx.npz """ """Launch Isaac Sim Simulator first.""" import argparse import os import numpy as np import torch from typing import Sequence from isaaclab.app import AppLauncher # add argparse arguments parser = argparse.ArgumentParser(description="Replay converted motions.") parser.add_argument("--motion_file", type=str, required=True, help="Path to the motion file (.npz).") # append AppLauncher cli args AppLauncher.add_app_launcher_args(parser) # parse the arguments args_cli = parser.parse_args() # launch omniverse app app_launcher = AppLauncher(args_cli) simulation_app = app_launcher.app """Rest everything follows.""" import isaaclab.sim as sim_utils from isaaclab.assets import Articulation, ArticulationCfg, AssetBaseCfg from isaaclab.scene import InteractiveScene, InteractiveSceneCfg from isaaclab.sim import SimulationContext from isaaclab.utils import configclass from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR # ! terrain from isaaclab.terrains import TerrainImporterCfg ## # Pre-defined configs ## from engineai_lab.robots.pm01 import PM01_CFG class MotionLoader: def __init__(self, motion_file: str, body_indexes: Sequence[int], device: str = "cpu"): assert os.path.isfile(motion_file), f"Invalid file path: {motion_file}" data = np.load(motion_file) self.fps = data["fps"] self.joint_pos = torch.tensor(data["joint_pos"], dtype=torch.float32, device=device) self.joint_vel = torch.tensor(data["joint_vel"], dtype=torch.float32, device=device) self._body_pos_w = torch.tensor(data["body_pos_w"], dtype=torch.float32, device=device) self._body_quat_w = torch.tensor(data["body_quat_w"], dtype=torch.float32, device=device) self._body_lin_vel_w = torch.tensor(data["body_lin_vel_w"], dtype=torch.float32, device=device) self._body_ang_vel_w = torch.tensor(data["body_ang_vel_w"], dtype=torch.float32, device=device) self._body_indexes = body_indexes self.time_step_total = self.joint_pos.shape[0] @property def body_pos_w(self) -> torch.Tensor: return self._body_pos_w[:, self._body_indexes] @property def body_quat_w(self) -> torch.Tensor: return self._body_quat_w[:, self._body_indexes] @property def body_lin_vel_w(self) -> torch.Tensor: return self._body_lin_vel_w[:, self._body_indexes] @property def body_ang_vel_w(self) -> torch.Tensor: return self._body_ang_vel_w[:, self._body_indexes] @configclass class ReplayMotionsSceneCfg(InteractiveSceneCfg): """Configuration for a replay motions scene.""" terrain = TerrainImporterCfg( prim_path="/World/ground", terrain_type="plane", collision_group=-1, physics_material=sim_utils.RigidBodyMaterialCfg( friction_combine_mode="multiply", restitution_combine_mode="multiply", static_friction=1.0, dynamic_friction=1.0, ), visual_material=sim_utils.MdlFileCfg( mdl_path="{NVIDIA_NUCLEUS_DIR}/Materials/Base/Architecture/Shingles_01.mdl", project_uvw=True, ), ) sky_light = AssetBaseCfg( prim_path="/World/skyLight", spawn=sim_utils.DomeLightCfg( intensity=750.0, texture_file=f"{ISAAC_NUCLEUS_DIR}/Materials/Textures/Skies/PolyHaven/kloofendal_43d_clear_puresky_4k.hdr", ), ) # articulation robot: ArticulationCfg = PM01_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot") def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene, motion_loader: MotionLoader): # Extract scene entities robot: Articulation = scene["robot"] # Define simulation stepping sim_dt = sim.get_physics_dt() motion = motion_loader time_steps = torch.zeros(scene.num_envs, dtype=torch.long, device=sim.device) # Simulation loop while simulation_app.is_running(): time_steps += 1 reset_ids = time_steps >= motion.time_step_total time_steps[reset_ids] = 0 root_states = robot.data.default_root_state.clone() root_states[:, :3] = motion.body_pos_w[time_steps][:, 0] + scene.env_origins[:, None, :] root_states[:, 3:7] = motion.body_quat_w[time_steps][:, 0] root_states[:, 7:10] = motion.body_lin_vel_w[time_steps][:, 0] root_states[:, 10:] = motion.body_ang_vel_w[time_steps][:, 0] robot.write_root_state_to_sim(root_states) robot.write_joint_state_to_sim(motion.joint_pos[time_steps], motion.joint_vel[time_steps]) scene.write_data_to_sim() sim.render() # We don't want physic (sim.step()) scene.update(sim_dt) pos_lookat = root_states[0, :3].cpu().numpy() sim.set_camera_view(pos_lookat + np.array([2.0, 2.0, 0.5]), pos_lookat) def main(): sim_cfg = sim_utils.SimulationCfg(device=args_cli.device) sim_cfg.dt = 0.01 sim = SimulationContext(sim_cfg) motion_loader = MotionLoader( motion_file=args_cli.motion_file, body_indexes=torch.tensor([0], dtype=torch.long, device=sim.device), device=sim.device, ) scene_cfg = ReplayMotionsSceneCfg(num_envs=1, env_spacing=2.0) scene = InteractiveScene(scene_cfg) sim.reset() # Run the simulator run_simulator(sim, scene, motion_loader) if __name__ == "__main__": # run the main function main() # close sim app simulation_app.close()