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.