|
3 | 3 | # |
4 | 4 | # SPDX-License-Identifier: BSD-3-Clause |
5 | 5 |
|
6 | | -""" |
7 | | -Script to view ARL Robot 1. |
| 6 | +"""Script to view ARL Robot 1. |
| 7 | +
|
| 8 | +.. code-block:: bash |
| 9 | +
|
| 10 | + # Usage with default PhysX physics and default kit visualizer. |
| 11 | + ./isaaclab.sh -p scripts/demos/arl_robot_1.py |
| 12 | +
|
| 13 | + # Usage with Newton visualizer and default PhysX physics. |
| 14 | + ./isaaclab.sh -p scripts/demos/arl_robot_1.py --visualizer newton |
8 | 15 |
|
9 | | -Launch Isaac Sim Simulator first. |
10 | 16 | """ |
11 | 17 |
|
12 | | -# Create argparser |
| 18 | +"""Parse CLI first so we can decide whether to launch Isaac Sim Kit.""" |
| 19 | + |
13 | 20 | import argparse |
14 | 21 |
|
15 | | -from isaaclab.app import AppLauncher |
| 22 | +from isaaclab.app import add_launcher_args, launch_simulation |
16 | 23 |
|
17 | | -parser = argparse.ArgumentParser(description="View ARL Robot 1 with Lee Position Controller.") |
18 | | -# append AppLauncher cli args |
19 | | -AppLauncher.add_app_launcher_args(parser) |
| 24 | +parser = argparse.ArgumentParser( |
| 25 | + description="View ARL Robot 1 with Lee Position Controller.", |
| 26 | + conflict_handler="resolve", |
| 27 | +) |
| 28 | +parser.add_argument("--physics", default="physx", choices=["physx"], help="Physics backend.") |
| 29 | +add_launcher_args(parser) |
| 30 | +parser.set_defaults(visualizer=["kit"]) |
20 | 31 | args_cli = parser.parse_args() |
21 | 32 |
|
22 | | -# launch omniverse app |
23 | | -app_launcher = AppLauncher(args_cli) |
24 | | -simulation_app = app_launcher.app |
25 | | - |
26 | | -"""Rest everything follows.""" |
27 | | - |
28 | 33 | import torch |
29 | 34 |
|
30 | | -import omni.usd |
31 | | -from pxr import Gf, UsdLux |
32 | | - |
33 | 35 | import isaaclab.sim as sim_utils |
34 | | -from isaaclab.sim import SimulationContext |
35 | 36 |
|
36 | | -from isaaclab_contrib.assets import Multirotor |
| 37 | +## |
| 38 | +# Pre-defined configs |
| 39 | +## |
| 40 | +from isaaclab.physics import PhysicsCfg |
| 41 | + |
37 | 42 | from isaaclab_contrib.controllers.lee_position_control import LeePosController |
38 | 43 | from isaaclab_contrib.controllers.lee_position_control_cfg import LeePosControllerCfg |
39 | 44 |
|
|
42 | 47 |
|
43 | 48 | def main(): |
44 | 49 | """Main function to spawn arl_robot_1.""" |
45 | | - |
46 | | - # Create simulation context |
47 | | - sim_cfg = sim_utils.SimulationCfg(dt=0.01) |
48 | | - sim = SimulationContext(sim_cfg) |
49 | | - |
50 | | - # Create a dome light with light blue color |
51 | | - stage = omni.usd.get_context().get_stage() |
52 | | - dome_light = UsdLux.DomeLight.Define(stage, "/World/DomeLight") |
53 | | - dome_light.CreateColorAttr(Gf.Vec3f(0.53, 0.81, 0.92)) # Light blue |
54 | | - dome_light.CreateIntensityAttr(1000.0) |
55 | | - |
56 | | - # Spawn ground plane |
57 | | - cfg = sim_utils.GroundPlaneCfg() |
58 | | - cfg.func("/World/defaultGroundPlane", cfg) |
59 | | - |
60 | | - # Spawn robot |
61 | | - robot_cfg = ARL_ROBOT_1_CFG.replace(prim_path="/World/Robot") |
62 | | - robot_cfg.actuators["thrusters"].dt = sim_cfg.dt |
63 | | - robot = Multirotor(robot_cfg) |
64 | | - |
65 | | - # Play the simulator |
66 | | - sim.reset() |
67 | | - |
68 | | - # Create Lee position controller |
69 | | - controller_cfg = LeePosControllerCfg( |
70 | | - K_pos_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)), |
71 | | - K_vel_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)), |
72 | | - K_rot_range=((1.6, 1.6, 0.25), (1.85, 1.85, 0.4)), |
73 | | - K_angvel_range=((0.4, 0.4, 0.075), (0.5, 0.5, 0.09)), |
74 | | - max_inclination_angle_rad=1.0471975511965976, |
75 | | - max_yaw_rate=1.0471975511965976, |
76 | | - ) |
77 | | - controller = LeePosController(controller_cfg, robot, num_envs=1, device=str(sim.device)) |
78 | | - |
79 | | - # Get allocation matrix and compute pseudoinverse |
80 | | - allocation_matrix = torch.tensor(robot_cfg.allocation_matrix, device=sim.device, dtype=torch.float32) |
81 | | - # allocation_matrix is (6, num_thrusters), we need pseudoinverse for wrench -> thrust |
82 | | - alloc_pinv = torch.linalg.pinv(allocation_matrix) # Shape: (num_thrusters, 6) |
83 | | - |
84 | | - # Position command: hover in place (zero position, zero yaw) |
85 | | - pos_command = torch.zeros((1, 4), device=sim.device) # [x, y, z, yaw] |
86 | | - pos_command[0, 2] = 1.0 # Hover at 1 meter height |
87 | | - |
88 | | - # Simulation loop |
89 | | - print("[INFO] Starting demo with Lee Position Controller. Press Ctrl+C to stop.") |
90 | | - |
91 | | - while simulation_app.is_running(): |
92 | | - # Compute wrench from velocity controller |
93 | | - wrench = controller.compute(pos_command) # Shape: (1, 6) |
94 | | - |
95 | | - # Allocate wrench to thrusters: thrust = pinv(A) @ wrench |
96 | | - thrust_cmd = torch.matmul(wrench, alloc_pinv.T) # Shape: (1, num_thrusters) |
97 | | - thrust_cmd = thrust_cmd.clamp(min=0.0) # Ensure non-negative thrust |
98 | | - |
99 | | - # Apply thrust |
100 | | - robot.set_thrust_target(thrust_cmd) |
101 | | - |
102 | | - # Step simulation |
103 | | - robot.write_data_to_sim() |
104 | | - sim.step() |
105 | | - |
106 | | - # Update robot |
107 | | - robot.update(sim_cfg.dt) |
108 | | - |
109 | | - # Cleanup |
110 | | - simulation_app.close() |
| 50 | + with launch_simulation(cfg=PhysicsCfg(), launcher_args=args_cli) as physics_cfg: |
| 51 | + # Create simulation context |
| 52 | + sim_cfg = sim_utils.SimulationCfg(dt=0.01, device=args_cli.device, physics=physics_cfg) |
| 53 | + sim = sim_utils.SimulationContext(sim_cfg) |
| 54 | + |
| 55 | + # Create a dome light with light blue color |
| 56 | + light_cfg = sim_utils.DomeLightCfg(intensity=1000.0, color=(0.53, 0.81, 0.92)) |
| 57 | + light_cfg.func("/World/DomeLight", light_cfg) |
| 58 | + |
| 59 | + # Spawn ground plane |
| 60 | + ground_cfg = sim_utils.GroundPlaneCfg() |
| 61 | + ground_cfg.func("/World/defaultGroundPlane", ground_cfg) |
| 62 | + |
| 63 | + # Spawn robot |
| 64 | + robot_cfg = ARL_ROBOT_1_CFG.replace(prim_path="/World/Robot") |
| 65 | + robot_cfg.actuators["thrusters"].dt = sim_cfg.dt |
| 66 | + robot = robot_cfg.class_type(robot_cfg) |
| 67 | + |
| 68 | + # Play the simulator |
| 69 | + sim.reset() |
| 70 | + |
| 71 | + # Create Lee position controller |
| 72 | + controller_cfg = LeePosControllerCfg( |
| 73 | + K_pos_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)), |
| 74 | + K_vel_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)), |
| 75 | + K_rot_range=((1.6, 1.6, 0.25), (1.85, 1.85, 0.4)), |
| 76 | + K_angvel_range=((0.4, 0.4, 0.075), (0.5, 0.5, 0.09)), |
| 77 | + max_inclination_angle_rad=1.0471975511965976, |
| 78 | + max_yaw_rate=1.0471975511965976, |
| 79 | + ) |
| 80 | + controller = LeePosController(controller_cfg, robot, num_envs=1, device=str(sim.device)) |
| 81 | + |
| 82 | + # Get allocation matrix and compute pseudoinverse |
| 83 | + allocation_matrix = torch.tensor(robot_cfg.allocation_matrix, device=sim.device, dtype=torch.float32) |
| 84 | + # allocation_matrix is (6, num_thrusters), we need pseudoinverse for wrench -> thrust |
| 85 | + alloc_pinv = torch.linalg.pinv(allocation_matrix) # Shape: (num_thrusters, 6) |
| 86 | + |
| 87 | + # Position command: hover in place (zero position, zero yaw) |
| 88 | + pos_command = torch.zeros((1, 4), device=sim.device) # [x, y, z, yaw] |
| 89 | + pos_command[0, 2] = 1.0 # Hover at 1 meter height |
| 90 | + |
| 91 | + # Simulation loop |
| 92 | + print("[INFO] Starting demo with Lee Position Controller. Press Ctrl+C to stop.") |
| 93 | + |
| 94 | + # Step while a visualizer window is still open (or none exist, e.g. headless); works for kit and newton. |
| 95 | + while sim.is_headless_or_exist_active_visualizer(): |
| 96 | + # Compute wrench from position controller |
| 97 | + wrench = controller.compute(pos_command) # Shape: (1, 6) |
| 98 | + |
| 99 | + # Allocate wrench to thrusters: thrust = pinv(A) @ wrench |
| 100 | + thrust_cmd = torch.matmul(wrench, alloc_pinv.T) # Shape: (1, num_thrusters) |
| 101 | + thrust_cmd = thrust_cmd.clamp(min=0.0) # Ensure non-negative thrust |
| 102 | + |
| 103 | + # Apply thrust |
| 104 | + robot.set_thrust_target(thrust_cmd) |
| 105 | + |
| 106 | + # Step simulation |
| 107 | + robot.write_data_to_sim() |
| 108 | + sim.step() |
| 109 | + |
| 110 | + # Update robot |
| 111 | + robot.update(sim_cfg.dt) |
111 | 112 |
|
112 | 113 |
|
113 | 114 | if __name__ == "__main__": |
|
0 commit comments