Skip to content
Open
171 changes: 86 additions & 85 deletions scripts/demos/arl_robot_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,42 @@
#
# SPDX-License-Identifier: BSD-3-Clause

"""
Script to view ARL Robot 1.
"""Script to view ARL Robot 1.

.. code-block:: bash

# Usage with default PhysX physics and default kit visualizer.
./isaaclab.sh -p scripts/demos/arl_robot_1.py

# Usage with Newton visualizer and default PhysX physics.
./isaaclab.sh -p scripts/demos/arl_robot_1.py --visualizer newton

Launch Isaac Sim Simulator first.
"""

# Create argparser
"""Parse CLI first so we can decide whether to launch Isaac Sim Kit."""

import argparse

from isaaclab.app import AppLauncher
from isaaclab.app import add_launcher_args, launch_simulation

parser = argparse.ArgumentParser(description="View ARL Robot 1 with Lee Position Controller.")
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
parser = argparse.ArgumentParser(
description="View ARL Robot 1 with Lee Position Controller.",
conflict_handler="resolve",
)
parser.add_argument("--physics", default="physx", choices=["physx"], help="Physics backend.")

@YizeWang YizeWang Jun 11, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Newton backend is not supported because the Multirotor class is directly tied to the physx backend. Filed Proposal#6141: Add Newton Backend Support for Multirotor Asset.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is Ok for now. We can look into drones later.

add_launcher_args(parser)
parser.set_defaults(visualizer=["kit"])
args_cli = parser.parse_args()

# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

"""Rest everything follows."""

import torch

import omni.usd
from pxr import Gf, UsdLux

import isaaclab.sim as sim_utils
from isaaclab.sim import SimulationContext

from isaaclab_contrib.assets import Multirotor
##
# Pre-defined configs
##
from isaaclab.physics import PhysicsCfg

from isaaclab_contrib.controllers.lee_position_control import LeePosController
from isaaclab_contrib.controllers.lee_position_control_cfg import LeePosControllerCfg

Expand All @@ -42,72 +47,68 @@

def main():
"""Main function to spawn arl_robot_1."""

# Create simulation context
sim_cfg = sim_utils.SimulationCfg(dt=0.01)
sim = SimulationContext(sim_cfg)

# Create a dome light with light blue color
stage = omni.usd.get_context().get_stage()
dome_light = UsdLux.DomeLight.Define(stage, "/World/DomeLight")
dome_light.CreateColorAttr(Gf.Vec3f(0.53, 0.81, 0.92)) # Light blue
dome_light.CreateIntensityAttr(1000.0)

# Spawn ground plane
cfg = sim_utils.GroundPlaneCfg()
cfg.func("/World/defaultGroundPlane", cfg)

# Spawn robot
robot_cfg = ARL_ROBOT_1_CFG.replace(prim_path="/World/Robot")
robot_cfg.actuators["thrusters"].dt = sim_cfg.dt
robot = Multirotor(robot_cfg)

# Play the simulator
sim.reset()

# Create Lee position controller
controller_cfg = LeePosControllerCfg(
K_pos_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)),
K_vel_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)),
K_rot_range=((1.6, 1.6, 0.25), (1.85, 1.85, 0.4)),
K_angvel_range=((0.4, 0.4, 0.075), (0.5, 0.5, 0.09)),
max_inclination_angle_rad=1.0471975511965976,
max_yaw_rate=1.0471975511965976,
)
controller = LeePosController(controller_cfg, robot, num_envs=1, device=str(sim.device))

# Get allocation matrix and compute pseudoinverse
allocation_matrix = torch.tensor(robot_cfg.allocation_matrix, device=sim.device, dtype=torch.float32)
# allocation_matrix is (6, num_thrusters), we need pseudoinverse for wrench -> thrust
alloc_pinv = torch.linalg.pinv(allocation_matrix) # Shape: (num_thrusters, 6)

# Position command: hover in place (zero position, zero yaw)
pos_command = torch.zeros((1, 4), device=sim.device) # [x, y, z, yaw]
pos_command[0, 2] = 1.0 # Hover at 1 meter height

# Simulation loop
print("[INFO] Starting demo with Lee Position Controller. Press Ctrl+C to stop.")

while simulation_app.is_running():
# Compute wrench from velocity controller
wrench = controller.compute(pos_command) # Shape: (1, 6)

# Allocate wrench to thrusters: thrust = pinv(A) @ wrench
thrust_cmd = torch.matmul(wrench, alloc_pinv.T) # Shape: (1, num_thrusters)
thrust_cmd = thrust_cmd.clamp(min=0.0) # Ensure non-negative thrust

# Apply thrust
robot.set_thrust_target(thrust_cmd)

# Step simulation
robot.write_data_to_sim()
sim.step()

# Update robot
robot.update(sim_cfg.dt)

# Cleanup
simulation_app.close()
with launch_simulation(cfg=PhysicsCfg(), launcher_args=args_cli) as physics_cfg:
# Create simulation context
sim_cfg = sim_utils.SimulationCfg(dt=0.01, device=args_cli.device, physics=physics_cfg)
sim = sim_utils.SimulationContext(sim_cfg)

# Create a dome light with light blue color
light_cfg = sim_utils.DomeLightCfg(intensity=1000.0, color=(0.53, 0.81, 0.92))
light_cfg.func("/World/DomeLight", light_cfg)

# Spawn ground plane
ground_cfg = sim_utils.GroundPlaneCfg()
ground_cfg.func("/World/defaultGroundPlane", ground_cfg)

# Spawn robot
robot_cfg = ARL_ROBOT_1_CFG.replace(prim_path="/World/Robot")
robot_cfg.actuators["thrusters"].dt = sim_cfg.dt
robot = robot_cfg.class_type(robot_cfg)

# Play the simulator
sim.reset()

# Create Lee position controller
controller_cfg = LeePosControllerCfg(
K_pos_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)),
K_vel_range=((2.5, 2.5, 1.5), (3.5, 3.5, 2.0)),
K_rot_range=((1.6, 1.6, 0.25), (1.85, 1.85, 0.4)),
K_angvel_range=((0.4, 0.4, 0.075), (0.5, 0.5, 0.09)),
max_inclination_angle_rad=1.0471975511965976,
max_yaw_rate=1.0471975511965976,
)
controller = LeePosController(controller_cfg, robot, num_envs=1, device=str(sim.device))

# Get allocation matrix and compute pseudoinverse
allocation_matrix = torch.tensor(robot_cfg.allocation_matrix, device=sim.device, dtype=torch.float32)
# allocation_matrix is (6, num_thrusters), we need pseudoinverse for wrench -> thrust
alloc_pinv = torch.linalg.pinv(allocation_matrix) # Shape: (num_thrusters, 6)

# Position command: hover in place (zero position, zero yaw)
pos_command = torch.zeros((1, 4), device=sim.device) # [x, y, z, yaw]
pos_command[0, 2] = 1.0 # Hover at 1 meter height

# Simulation loop
print("[INFO] Starting demo with Lee Position Controller. Press Ctrl+C to stop.")

# Step while a visualizer window is still open (or none exist, e.g. headless); works for kit and newton.
while sim.is_headless_or_exist_active_visualizer():
# Compute wrench from position controller
wrench = controller.compute(pos_command) # Shape: (1, 6)

# Allocate wrench to thrusters: thrust = pinv(A) @ wrench
thrust_cmd = torch.matmul(wrench, alloc_pinv.T) # Shape: (1, num_thrusters)
thrust_cmd = thrust_cmd.clamp(min=0.0) # Ensure non-negative thrust

# Apply thrust
robot.set_thrust_target(thrust_cmd)

# Step simulation
robot.write_data_to_sim()
sim.step()

# Update robot
robot.update(sim_cfg.dt)


if __name__ == "__main__":
Expand Down
5 changes: 2 additions & 3 deletions scripts/demos/arms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause

"""
This script demonstrates different single-arm manipulators.
"""This script demonstrates different single-arm manipulators.
.. code-block:: bash
Expand Down Expand Up @@ -60,7 +59,7 @@


def define_origins(num_origins: int, spacing: float) -> list[list[float]]:
"""Defines the origins of the the scene."""
"""Defines the origins of the scene."""
# create tensor based on number of environments
env_origins = torch.zeros(num_origins, 3)
# create a grid of origins
Expand Down
11 changes: 6 additions & 5 deletions scripts/demos/bin_packing.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,21 @@

import torch

import isaaclab.sim as sim_utils
import isaaclab.utils.math as math_utils

##
# Pre-defined configs
##
from isaaclab_newton.physics import MJWarpSolverCfg, NewtonCfg

import isaaclab.sim as sim_utils
import isaaclab.utils.math as math_utils
from isaaclab.assets import AssetBaseCfg, RigidObjectCfg, RigidObjectCollectionCfg
from isaaclab.physics import PhysicsCfg
from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
from isaaclab.utils import Timer
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR
from isaaclab.utils.configclass import configclass

from isaaclab_newton.physics import MJWarpSolverCfg, NewtonCfg # isort:skip

if TYPE_CHECKING:
from isaaclab.assets import RigidObjectCollection

Expand Down Expand Up @@ -348,7 +349,7 @@ def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene) ->
scene.update(sim_dt)


def main() -> None:
def main():
"""Main function.

Returns:
Expand Down
3 changes: 1 addition & 2 deletions scripts/demos/bipeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause

"""
This script demonstrates how to simulate bipedal robots.
"""This script demonstrates how to simulate bipedal robots.
.. code-block:: bash
Expand Down
Loading