UAV Models and Usage#

See also

We strongly recommend going through the tutorials provided by Isaac Sim and Isaac Lab.

Using the UAV Models#

All UAV models, e.g., Hummingbird and Firefly are subclassed from MultirotorBase. An instance of MultirotorBase does not correspond to a specific UAV, but acts like a view (think of torch.Tensor.view) that holds the states of a group of UAVs of that type in torch.Tensor for reading and writing. It implements the multirotor dynamics and provides interfaces for common interactions such as getting the kinematic information and applying rotor commands.

The following example demonstrates:

  1. How to create and control a UAV using the MultirotorBase class.

  2. How to use a position controller to track a circular trajectory.

  3. How to attach cameras to UAVs to record images and hence videos.

Importing/Creating New UAVs#

Since MultirotorBase implements the commonly use multirotor dynamics, adding an ordinary UAV is easy:

from omni_drones.robots.drone.multirotor import MultirotorBase
from omni_drones.robots.robot import ASSET_PATH


class Iris(MultirotorBase):

    usd_path: str = ASSET_PATH + "/usd/iris.usd"
    param_path: str = ASSET_PATH + "/usd/iris.yaml"

which effectively comes to 1. providing a description file in .usd format, and 2. specifying its parameters.

Adding an UAV model with more complex dynamics may require extending the corresponding methods. For example, the omnidirectional UAV Omav has 6 tilt units. So we extend Omav.apply_action() to control the tilt units via velocity targets, and Omav._reset_idx() to reset the tilting angle.

 1import torch
 2from torchrl.data import BoundedTensorSpec, UnboundedContinuousTensorSpec
 3
 4from omni_drones.robots.drone import MultirotorBase
 5from omni_drones.robots.robot import ASSET_PATH
 6
 7class Omav(MultirotorBase):
 8
 9    usd_path: str = ASSET_PATH + "/usd/omav.usd"
10    param_path: str = ASSET_PATH + "/usd/omav.yaml"
11
12    def __init__(self, name: str = "Omav", cfg=None) -> None:
13        super().__init__(name, cfg)
14        self.action_spec = BoundedTensorSpec(-1, 1, 12 + 6, device=self.device)
15        self.tilt_dof_indices = torch.arange(0, 6, device=self.device)
16        self.rotor_dof_indices = torch.arange(6, 18, device=self.device)
17        self.max_tilt_velocity = 10
18
19        self.action_spec = BoundedTensorSpec(-1, 1, self.num_rotors + 6, device=self.device)
20        self.state_spec = UnboundedContinuousTensorSpec(
21            19 + self.num_rotors + 12, device=self.device
22        )
23
24    def initialize(self, prim_paths_expr: str = None):
25        if not self.is_articulation:
26            raise NotImplementedError
27        super().initialize(prim_paths_expr)
28        self.init_joint_positions = self._view.get_joint_positions()
29        self.init_joint_velocities = self._view.get_joint_velocities()
30
31    def apply_action(self, actions: torch.Tensor) -> torch.Tensor:
32        rotor_cmds, tilt_cmds = actions.expand(*self.shape, 18).split([12, 6], dim=-1)
33        super().apply_action(rotor_cmds)
34
35        velocity_targets = tilt_cmds.clamp(-1, 1) * self.max_tilt_velocity
36        self._view.set_joint_velocity_targets(
37            velocity_targets, joint_indices=self.tilt_dof_indices
38        )
39
40        return self.throttle.sum(-1)
41
42    def _reset_idx(self, env_ids: torch.Tensor, train: bool=True):
43        env_ids = super()._reset_idx(env_ids, train)
44        self._view.set_joint_positions(
45            self.init_joint_positions[env_ids],
46            env_indices=env_ids,
47        )
48        self._view.set_joint_velocities(
49            self.init_joint_velocities[env_ids],
50            env_indices=env_ids,
51        )
52        return env_ids
53
54    def get_state(self, env=True):
55        state = super().get_state(env)
56        joint_positions = self.get_joint_positions()[..., self.tilt_dof_indices]
57        joint_velocities = self.get_joint_velocities()[..., self.tilt_dof_indices]
58        state = torch.cat([state, joint_positions, joint_velocities], dim=-1)
59        assert not torch.isnan(state).any()
60        return state
61

Customized Dynamics#

Note

To be refactored.

Building New Configurations#

Note

To be refactored.