forked from isaac-sim/IsaacLab
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathh1_locomotion.py
More file actions
240 lines (203 loc) · 10.5 KB
/
Copy pathh1_locomotion.py
File metadata and controls
240 lines (203 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""
This script demonstrates an interactive demo with the H1 rough terrain environment.
.. code-block:: bash
# Usage
uv run python scripts/demos/h1_locomotion.py
"""
"""Launch Isaac Sim Simulator first."""
import argparse
from importlib import metadata
from isaaclab_rl.entrypoints.backends import cli_args_rsl_rl as cli_args # isort: skip
from isaaclab.app import AppLauncher
# add argparse arguments
parser = argparse.ArgumentParser(
description="This script demonstrates an interactive demo with the H1 rough terrain environment."
)
# append RSL-RL cli arguments
cli_args.add_rsl_rl_args(parser)
parser.add_argument(
"--physics",
default="isaacsim_physx",
choices=["isaacsim_physx"],
help="Physics backend.",
)
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# demos should open Kit visualizer by default
parser.set_defaults(visualizer=["kit"])
# parse the arguments
args_cli = parser.parse_args()
# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
import torch
from rsl_rl.runners import OnPolicyRunner
import carb
import omni
from omni.kit.viewport.utility import get_viewport_from_window_name
from omni.kit.viewport.utility.camera_state import ViewportCameraState
from pxr import Gf, Sdf
from isaaclab.envs import ManagerBasedRLEnv
from isaaclab.sim.utils.stage import get_current_stage
from isaaclab.utils.math import quat_apply
from isaaclab_rl.rsl_rl import RslRlOnPolicyRunnerCfg, RslRlVecEnvWrapper, handle_deprecated_rsl_rl_cfg
from isaaclab_rl.utils.pretrained_checkpoint import (
get_pretrained_checkpoint_backend_names,
get_published_pretrained_checkpoint,
)
from isaaclab_tasks.utils import resolve_task_config
TASK = "Isaac-Velocity-Rough-H1"
RL_LIBRARY = "rsl_rl"
class H1RoughDemo:
"""This class provides an interactive demo for the H1 rough terrain environment.
It loads a pre-trained checkpoint for the Isaac-Velocity-Rough-H1 task, trained with RSL RL
and defines a set of keyboard commands for directing motion of selected robots.
A robot can be selected from the scene through a mouse click. Once selected, the following
keyboard controls can be used to control the robot:
* UP: go forward
* LEFT: turn left
* RIGHT: turn right
* DOWN: stop
* C: switch between third-person and perspective views
* ESC: exit current third-person view"""
def __init__(self):
"""Initializes environment config designed for the interactive model and sets up the environment,
loads pre-trained checkpoints, and registers keyboard events."""
agent_cfg: RslRlOnPolicyRunnerCfg = cli_args.parse_rsl_rl_cfg(TASK, args_cli)
agent_cfg = handle_deprecated_rsl_rl_cfg(agent_cfg, metadata.version("rsl-rl-lib"))
# create envionrment
env_cfg, _ = resolve_task_config(TASK, "", play_mode=True, overrides=(f"physics={args_cli.physics}",))
env_cfg.scene.num_envs = 25
env_cfg.episode_length_s = 1000000
env_cfg.curriculum = None
env_cfg.commands.base_velocity.ranges.lin_vel_x = (0.0, 1.0)
env_cfg.commands.base_velocity.ranges.heading = (-1.0, 1.0)
# load the trained jit policy
backend_names = get_pretrained_checkpoint_backend_names(env_cfg)
checkpoint = get_published_pretrained_checkpoint(RL_LIBRARY, TASK, *backend_names)
if checkpoint is None:
raise FileNotFoundError("No published checkpoint is available for the H1 locomotion demo.")
# wrap around environment for rsl-rl
self.env = RslRlVecEnvWrapper(ManagerBasedRLEnv(cfg=env_cfg))
self.device = self.env.unwrapped.device
# load previously trained model
ppo_runner = OnPolicyRunner(self.env, agent_cfg.to_dict(), log_dir=None, device=self.device)
ppo_runner.load(checkpoint)
# obtain the trained policy for inference
self.policy = ppo_runner.get_inference_policy(device=self.device)
self.create_camera()
self.commands = torch.zeros(env_cfg.scene.num_envs, 4, device=self.device)
self.commands[:, 0:3] = self.env.unwrapped.command_manager.get_command("base_velocity")
self.set_up_keyboard()
self._prim_selection = omni.usd.get_context().get_selection()
self._selected_id = None
self._previous_selected_id = None
self._camera_local_transform = torch.tensor([-2.5, 0.0, 0.8], device=self.device)
def create_camera(self):
"""Creates a camera to be used for third-person view."""
stage = get_current_stage()
self.viewport = get_viewport_from_window_name("Viewport")
# Create camera
self.camera_path = "/World/Camera"
self.perspective_path = "/OmniverseKit_Persp"
camera_prim = stage.DefinePrim(self.camera_path, "Camera")
camera_prim.GetAttribute("focalLength").Set(8.5)
coi_prop = camera_prim.GetProperty("omni:kit:centerOfInterest")
if not coi_prop or not coi_prop.IsValid():
camera_prim.CreateAttribute(
"omni:kit:centerOfInterest", Sdf.ValueTypeNames.Vector3d, True, Sdf.VariabilityUniform
).Set(Gf.Vec3d(0, 0, -10))
self.viewport.set_active_camera(self.perspective_path)
def set_up_keyboard(self):
"""Sets up interface for keyboard input and registers the desired keys for control."""
self._input = carb.input.acquire_input_interface()
self._keyboard = omni.appwindow.get_default_app_window().get_keyboard()
self._sub_keyboard = self._input.subscribe_to_keyboard_events(self._keyboard, self._on_keyboard_event)
T = 1
R = 0.5
self._key_to_control = {
"UP": torch.tensor([T, 0.0, 0.0, 0.0], device=self.device),
"DOWN": torch.tensor([0.0, 0.0, 0.0, 0.0], device=self.device),
"LEFT": torch.tensor([T, 0.0, 0.0, -R], device=self.device),
"RIGHT": torch.tensor([T, 0.0, 0.0, R], device=self.device),
"ZEROS": torch.tensor([0.0, 0.0, 0.0, 0.0], device=self.device),
}
def _on_keyboard_event(self, event):
"""Checks for a keyboard event and assign the corresponding command control depending on key pressed."""
if event.type == carb.input.KeyboardEventType.KEY_PRESS:
# Arrow keys map to pre-defined command vectors to control navigation of robot
if event.input.name in self._key_to_control:
if self._selected_id is not None:
self.commands[self._selected_id] = self._key_to_control[event.input.name]
# Escape key exits out of the current selected robot view
elif event.input.name == "ESCAPE":
self._prim_selection.clear_selected_prim_paths()
# C key swaps between third-person and perspective views
elif event.input.name == "C":
if self._selected_id is not None:
if self.viewport.get_active_camera() == self.camera_path:
self.viewport.set_active_camera(self.perspective_path)
else:
self.viewport.set_active_camera(self.camera_path)
# On key release, the robot stops moving
elif event.type == carb.input.KeyboardEventType.KEY_RELEASE:
if self._selected_id is not None:
self.commands[self._selected_id] = self._key_to_control["ZEROS"]
def update_selected_object(self):
"""Determines which robot is currently selected and whether it is a valid H1 robot.
For valid robots, we enter the third-person view for that robot.
When a new robot is selected, we reset the command of the previously selected
to continue random commands."""
self._previous_selected_id = self._selected_id
selected_prim_paths = self._prim_selection.get_selected_prim_paths()
if len(selected_prim_paths) == 0:
self._selected_id = None
self.viewport.set_active_camera(self.perspective_path)
elif len(selected_prim_paths) > 1:
print("Multiple prims are selected. Please only select one!")
else:
prim_splitted_path = selected_prim_paths[0].split("/")
# a valid robot was selected, update the camera to go into third-person view
if len(prim_splitted_path) >= 4 and prim_splitted_path[3][0:4] == "env_":
self._selected_id = int(prim_splitted_path[3][4:])
if self._previous_selected_id != self._selected_id:
self.viewport.set_active_camera(self.camera_path)
self._update_camera()
else:
print("The selected prim was not a H1 robot")
# Reset commands for previously selected robot if a new one is selected
if self._previous_selected_id is not None and self._previous_selected_id != self._selected_id:
self.env.unwrapped.command_manager.reset([self._previous_selected_id])
self.commands[:, 0:3] = self.env.unwrapped.command_manager.get_command("base_velocity")
def _update_camera(self):
"""Updates the per-frame transform of the third-person view camera to follow
the selected robot's torso transform."""
base_pos = self.env.unwrapped.scene["robot"].data.root_pos_w.torch[
self._selected_id, :
] # - env.scene.env_origins
base_quat = self.env.unwrapped.scene["robot"].data.root_quat_w.torch[self._selected_id, :]
camera_pos = quat_apply(base_quat, self._camera_local_transform) + base_pos
camera_state = ViewportCameraState(self.camera_path, self.viewport)
eye = Gf.Vec3d(camera_pos[0].item(), camera_pos[1].item(), camera_pos[2].item())
target = Gf.Vec3d(base_pos[0].item(), base_pos[1].item(), base_pos[2].item() + 0.6)
camera_state.set_position_world(eye, True)
camera_state.set_target_world(target, True)
def main():
"""Main function."""
demo_h1 = H1RoughDemo()
obs, _ = demo_h1.env.reset()
while simulation_app.is_running():
# check for selected robots
demo_h1.update_selected_object()
with torch.inference_mode():
action = demo_h1.policy(obs)
obs, _, _, _ = demo_h1.env.step(action)
# overwrite command based on keyboard input
obs[:, 9:13] = demo_h1.commands
if __name__ == "__main__":
main()
simulation_app.close()