Base Drone Class#

Custom Drone Example

While this section of the documentation serves as the Rosetta stone for all abstracted components, a very comprehensive tutorial on constructing your own drone can be found in the tutorials section.

Class Description#

class PyFlyt.core.abstractions.DroneClass(p: BulletClient, start_pos: ndarray, start_orn: ndarray, control_hz: int, physics_hz: int, drone_model: str, model_dir: None | str = None, np_random: None | Generator = None)#

The DroneClass is an abstract class that all drones should inherit from.

It serves as a template class for interfacing with the Aviary. Each drone inheriting from this class must have several attributes and methods implemented before they can be considered usable.

Parameters:
  • p (bullet_client.BulletClient) – PyBullet physics client ID.

  • start_pos (np.ndarray) – an (3,) array for the starting X, Y, Z position for the drone.

  • start_orn (np.ndarray) – an (3,) array for the starting X, Y, Z orientation for the drone.

  • control_hz (int) – an integer representing the control looprate of the drone.

  • physics_hz (int) – an integer representing the physics looprate of the Aviary.

  • drone_model (str) – name of the drone itself, must be the same name as the folder where the URDF and YAML files are located.

  • model_dir (None | str = None) – directory where the drone model folder is located, if none is provided, defaults to the directory of the default drones.

  • np_random (None | np.random.Generator = None) – random number generator of the simulation.

Example Implementation:
>>> def __init__(
>>>     self,
>>>     p: bullet_client.BulletClient,
>>>     start_pos: np.ndarray,
>>>     start_orn: np.ndarray,
>>>     control_hz: int = 120,
>>>     physics_hz: int = 240,
>>>     drone_model: str = "rocket_brick",
>>>     model_dir: None | str = os.path.dirname(os.path.realpath(__file__)),
>>>     np_random: None | np.random.Generator = None,
>>>     use_camera: bool = False,
>>>     use_gimbal: bool = False,
>>>     camera_angle_degrees: int = 0,
>>>     camera_FOV_degrees: int = 90,
>>>     camera_resolution: tuple[int, int] = (128, 128),
>>> ):
>>>     super().__init__(
>>>         p=p,
>>>         start_pos=start_pos,
>>>         start_orn=start_orn,
>>>         control_hz=control_hz,
>>>         physics_hz=physics_hz,
>>>         model_dir=model_dir,
>>>         drone_model=drone_model,
>>>         np_random=np_random,
>>>     )
>>>     with open(self.param_path, "rb") as f:
>>>         # load all params from yaml into components
>>>         all_params = yaml.safe_load(f)
>>>
>>>         self.lifting_surfaces = LiftingSurfaces(...)
>>>         self.boosters = Boosters(...)
>>>
>>>     self.use_camera = use_camera
>>>     if self.use_camera:
>>>         self.camera = Camera(...)

Default Attributes#

property PyFlyt.core.abstractions.DroneClass.np_random#

dtype - np.random.RandomState

property PyFlyt.core.abstractions.DroneClass.physics_period#

dtype - float

property PyFlyt.core.abstractions.DroneClass.control_period#

dtype - float

property PyFlyt.core.abstractions.DroneClass.drone_path#

Path to the drone’s URDF file.

dtype - str

property PyFlyt.core.abstractions.DroneClass.param_path#

Path to the drone’s YAML parameters file.

dtype - str

property PyFlyt.core.abstractions.DroneClass.Id#

PyBullet ID of the drone itself.

dtype - int

Required Attributes#

property PyFlyt.core.abstractions.DroneClass.state#

dtype - np.ndarray

property PyFlyt.core.abstractions.DroneClass.aux_state#

dtype - np.ndarray

property PyFlyt.core.abstractions.DroneClass.setpoint#

dtype - np.ndarray

Optional Attributes#

property PyFlyt.core.abstractions.DroneClass.rgbaImg#

dtype - np.ndarray

property PyFlyt.core.abstractions.DroneClass.depthImg#

dtype - np.ndarray

property PyFlyt.core.abstractions.DroneClass.segImg#

dtype - np.ndarray

property PyFlyt.core.abstractions.DroneClass.registered_controllers#

dtype - dict[int, type[ControlClass]]

property PyFlyt.core.abstractions.DroneClass.instanced_controllers#

dtype - dict[int, ControlClass]

property PyFlyt.core.abstractions.DroneClass.registered_base_controllers#

dtype - dict[int, int]

Default Methods#

PyFlyt.core.abstractions.DroneClass.set_mode(self, mode: int) None#

Default set_mode.

By default, mode 0 defines the following setpoint behaviour: Mode 0 - [Roll, Pitch, Yaw, Thrust]

PyFlyt.core.abstractions.DroneClass.get_joint_info(self) None#

Debugging function for displaying all joint IDs and names as defined in URDF.

PyFlyt.core.abstractions.DroneClass.disable_artificial_damping(self) None#

Disable the artificial damping that pybullet has to enable more accurate aerodynamics simulation.

Required Methods#

PyFlyt.core.abstractions.DroneClass.reset(self) None#

Resets the vehicle to the initial state.

Example Implementation:
>>> def reset(self):
>>>     # set the flight mode and reset the setpoint and actuator command
>>>     self.set_mode(0)
>>>     self.setpoint = np.zeros(2)
>>>     self.cmd = np.zeros(2)
>>>
>>>     # reset the drone position and orientation and damping
>>>     self.p.resetBasePositionAndOrientation(self.Id, self.start_pos, self.start_orn)
>>>     self.disable_artificial_damping()
>>>
>>>     # reset the components to their default states
>>>     self.lifting_surfaces.reset()
>>>     self.boosters.reset()
PyFlyt.core.abstractions.DroneClass.update_control(self, physics_step: int) None#

Updates onboard flight control laws at a rate specified by control_hz.

Example Implementation:
>>> def update_control(self, physics_step: int) -> None:
>>>     # skip control if we have not enough physics steps
>>>     if physics_step % self.physics_control_ratio != 0:
>>>         return
>>>
>>>     # depending on the flight control mode, do things
>>>     if self.mode == 0:
>>>         # assign the actuator commands to be some function of the setpoint
>>>         self.cmd = self.setpoint
>>>         return
>>>
>>>     # otherwise, check that we have a custom controller
>>>     if self.mode not in self.registered_controllers.keys():
>>>         raise ValueError(
>>>             f"Don't have other modes aside from 0, received {self.mode}."
>>>         )
>>>
>>>     # run custom controllers if any
>>>     self.cmd = self.instanced_controllers[self.mode].step(self.state, self.setpoint)
PyFlyt.core.abstractions.DroneClass.update_physics(self) None#

Updates all physics on the vehicle at a rate specified by physics_hz.

Example Implementation:
>>> def update_physics(self) -> None:
>>>     self.lifting_surfaces.physics_update(self.cmd[...])
>>>     self.boosters.physics_update(self.cmd[...])
>>>     ...
PyFlyt.core.abstractions.DroneClass.update_state(self) None#

Updates the vehicle’s state values at a rate specified by phyiscs_hz.

Example Implementation:
>>> def update_state(self) -> None:
>>>     # get all relevant information from PyBullet backend
>>>     lin_pos, ang_pos = self.p.getBasePositionAndOrientation(self.Id)
>>>     lin_vel, ang_vel = self.p.getBaseVelocity(self.Id)
>>>
>>>     # express vels in local frame
>>>     rotation = np.array(self.p.getMatrixFromQuaternion(ang_pos)).reshape(3, 3).T
>>>     lin_vel = np.matmul(rotation, lin_vel)
>>>     ang_vel = np.matmul(rotation, ang_vel)
>>>
>>>     # ang_pos in euler form
>>>     ang_pos = self.p.getEulerFromQuaternion(ang_pos)
>>>
>>>     # create the state, this is accessed from the aviary
>>>     self.state = np.stack([ang_vel, ang_pos, lin_vel, lin_pos], axis=0)
>>>
>>>     # update all relevant components as required
>>>     self.lifting_surfaces.state_update(rotation)
>>>     ...
>>>
>>>     # update auxiliary information
>>>     self.aux_state = np.concatenate(
>>>         (self.lifting_surfaces.get_states(), self.boosters.get_states(), ...)
>>>     )
PyFlyt.core.abstractions.DroneClass.update_last(self, physics_step: int) None#

Update that happens at the end of Aviary.step(), usually reserved for camera updates.

Example Implementation:
>>> def update_last(self, physics_step: int) -> None:
>>>
>>>     if self.use_camera and (physics_step % self.physics_camera_ratio == 0):
>>>         self.rgbaImg, self.depthImg, self.segImg = self.camera.capture_image()

Optional Methods#

PyFlyt.core.abstractions.DroneClass.register_controller(self, controller_id: int, controller_constructor: type[ControlClass], base_mode: int) None#

Default register_controller.

Parameters:
  • controller_id (int) – ID to bind to this controller

  • controller_constructor (type[ControlClass]) – A class pointer to the controller implementation, must be subclass of ControlClass.

  • base_mode (int) – Whether this controller uses outputs of an underlying controller as setpoints.