Skip to content
msmith626Public

About

Configure, calibrate and diagnose ArduPilot flight controllers over MAVLink. One tested core behind a Python API, a CLI and an MCP server for AI agents: read-only by default, human-approved parameter changes with read-back, identity-checked backups, guided calibrations with evidence-based results. Complements MAVProxy.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

MAVForge

CI

Intelligent tools for flight controllers.

MAVForge is an open-source engineering toolkit for configuring, diagnosing and (soon) calibrating MAVLink flight controllers, starting with ArduPilot. One tested core is exposed three ways:

  • a Python API for scripts and other programs
  • a one-shot CLI (mavforge) with --json output and stable exit codes
  • an MCP server (mavforge-mcp) so AI agents can use the same operations under the same safety policy

MAVForge complements interactive ground stations such as MAVProxy and Mission Planner. It does not replace them: there is no console, map, mission planning or flight control. See docs/mavproxy.md.

Status: pre-alpha (0.1.0.dev0). Parameter changes work, behind a reviewed and approved plan with read-back verification. Gyro, level, compass and 6-position accel calibration work as verified state machines; see docs/calibration.md. Nothing MAVForge reports means a vehicle is safe to fly.

What works today

Operation API CLI MCP tool Verified against
Identify vehicle (autopilot, firmware, git hash, board, capabilities, SITL detection) vehicle.info() mavforge info vehicle_info fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Status snapshot (armed, mode, sensors, pre-arm flag, battery, GPS, STATUSTEXT) vehicle.status() mavforge status vehicle_status fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Download all parameters, glob filter, gap recovery; prefers MAVFTP's packed param.pck (far fewer round trips) when the vehicle reports FTP support, falling back to PARAM_REQUEST_LIST on any FTP-specific failure vehicle.params.list() mavforge params list params_list fake vehicle, ArduCopter 4.7.2 SITL (1369 params), ArduPlane 4.6.2 hardware (1117 params over USB serial: 1.11s via FTP vs 16.28s via PARAM_REQUEST_LIST)
Read one parameter vehicle.params.get() mavforge params get params_get fake vehicle, ArduCopter 4.7.2 SITL
Back up all parameters with vehicle identity (JSON, optional .param export) vehicle.params.backup() mavforge params backup params_backup fake vehicle, ArduCopter 4.7.2 SITL
Diff vehicle vs a backup or .param file; diff two files offline vehicle.params.diff(), mavforge.diff_backups() mavforge params diff params_diff fake vehicle, ArduCopter 4.7.2 SITL
Diff vehicle vs the firmware's own shipped defaults (what's changed from stock); needs MAVFTP vehicle.params.diff_defaults() mavforge params diff-defaults params_diff_defaults fake vehicle, ArduCopter 4.7.2 SITL (42/1369 differ), ArduPlane 4.6.2 hardware (76/1117 differ)
Diagnose: classified findings (fault / warning / suspected / not checked / passed) from vehicle pre-arm reports, sensor health and ArduPilot configuration rules; propose_fixes also builds a change plan for findings with a safe, judgment-free default; baseline also compares against a saved backup (the same comparison params diff does on its own), surfaced as report.baseline vehicle.diagnose(propose_fixes=..., baseline=...) mavforge diagnose [--propose-fixes] [--baseline ID-OR-FILE] diagnose (baseline_backup_id - agents name a backup by id only, same as params_diff) fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware (all incl. propose_fixes)
Setup status: ArduPilot's own first-time setup sequence as a checklist (done / needed / recommended / unknown / not_applicable per step), derived from diagnose; next_step names what to run next vehicle.setup_status() mavforge setup setup_status fake vehicle, ArduCopter 4.7.2 SITL
List backups mavforge.list_backups() mavforge params backups params_backups fake vehicle
Change parameters: plan (validated against firmware metadata), human approval, backup, write, read-back verification vehicle.params.plan(), mavforge.approve_plan(), vehicle.params.apply() mavforge params set, params plan, approve, params apply, params plans params_plan, params_apply, params_plans (with --allow-configure) fake vehicle (incl. rejected, clamped, ignored writes, link loss), ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Calibrate: gyro, level, onboard compass, 6-position accelerometer (guided, approved, evidence-based success) vehicle.calibration.request()/start()/status()/confirm()/cancel() mavforge calibrate gyro|level|compass|accel|list calibration_procedures, calibration_request, calibration_start, calibration_status, calibration_cancel (with --allow-calibrate; accel not via MCP) fake vehicle, ArduCopter 4.7.2 SITL (all four), ArduPlane 4.6.2 hardware (compass, gyro, level)
Radio (RC) calibration: guided stick sweep that proposes RCn_MIN/MAX/TRIM as a change plan vehicle.calibration.start_radio(), then approve_plan and params.apply mavforge calibrate radio [--plan-only] not via MCP fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Board orientation check: three guided poses that find how the flight controller is mounted and propose AHRS_ORIENTATION as a change plan vehicle.calibration.start_orientation(), then approve_plan and params.apply mavforge calibrate orientation [--plan-only] not via MCP fake vehicle, ArduCopter 4.7.2 SITL (simulated rotated board), ArduPlane 4.6.2 hardware
Flight mode assignment: sweeps the FLTMODE_CH switch to confirm each requested position is reachable, then proposes FLTMODE1..FLTMODE6 as a change plan vehicle.calibration.start_flight_modes(), then approve_plan and params.apply mavforge calibrate flight-modes FLTMODEn=VALUE ... [--plan-only] not via MCP fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Restore from a backup (identity-checked) vehicle.params.plan_restore() mavforge params restore params_plan_restore fake vehicle, ArduCopter 4.7.2 SITL, ArduPlane 4.6.2 hardware
Retry whatever a previous apply left unresolved (unknown/not_attempted only — typically a link loss) at its original value vehicle.params.plan_retry() mavforge params retry <plan-id> params_plan_retry (with --allow-configure) fake vehicle
List operations and permissions mavforge.capabilities() mavforge capabilities mavforge_capabilities unit tests

Hardware evidence so far is one board: ArduPlane 4.6.2 on a USB-connected flight controller.

  • Python API (2026-10-21): the read-only tests passed (tests/hardware).
  • CLI (2026-10-21 to 23): status, diagnose, backup/diff, and a verified two-parameter change and restore were run.
  • MCP has not been run against hardware.

Only ArduPilot has a platform adapter. Other autopilots get a generic read-only adapter that has not been tested.

Install (development)

Requires Python ≥ 3.12 and uv.

git clone https://github.com/msmith626/mavforge.git && cd mavforge
uv sync
uv run mavforge --help

Quick start

# ArduPilot SITL in Docker (see docs/sitl.md)
docker build -t mavforge-sitl:4.7.2 docker/sitl
docker run --rm -p 127.0.0.1:5760:5760 mavforge-sitl:4.7.2 &

uv run mavforge -c tcp:127.0.0.1:5760 --timeout 30 info
uv run mavforge -c tcp:127.0.0.1:5760 status
uv run mavforge -c tcp:127.0.0.1:5760 diagnose            # add --fail-on fault in scripts
uv run mavforge -c tcp:127.0.0.1:5760 params list 'COMPASS_*'
uv run mavforge -c tcp:127.0.0.1:5760 --json params get FRAME_CLASS

# Snapshot before changing anything, then see what changed later
uv run mavforge -c tcp:127.0.0.1:5760 params backup --param-file before.param
uv run mavforge params backups
uv run mavforge -c tcp:127.0.0.1:5760 params diff <backup-id>
uv run mavforge params diff known-good.param --against <backup-id>   # offline

# Change parameters: shows the plan and asks before writing; verifies by read-back
uv run mavforge -c tcp:127.0.0.1:5760 params set BATT_FS_LOW_ACT=2 ARMING_CHECK=1
uv run mavforge -c tcp:127.0.0.1:5760 params restore <pre-change-backup-id>   # undo

# Calibrate: shows what you'll need to do, asks, then guides you live
uv run mavforge calibrate list
uv run mavforge -c /dev/ttyACM0 calibrate compass
uv run mavforge -c /dev/ttyACM0 calibrate radio     # sweep the sticks, review the plan, apply
uv run mavforge -c /dev/ttyACM0 calibrate orientation  # tilt three ways: is AHRS_ORIENTATION right?

To use a real flight controller over USB, run mavforge -c /dev/ttyACM0 info. For a wireless link instead (tested against a SpeedyBee F405 WING's onboard WiFi), see docs/wireless.md.

Global options go before the command. You can also put the connection in MAVFORGE_CONNECTION instead of passing -c. Exit codes:

Code Meaning
0 OK
1 Failed
2 Usage error
3 Connection failed
4 Timeout or unknown outcome
5 Not permitted
6 Unsupported
7 Partial result

Python API

import mavforge

with mavforge.connect("tcp:127.0.0.1:5760", timeout=30) as vehicle:
    print(vehicle.identity.firmware)  # e.g. 4.7.2
    result = vehicle.params.list("INS_*")
    if result.status != "succeeded":  # partial downloads are reported, not hidden
        print("missing:", result.missing_indices)
    for p in result.params:
        print(p.name, p.value, p.type)

MCP (AI agents)

uv run mavforge-mcp --connection tcp:127.0.0.1:5760

See docs/mcp-setup.md for client configuration.

Safety model (short version)

  • Changes are planned, approved, verified. Every parameter change is a saved plan.
    • The plan shows current and new values, documented ranges and value names, and reboot and safety warnings.
    • A human approves it: by prompt, mavforge approve, or an MCP elicitation. The approval is bound to the plan's SHA-256 and the vehicle's identity, expires after 10 minutes, and is single-use.
    • MAVForge then takes a backup, refuses values that changed since planning, writes each value and reads it back. Results per parameter are verified, failed, unknown, skipped or not attempted.
    • Writes are refused while the vehicle is armed.
  • Read-only by default for agents. The MCP server exposes change tools only with --allow-configure, and touches real hardware only with --allow-real-vehicle. Agents cannot approve plans.
  • No arming, motor tests or flight control, by design.
  • The operator picks the vehicle link when starting the MCP server; agents can't choose it.
  • Backups are never overwritten and are created owner-only (mode 0600) under ~/.local/state/mavforge/backups/.
  • Every operation is audited to ~/.local/state/mavforge/audit.jsonl (mode 0600), with the interface (api/cli/mcp), the vehicle identity and the outcome.
  • Vehicle text is treated as untrusted. It is rendered inertly in the terminal and marked as data for agents.
  • MAVForge never sends HEARTBEATs, so it cannot mask a GCS-failsafe condition.

Details: docs/architecture.md, docs/risks.md.

Development

uv run ruff format --check . && uv run ruff check . && uv run pyright
uv run pytest            # unit + integration (fake vehicle), no hardware needed
uv run pytest -m sitl    # ArduCopter SITL in Docker
MAVFORGE_HW_CONNECTION=/dev/ttyACM0 uv run pytest -m hardware   # opt-in, read-only

Documentation

License

GPL-3.0-or-later. See LICENSE and THIRD_PARTY_NOTICES.md.

About

Configure, calibrate and diagnose ArduPilot flight controllers over MAVLink. One tested core behind a Python API, a CLI and an MCP server for AI agents: read-only by default, human-approved parameter changes with read-back, identity-checked backups, guided calibrations with evidence-based results. Complements MAVProxy.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages