The FGCS backend is a Python Flask application that handles communication between the frontend and the drone via the MAVLink protocol.
Frontend (React/Electron)
↕ (Socket.IO/HTTP)
Backend (Flask/Socket.IO)
↕ (MAVLink/Serial/TCP)
Drone (ArduPilot/PX4)- Flask application with Socket.IO integration
- Handles drone connection management
- Routes HTTP requests and Socket.IO events
- Manages application state and logging
The central class that manages drone communication and state:
class Drone:
def __init__(self, port, baud=57600, ...):
# Core MAVLink connection
self.master = mavutil.mavlink_connection(...)
# Controller instances
self.paramsController = ParamsController(self)
self.armController = ArmController(self)
self.flightModesController = FlightModesController(self)
# ... other controllersKey Responsibilities:
- Establish and maintain MAVLink connection
- Initialize all controller instances
- Handle data stream management
- Process incoming MAVLink messages
- Manage connection state and error handling
The drone class sets up various MAVLink data streams to receive telemetry:
DATASTREAM_RATES = {
mavutil.mavlink.MAV_DATA_STREAM_RAW_SENSORS: 1,
mavutil.mavlink.MAV_DATA_STREAM_EXTENDED_STATUS: 1,
mavutil.mavlink.MAV_DATA_STREAM_RC_CHANNELS: 1,
mavutil.mavlink.MAV_DATA_STREAM_POSITION: 1,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA1: 4,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA2: 3,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA3: 1,
}}Stream Types and Messages:
- RAW_SENSORS: IMU data, pressure sensors
- EXTENDED_STATUS: System status, GPS, mission info
- RC_CHANNELS: Radio control inputs and servo outputs
- POSITION: Local and global position data
- EXTRA1: Attitude data (roll, pitch, yaw)
- EXTRA2: VFR HUD data (airspeed, groundspeed, etc.)
- EXTRA3: Battery status, system time, vibration
The command lock is a thread synchronization mechanism (typically implemented using Python’s threading.Lock) that ensures only one command is sent to the drone at a time. This is crucial because the MAVLink protocol and ArduPilot expect commands to be sent and acknowledged sequentially. Sending multiple commands simultaneously can lead to race conditions, command collisions, or unexpected drone behavior.
In practice:
Whenever a controller needs to send a command to the drone (e.g., change mode, set a parameter, arm/disarm), it acquires the command lock, sends the command, waits for a response, and then releases the lock. This guarantees orderly and reliable communication with the drone. This can be achieved either manually by acquiring and releasing the lock, or by using the sendingCommandLock decorator.
Note: If you acquire a lock inside a function which then uses another function which acquires the lock as well this will lead to the program halting. Ensure that the lock is released before any other function acquires it.
Controllers encapsulate specific drone functionality and handle related MAVLink commands.