Pathing Architecture
- 1 Overview
- 2 MAVLink
- 3 Waypoints
- 3.1 Waypoint file
- 4 Modules
- 5 2023
- 5.1 QR input
- 5.2 QR to waypoint names
Overview
The pathing system controls the drone’s movement at a high level from the ground station computer.
2023: The system converts a QR code into a waypoint path that the drone follows autonomously with no human intervention.
2024: The system makes the drone follow a predetermined waypoint path, with the possibility of early stop and return to launch (RTL).
MAVLink
MAVLink is a communication protocol used to communicate with the drone. More detail here: MAVLink
The pathing system uses the dronekit library to interface with MAVLink: https://dronekit-python.readthedocs.io/en/latest/
We are currently migrating to use the common repository to interface with MAVLink: The common Repository
Waypoints
Waypoints are named locations with latitude, longitude, (and optionally altitude), coordinates
Waypoint file
The waypoint file stores the name, latitude, and longitude of each waypoint in a CSV.
There may be a header with name,latitude,longitude
Each row contains a waypoint.
Example:
name,latitude,longitude
WARG,43.47323264522664,-80.54011639872981
University of Waterloo Station for 301 ION,43.4735247614021,-80.54144667502672
Modules
A pathing program is consisted of modules. Modules are reusable segments of code. Generally modules can be broken down into three types
Command modules: These are modules that create or alter a list of mavlink commands to be sent to the drone
Utility modules: Modules for “utilities”, for example a parser for a specific data format, or QR scanner
Data structure modules: Modules for more advanced data structures that may be needed for certain scenarios (such as Waypoint class with altitude)
The main pathing script should be consisted of modules, and implement logic specific to a task on top of it.
Sample Modules
Load waypoints (Type 2)
Create a name to coordinate mapping of waypoints from the waypoint file.
Return:
True, [data]
if successfulFalse, None
on error (e.g. file doesn’t exist)
Function signature:
def load_waypoint_name_to_coordinates_map(waypoint_file_path: string) \
-> "tuple[bool, dict[string, tuple[float, float]] | None]":
Example:
WAYPOINT_FILE_PATH = "~/pathing/waypoints_example.csv"
result, value = load_waypoints_name_to_coordinates_map(WAYPOINT_FILE_PATH)
print(result)
True
print(value)
{'WARG': (43.47323264522664, -80.54011639872981), 'University of Waterloo Station for 301 ION': (43.4735247614021, -80.54144667502672)}
Waypoint names to waypoints coordinates (Type 2)
Converts waypoint names to waypoint coordinates using the provided mapping.
Return:
True, [data]
if successfulFalse, None
on error (e.g. name has no entry in mapping)
Function signature:
def waypoint_names_to_coordinates(waypoint_names: "list[string]",
waypoint_mapping: "dict[string, tuple[float, float]]") \
-> "tuple[bool, list[tuple[float, float]] | None]"
Example:
names_valid = ["Waterloo", "Aerial", "Robotics", "Group 15"]
waypoint_dictionary = {
"Aerial": (9, 7),
"Group 15": (3, 4),
"Robotics": (-1, 0),
"University of Waterloo Station for 301 ION": (6, 6),
"WARG": (8, 2),
"Waterloo": (2, -5),
}
result, value = waypoint_names_to_coordinates(names_valid, waypoint_dictionary)
print(result)
True
print(value)
[(2, -5), (9, 7), (-1, 0), (3, 4)]
names_invalid = ["WARG", "Hello", "World"]
result, value = waypoint_names_to_coordinates(names_invalid, waypoint_dictionary)
print(result)
False
print(value)
None
Waypoints to commands (Type 1)
Converts the list of waypoint coordinates into a list of commands. Use the same altitude parameter for all commands.
Use
MAV_FRAME_GLOBAL_RELATIVE_ALT
andMAV_CMD_NAV_WAYPOINT
(16)
Function signature:
def waypoints_to_commands(waypoints: "list[tuple[float, float]]",
altitude: float) -> "list[dronekit.Command]":
Example:
ALTITUDE = 40
waypoints = [
(2, -5),
(9, 7),
(-1, 0),
(3, 4),
]
output = waypoints_to_commands(waypoints, ALTITUDE)
print(output)
[MISSION_ITEM {target_system : 0, target_component : 0, seq : 0, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 10, param3 : 0, param4 : 0, x : 2, y : -5, z : 40}, MISSION_ITEM {etc., x : 9, y : 7, z : 40}, MISSION_ITEM {etc.}, MISSION_ITEM {etc.}]
Add takeoff and landing command (Type 1)
Prefixes a takeoff command and suffixes a landing command to the ends of the list of commands.
Use
MAV_CMD_NAV_TAKEOFF
(22)With relative frame
All parameters 0 except altitude
Use
MAV_CMD_NAV_RETURN_TO_LAUNCH
(20)With global frame:
MAV_FRAME_GLOBAL
All parameters 0
Function signature:
def add_takeoff_and_landing_command(commands: "list[dronekit.Command]",
altitude: float) -> "list[dronekit.Command]":
Example:
ALTITUDE = 40
commands = [...]
command_count = len(commands)
output = add_takeoff_and_landing_command(commands, ALTITUDE)
assert len(output) == command_count + 2
Upload commands (Deprecated, this is now in flightcontroller class instead)
Adds the list of commands to the drone’s command sequence.
Download and clear the command sequence before adding the commands
Function signature:
def upload_commands(drone: dronekit.Vehicle, commands: "list[dronekit.Command") -> None:
Example:
CONNECTION_ADDRESS = "tcp:localhost:14550"
drone = dronekit.connect(CONNECTION_ADDRESS, wait_ready=True)
commands = [
dronekit.Command(0, 0, 0, 3, 16, 0, 0, 0, 10, 0, 0, 2, -5, 40),
dronekit.Command(0, 0, 0, 3, 16, 0, 0, 0, 10, 0, 0, 9, 7, 40),
dronekit.Command(0, 0, 0, 3, 16, 0, 0, 0, 10, 0, 0, -1, 0, 40),
dronekit.Command(0, 0, 0, 3, 16, 0, 0, 0, 10, 0, 0, 3, 4, 40),
]
upload_commands(drone, commands)
# The waypoints appear in Mission Planner after reading data from the drone
2023
QR input
Uses the camera to convert a QR code into QR text. Displays the camera as it is being used. Can be aborted by pressing 'q' .
Return:
True, [data]
if successfulFalse, None
on error (e.g. user abort)
Function signature:
def qr_input(camera_device: "int | str") -> "tuple[bool, str | None]":
Example:
CAMERA = 0
# Successful scan
result, value = qr_input(0)
print(result)
True
print(value)
'Follow route: Waterloo; Aerial; Robotics; Group 15'
# User abort
result, value = qr_input(0)
print(result)
False
print(value)
None
QR to waypoint names
Converts the QR text string into a list of waypoint names. The QR text string input is expected as:
Follow route: [waypoint name]; [waypoint name]; [waypoint name]; [waypoint name]; etc.
where [waypoint name] is one of the waypoint names.
Return:
True, [data]
if successfulFalse, None
on error (e.g. bad QR string)
Function signature:
def qr_to_waypoint_names(qr_text: string) -> "tuple[bool, list[string] | None":
Example:
qr_text_valid = "Follow route: Waterloo, Aerial, Robotics, Group 15"
result, value = qr_to_waypoint_names(qr_text_valid)
print(result)
True
print(value)
['Waterloo', 'Aerial', 'Robotics', 'Group 15']
qr_text_invalid = "Avoid the area bounded by: Zulu; Bravo; Tango; Uniform. Rejoin the route at Lima"
result, value = qr_to_waypoint_names(qr_text_invalid)
print(result)
False
print(value)
None