cmvr_ai_lab/scripts/replay_npz.py

170 lines
5.5 KiB
Python
Raw Permalink Normal View History

2026-07-13 10:52:46 +08:00
"""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()