Library / SDK
mavlink/mavlink avatar
mavlink/mavlink

mavlink/mavlink: generating the drone messaging library from XML dialects

Marshalling / communication library for drones.

2,442 stars2,260 forksPythonNOASSERTION

At a glance

What is it?
The MAVLink repository is not the wire protocol itself but the message-set definitions and the Python generator that turns them into C, C++ and other language bindings. This review covers how mavgen works, how to install it, and where the header-only model stops being the right choice.
Who is it for?
Adopt mavlink/mavlink if you are building a flight controller, ground station or companion computer that must interoperate with other vendors over a low-bandwidth link, and you are willing to own the code generation step in your build. Do not adopt it if you want a runtime broker that routes packets between endpoints: that is a different tool, and the README points at none.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What mavlink/mavlink actually ships, and who needs it

The repository is a specification and a code generator, not a running service. The README describes MAVLink as "a very lightweight, header-only message library for communication between drones and/or ground control stations" and says it "consists primarily of message-set specifications for different systems (dialects) defined in XML files, and Python tools that convert these into appropriate source code for supported languages." That distinction matters when you evaluate it. If you are looking for something to install on a vehicle and point at a serial port, the repository itself is not that. If you are writing the firmware, the ground station, or the companion-computer process that speaks on that port, this is where the message definitions and the generator live.

The audience is therefore narrow and technical: firmware engineers on resource-constrained boards, developers of ground control software, and anyone implementing an interoperability interface between components from different manufacturers. The README makes the bandwidth argument explicitly, noting that MAVLink "is very well suited to applications with very limited communication bandwidth" and that the C reference implementation is optimized for systems with limited RAM and flash. That is the design centre. A telemetry link at a few kilobits per second is the target, not a LAN.

One consequence of the XML-first design is that the repository is a shared namespace. Dialects under message_definitions/ define message IDs and field layouts, and changing them is a compatibility question, not a local refactor. If your product extends the common dialect, you are now maintaining a fork of a specification that other vendors also read.

How the XML dialects become C headers

The data flow is linear. A dialect XML file under message_definitions/v1.0 describes messages, fields and their types. The Python tool pymavlink.tools.mavgen reads that file and emits source for a chosen language and wire protocol version. The generated output is what your program compiles against. Nothing in that chain runs on the vehicle at runtime; the generator is a build-time step.

The README gives the C build as a single command against common.xml, producing headers under generated/include/mavlink/v2.0. Note the two flags that shape the output: --lang selects the target language, and --wire-protocol selects 2.0. The wire protocol version is a real choice, because a v2.0 library and a v1.0 peer are not automatically the same conversation. The README does not spell out the compatibility matrix in the quick start, so treat the choice as something to confirm against the documentation site rather than assume.

The cmake path wraps the same generator. CMakeLists.txt and MAVLinkConfig.cmake.in at the repository root let you install headers into a prefix and consume them with find_package(MAVLink REQUIRED). The README is candid about what that target means: "even though we use target_link_libraries in cmake, it doesn't actually 'link' to MAVLink as it's just a header-only library." So the cmake integration is a header-path and compile-flag convenience, not a link step. If your mental model is a shared object you ship alongside your binary, correct it now.

Because the output is generated, it belongs in your build graph, not in your editor. Regenerating after a dialect change is the normal workflow, and the generated tree should be treated as a build artifact. The repository does not document a rollback path for dialect changes, so version pinning of the dialect XML is something you arrange yourself.

Installing mavgen and generating your first header

The README targets Ubuntu LTS 20.04, 22.04 or 24.04 for the minimal environment. It also notes that the documentation site covers other Ubuntu platforms and Windows, so the commands below are the Linux path only. The clone uses --recursive, which the README requires; the repository has a .gitmodules entry, so a plain clone would leave submodule content missing.

bash
# Dependencies
sudo apt install python3-pip

# Clone mavlink into the directory of your choice
git clone https://github.com/mavlink/mavlink.git --recursive
cd mavlink

python3 -m pip install -r pymavlink/requirements.txt

After the requirements install, generate the MAVLink2 C library for the common dialect from the repository root. The output directory is created by the tool at the path you pass to --output.

bash
python3 -m pymavlink.tools.mavgen --lang=C --wire-protocol=2.0 --output=generated/include/mavlink/v2.0 message_definitions/v1.0/common.xml

What you should see is a header tree under generated/include/mavlink/v2.0 that your C sources can include. If you would rather let cmake drive it, the README gives this sequence, which installs headers into a local install directory with the dialect and version chosen at configure time.

bash
cmake -Bbuild -H. -DCMAKE_INSTALL_PREFIX=install -DMAVLINK_DIALECT=common -DMAVLINK_VERSION=2.0
cmake --build build --target install

Consuming it from another project means pointing cmake at that prefix. The README shows the pattern with a relative path, and it also points at examples/c and examples/cpp for full working programs, the C++ example requiring C++11.

bash
cd ../my_program
cmake -Bbuild -H. -DCMAKE_PREFIX_PATH=../mavlink/install

If your target is not C or C++, the README does not put the commands in the quick start. It defers to the documentation site's page on generating MAVLink libraries for the other supported languages. That is the honest place to look, because the flag values differ per language and the README does not enumerate them.

Where the header-only model costs you

The first limitation is the one the README states outright: there is no library to link. Every translation unit that includes the generated headers compiles the message machinery itself. On a small firmware target with one or two consumers that is fine, and it is exactly why the approach suits limited flash. In a larger C++ ground station with many translation units, the same property means the build does more work and you have no single place to patch behaviour without regenerating or wrapping.

The second is that the repository is a generator, so it inherits the failure modes of code generation. A dialect change produces a diff in generated files, and the README does not document a rollback procedure for a dialect or a generated tree. If your team is not comfortable treating generated code as a build output with a pinned input, this will chafe. The repository also carries no release information in the available documentation, so there is no changelog to read before you move a dialect forward.

The third is scope. MAVLink is a message marshalling layer. It defines how messages are laid out and encoded; it does not define how your process discovers peers, retries lost commands, or arbitrates between two links. Those are application concerns, and the README does not claim otherwise. Teams that adopt it expecting routing, connection management or a session layer will end up writing that themselves. If what you actually need is a packet broker between endpoints, this is the wrong repository, and the README points at no such component.

Finally, the licence signal is ambiguous in the repository metadata: the licence is reported as NOASSERTION while a COPYING file sits at the root. That is not a legal opinion, but it is a reason to read COPYING and the licence section of the documentation site before you ship a product around the generated headers.

MAVLink alternatives and the routing question

The related searches include "mavlink router" and "MAVLink alternatives", and the two are connected. A router is not a competing marshalling library; it is the layer above. The difference in approach is that mavlink/mavlink gives you typed messages and encoders that you compile into your program, while a router is a separate process that moves already-encoded MAVLink packets between endpoints such as a serial radio, a UDP link and a local application. If your problem is "two programs on this machine both want the telemetry stream", generating headers does not solve it.

On the alternatives axis, the honest framing is that MAVLink is a protocol with a reference implementation, not a category with many drop-in replacements. The realistic alternatives are other vehicle or telemetry protocols, and switching means switching the message set and the toolchain together, not swapping one library call for another. The README's interoperability claim, that the C implementation "serves as interoperability interface between components of different manufacturers", is the property you would be giving up.

A more useful comparison for most readers is between the two things inside this repository: the generated C headers and the Python tooling under pymavlink. The C path is the one the README optimizes for constrained targets. The Python path is where the generator, examples and utilities live. If you are prototyping on a companion computer, you may never compile a header at all.

Maintenance, licence and the cost of keeping up

The repository is not archived, and the last push was on 2026-09-27. That is a single day before the date used for this review, so the project is being pushed to. It is still worth separating activity from release discipline: the available information lists no recent releases, so there is no tagged version to pin against in the usual sense. Your pinning unit is therefore the commit you cloned, which is a fine practice but a deliberate one.

Upgrade cost concentrates in two places. First, the dialect XML: moving to a newer common.xml can add or change messages, and regenerating rewrites your headers. Second, the generator itself, which is Python under pymavlink and installed from pymavlink/requirements.txt. A requirements change is a build-environment change, and the README's install path targets specific Ubuntu LTS versions, so a jump in base image is the moment to re-run the install rather than assume it still resolves.

The repository also carries AGENTS.md, CLAUDE.md, a ruff.toml and a .github/ directory, which tells you the project has linting and CI conventions of its own. If you contribute dialect changes upstream, expect to follow those rather than your house style. On licensing, the metadata reports NOASSERTION and the root contains COPYING; the README links to a licence section on the documentation site. Read both before distributing generated headers in a product, and take your own advice on the legal question rather than this article's.

Editorial conclusion

Adopt mavlink/mavlink if you are building a flight controller, ground station or companion computer that must interoperate with other vendors over a low-bandwidth link, and you are willing to own the code generation step in your build. Do not adopt it if you want a runtime broker that routes packets between endpoints: that is a different tool, and the README points at none. Before committing, verify that the dialect XML you need is present under message_definitions/v1.0, check the pymavlink requirements install cleanly on your target Python, and confirm whether your project can live with a header-only C library plus generated code rather than a linkable binary. The licence file is COPYING, and the repository reports NOASSERTION, so resolve the actual terms before shipping.

Frequently asked questions

What is MAVLink?

The README describes it as a very lightweight, header-only message library for communication between drones and ground control stations, consisting primarily of XML message-set specifications called dialects plus Python tools that convert them into source code for supported languages.

How do I install MAVLink on Ubuntu?

The README gives a minimal environment for Ubuntu LTS 20.04, 22.04 or 24.04: install python3-pip, clone the repository with --recursive, then run python3 -m pip install -r pymavlink/requirements.txt from the mavlink directory. The documentation site covers other Ubuntu platforms and Windows.

How do I use MAVLink to generate C headers?

From the repository root, run python3 -m pymavlink.tools.mavgen with --lang=C, --wire-protocol=2.0, an --output path and a dialect XML such as message_definitions/v1.0/common.xml. The README shows this producing the MAVLink2 C library under generated/include/mavlink/v2.0.

What is the difference between MAVLink 1 and MAVLink 2?

The README does not document the differences between the two wire protocol versions. What it does show is that mavgen takes a --wire-protocol flag, with 2.0 used in the README examples, and that cmake takes a MAVLINK_VERSION option set to 2.0. Treat the choice as a compatibility decision to confirm against the documentation site.

Can I use mavlink/mavlink as a MAVLink router?

No. The repository holds message-set XML definitions and the Python generator that turns them into source code, and the README describes no routing or packet-brokering component. Routing between links is a separate process you would run alongside the generated libraries.

How do I set up MAVLink for a project?

The README's quick start is the setup path: clone with --recursive, install pymavlink/requirements.txt, then either run pymavlink.tools.mavgen directly or configure cmake with MAVLINK_DIALECT and MAVLINK_VERSION and install the headers into a prefix. The documentation site covers the remaining languages and platforms.

Official sources

  1. Issues
  2. mavlink/mavlink on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mavlink-mavlink.svg)](https://hysenlabs.com/projects/mavlink-mavlink)