The Flight Controller Communication sub-application establishes connection to the flight controller, retrieves hardware information, downloads parameters and their default values. This is a critical component that enables the ArduPilot Methodic Configurator to communicate with ArduPilot-based flight controllers using the MAVLink protocol.
discover_connections() (USB, TCP, UDP, serial)serial.tools.list_ports and network portsconnect(), maintenance via heartbeat, and termination via disconnect()__create_connection_with_retry()BackendFlightcontrollerInfo class__process_autopilot_version()download_params() with both MAVLink and MAVFTP methodsannotate_params.Par classdownload_params_via_mavftp()set_param() and verificationpymavlink.mavutilMAVFTP class (1656 lines of implementation)__create_connection_with_retry()set_param() confirmationThe flight controller communication system uses a delegation pattern where the main
FlightController class acts as a facade, delegating operations to specialized manager classes.
This architecture provides:
backend_flightcontroller.pyFlightController: Facade class coordinating all operationsconnect(): Delegates to connection managerdownload_params(): Delegates to params managerset_param(): Delegates to params manager (returns tuple[bool, str])test_motor(): Delegates to commands managerupload_file(): Delegates to files manager_connection_manager_params_manager_commands_manager_files_managerFlightControllerConnection for connection managementFlightControllerParams for parameter operationsFlightControllerCommands for command executionFlightControllerFiles for file operationsbackend_flightcontroller_connection.pyFlightControllerConnection: Connection establishment and managementFakeSerialForTests: Mock serial class for unit testingconnect(): Establishes connection with retry logicdisconnect(): Closes connection gracefullydiscover_connections(preserved_connections): Auto-detects available ports and merges caller-supplied
history entries that are not physically present on the busregister_and_try_connect(): Registers and connects to portcreate_connection_with_retry(): Connection with retry logicFlightControllerInfo (single source of truth)pymavlink.mavutil for MAVLink protocolserial.tools.list_ports for port discoveryFlightControllerInfo for metadata storagetime and logging for operationsbackend_flightcontroller_reconnect.py keeps the original nonempty FC hardware UID,
selected endpoint and active baud rate for one editor session. Its PyMAVLink message
hook only timestamps heartbeats from the selected system and component. Hooks run
before receive filters, so plugin reads continue to receive their expected replies.
frontend_tkinter_connection_recovery.py owns the timer, recovery worker and lifecycle
states: MONITORING, RECOVERING, STOPPING and STOPPED. The editor supplies typed
callbacks for receiver suspension, control locking, status display and parameter-cell
refresh. Worker threads perform backend I/O; UI callbacks run on the Tk thread.
The coordinator checks once per second. It reads a bounded batch only when no plugin
or sub-application owns reception. Synchronous operations retain an operation() lease
across nested Tk event loops; the file browser holds an acquire_operation() lease
until its close callback runs. Parameter upload previews and export windows retain
a lease until their root is destroyed, including when withdrawn or running without
a modal grab. Releases are idempotent, and the last release renews the heartbeat
grace period. Navigation locks and modal grabs remain defensive checks for callers
without an explicit lease. Window visibility alone does not imply receive ownership;
tools that outlive their opening callback must retain a lease for their full lifetime.
With an active plugin, checks are passive. After eight seconds without an observed
target heartbeat, the coordinator pauses the plugin and checks buffered packets before reconnecting.
The optional SuspendablePlugin protocol accepts a PluginPauseReason:
EXCLUSIVE_OPERATION stops actuators before FC tools take reception;
CONNECTION_RECOVERY yields reception without sending actuator commands.
resolve_plugin_lifecycle() selects the same paired hooks for recovery eligibility
and suspension, preferring suspend/resume over the legacy hide/show pair.
Plugins must stop receive timers when suspended or deactivated; a view without either
paired lifecycle interface retains ownership and defers reconnection.
During recovery, navigation and plugin controls are disabled. One worker attempts the
original endpoint at the original baud rate; USB metadata can locate renumbered
interfaces. The original endpoint is preferred when available. If metadata is shared
or the USB interface description changes, other matching interfaces are tried too,
and each failed attempt logs its reason. The hardware UID and original MAVLink system/component
IDs must match before downloading fresh parameters. This prevents a routed version message
from the original FC from authorizing a different target.
Changed or unknown IDs, connection failures and incomplete downloads leave the editor
waiting and retrying. A missing original UID disables automatic recovery. Hardware
identification uses uid2, falling back to uid, as decoded by the connection manager.
Refresh downloads use temporary files. Local parameter edits and the selected step remain intact; interrupted uploads and commands are never replayed. The editor resumes the plugin after a verified recovery. Closing cancels retries, waits for an in-flight worker to return from backend I/O and removes only the editor’s observer hook. The coordinator retains control ownership until that worker yields, discards late success after cancellation, and never resumes the plugin while closing. Recovery passes its cancellation event through the parameter facade to both download protocols. MAVLink reception checks cancellation in short (at most 100 ms) receive slices; only new parameter names renew its no-progress deadline, so repeated replies cannot retain ownership indefinitely. MAVFTP checks cancellation inside its reply loop and performs session cleanup on the worker before yielding. Normal transport-specific download budgets remain unchanged. A single pending-close chain keeps Tk responsive, displays the shutdown wait status, and offers to save only after the worker exits.
backend_flightcontroller_params.pyFlightControllerParams: Parameter download, set, and fetchdownload_params(): Downloads via MAVLink or MAVFTPset_param(): Sets parameter (returns tuple[bool, str])fetch_param(): Fetches single parameter with timeoutget_param(): Gets parameter from cache with defaultmaster, info, comport_deviceFlightControllerConnectionProtocol for connection stateMAVFTP for efficient parameter downloadsParDict for parameter storagebackend_flightcontroller_commands.pyFlightControllerCommands: Command execution and status queriessend_command_and_wait_ack(): Sends command and waits for ACKtest_motor(): Tests individual motortest_all_motors(): Tests all motors simultaneouslystop_all_motors(): Emergency stopget_battery_statuses(): Queries battery telemetry keyed by zero-based MAVLink battery IDreset_all_parameters_to_default(): Resets parametersmaster connectionFlightControllerConnectionProtocol for connectionFlightControllerParamsProtocol for parametersbackend_flightcontroller_files.pyFlightControllerFiles: File upload/download operationsupload_file(): Uploads file to flight controllerdownload_last_flight_log(): Downloads latest log filemaster and infoFlightControllerConnectionProtocol for connectionMAVFTP for file transfer protocolbackend_flightcontroller_protocols.pyFlightControllerConnectionProtocol: Connection manager contractFlightControllerParamsProtocol: Parameters manager contractFlightControllerCommandsProtocol: Commands manager contractFlightControllerFilesProtocol: Files manager contractpreserved_connections is typed as Optional[Sequence[str]] (read-only iterable contract)
rather than list[str], allowing callers to pass tuples or other sequences without forcing materialisation.Type Checking Pattern:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from backend_flightcontroller_protocols import FlightControllerConnectionProtocol
This prevents circular imports while enabling type hints
backend_flightcontroller_business_logic.pycalculate_voltage_thresholds(): Battery voltage limitsis_battery_monitoring_enabled(): Battery monitoring checkget_frame_info(): Frame class and type extractionvalidate_battery_voltage(): Voltage safety validationbackend_flightcontroller_factory_mavftp.pycreate_mavftp(): Creates MAVFTP instance with error handlingcreate_mavftp_safe(): Safe creation returning None on failurebackend_mavftp.pyMAVFTP: Complete FTP-over-MAVLink implementationpymavlink.mavutil for MAVLink message handlingstruct for binary data packing/unpackingrandom for session ID generationos and time for file system operationsdata_model_flightcontroller_info.pyBackendFlightcontrollerInfo: Processes and stores FC informationdata_model_fc_ids.py (Auto-generated)frontend_tkinter_connection_selection.pyConnectionSelectionWidgets: Manages connection UI componentsConnectionSelectionWindow: Main window for connection selectionPairTupleCombobox_refresh_ports() that preserves history entries not currently on the bus_connection_history_cache loaded once at init from ProgramSettings to avoid repeated disk I/O on every refresh cycle;
updated in-memory after each successful connection or manual addreconnect() persists the user-selected connection string (falling back to the detected device path for auto-connect) rather than
the possibly resolved symlink target (e.g. /dev/ttyACM0)tkinter and tkinter.ttk for GUI componentsPairTupleCombobox for connection selection widgetBaseWindow for consistent window behaviorProgressWindow for connection progress displayProgramSettings for persistent connection historyfrontend_tkinter_flightcontroller_info.pyFlightControllerInfoPresenter: Business logic separated from UIFlightControllerInfoWindow: Main information display windowtkinter and tkinter.ttk for GUI componentsBaseWindow for consistent window behaviorProgressWindow for parameter download progressannotate_params.Par for parameter handling__main__.py via connect_to_fc_and_set_vehicle_type() functionFlightController facade created with dependency injection supportFlightControllerInfo instancediscover_connections() delegates to connection manager for port detectionConnectionSelectionWindow is displayed for manual selectionFlightController.connect() delegates to connection_manager.connect()create_connection_with_retry()_detect_vehicles_from_heartbeats()_select_supported_autopilot()FlightControllerInfo (sole mutator)AUTOPILOT_VERSION message_retrieve_autopilot_version_and_banner() processes responses_process_autopilot_version()FlightControllerInfo_extract_firmware_type_from_banner()_extract_chibios_version_from_banner()FlightController.download_params() delegates to params managerinfo.is_mavftp_supportedparams_manager.fc_parameters dictionaryFlightController.test_motor() delegates to commands managersend_command_and_wait_ack() handles MAVLink command protocolget_battery_statuses() with independent caching and expiry per battery IDmaster is not None before executionProgressWindow during operationsshow_no_connection_error() and message boxesFlightControllerInfoWindow with formatted informationset_param() now returns tuple[bool, str] for explicit error handlingconnect_to_fc_and_set_vehicle_type() in __main__.pyFlightController object with fc_parameters dict and set_param() methodbackend_filesystem.py for parameter file storage and metadata managementbackend_internet.py when neededcommon_arguments.py for connection and reboot configurationBaseWindow, ProgressWindow, and custom tkinter componentsProgramSettings (settings.json) and restored on startupThe flight controller communication system has comprehensive test coverage organized by testing approach:
@pytest.mark.integration for integration test scenariostest_user_can_*@pytest.mark.integration and @pytest.mark.sitl markerstest_user_can_* describing user workflows@pytest.mark.integration and/or @pytest.mark.sitl# Run all flight controller tests
pytest tests/test_*flightcontroller*.py -v
# Run only unit tests (skip SITL integration tests)
pytest tests/test_*flightcontroller*.py -m "not sitl" -v
# Run only integration tests
pytest -m integration tests/ -v
# Run only SITL integration tests
pytest -m sitl tests/ -v
# Run with coverage for backend flight controller modules
pytest tests/test_*flightcontroller*.py --cov=ardupilot_methodic_configurator.backend_flightcontroller --cov-report=html
# Run specific test file
pytest tests/test_backend_flightcontroller_params.py -v
# Facade and coordination
backend_flightcontroller.py # Main facade delegating to managers
# Specialized managers (delegation pattern)
backend_flightcontroller_connection.py # Connection management
backend_flightcontroller_params.py # Parameter operations
backend_flightcontroller_commands.py # Command execution
backend_flightcontroller_files.py # File operations via MAVFTP
# Protocol definitions and utilities
backend_flightcontroller_protocols.py # Protocol interfaces for DI
backend_flightcontroller_business_logic.py # Pure business logic functions
backend_flightcontroller_factory_mavftp.py # MAVFTP factory functions
# Data models and supporting files
data_model_flightcontroller_info.py # Flight controller metadata
backend_mavftp.py # FTP-over-MAVLink implementation
data_model_fc_ids.py # Hardware identification (auto-generated)
# User interface
frontend_tkinter_connection_selection.py # Connection selection GUI
frontend_tkinter_flightcontroller_info.py # Information display GUI
socket for network connectionsserial for USB/serial connectionsthreading for non-blocking operationstime for timeout handlingstruct for binary data packingpymavlink for MAVLink protocol implementationtkinter for GUI componentspyserial for serial port communicationbackend_filesystem for parameter file operationsbackend_internet for downloading documentationfrontend_tkinter_base_window for GUI base classesfrontend_tkinter_progress_window for progress dialogs