170 lines
5.5 KiB
Python
170 lines
5.5 KiB
Python
"""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()
|