# MAVROS: a MAVLink-to-ROS 2 bridge for drones

> MAVROS is the glue between the wire protocol flight controllers speak and the robotics framework people program in. It turns a PX4, ArduPilot or Flix autopilot into standard ROS 2 topics, services and parameters, and it can also act as a router, proxying between a ground station, the flight controller and several ROS processes over a single link.

**mavlink/mavros** — MAVLink to ROS gateway with proxy for Ground Control Station

- Repository: https://github.com/mavlink/mavros
- Stars: 1,246 · Forks: 1,127
- Language: C++
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/mavlink-mavros

## The flight controller speaks MAVLink, your code speaks ROS

MAVLink is the wire protocol most flight controllers speak, and ROS 2 is a robotics framework for building software. MAVROS is the glue between them, and the README puts the benefit plainly: it turns a MAVLink autopilot into a set of familiar ROS 2 topics, services and parameters, so you can program a drone in ROS the same way you would program any other robot, with no need to speak MAVLink.

The diagram in the README shows the three parties. The flight controller, running PX4 or ArduPilot, speaks MAVLink over UDP, TCP or serial to the MAVROS node, which contains the bridge and its plugins, and the MAVROS node in turn publishes and serves ROS 2 topics, services and parameters to your application, which is shown as three kinds of node, telemetry nodes, command nodes, and mission or ground control station nodes.

That middle box is the whole point of the project. A MAVLink message is a compact binary frame with a message id and a packed payload, and the set of ids is large and versioned. A ROS 2 topic is a typed, discoverable stream with a defined message definition. MAVROS is the translation layer between two entirely different models of what a piece of drone data is, and doing that by hand in an application is a large amount of work that has nothing to do with your actual task.

The autopilot list includes Flix alongside PX4 and ArduPilot, which is a reminder that MAVROS is aimed at the ecosystem rather than at one vendor.

## Telemetry out, commands in, and a router in the middle

The README describes the boring, low-level work the project does for you, and it falls into three groups.

Telemetry out is one direction. Autopilot state, IMU, GPS, attitude, battery and more arrive as standard sensor_msgs and mavros_msgs topics, so a subscriber writes against a message type rather than against a frame layout.

Commanding in is the other. Arm and disarm, takeoff, land, set mode, upload missions and upload geofences all go through familiar ROS 2 services. The important property here is that the service interface is the same everywhere, so the code that arms a vehicle does not change when the autopilot underneath does.

Routing is the third, and it is the one that is easy to overlook. MAVROS can proxy between a ground station, the FCU and multiple ROS processes over a single link. In practice that means a setup where a ground station, the autopilot and two ROS 2 processes all talk through the one node, rather than a mesh of links where each participant has to be able to reach each other.

Two supporting details make the deployment practical. The transport is flexible, covering USB or serial, UDP, TCP, or a shared UAS bus, so the same build works against a flight controller wired to a companion computer and against a simulated one. And the project is tested against PX4 and ArduPilot, including SITL simulation, which is the part that determines whether a flight stack change breaks your integration.

## The plugin architecture, one plugin per MAVLink message

The extensibility claim is specific: a plugin architecture translates each MAVLink message, and you add behaviour without touching the core.

That is the right shape for this problem, because the number of MAVLink messages is large and the set differs between autopilot families and firmware versions. If the translation lived in one large switch, every new message would be a change to shared code, and a fork of the bridge would be needed for any custom message. With plugins, a message that the autopilot sends and ROS 2 does not yet expose is a new plugin rather than a patch.

The plugin reference in the documentation is presented as every topic, service and parameter, which is the right way to publish this kind of mapping. A user does not want to know that MAVLink message 30 maps to a ROS 2 topic with a particular name and a particular frame convention, but they need to be able to look it up, and a reference of every topic, service and parameter is exactly the document that makes the bridge usable without reading the source.

The package list shows where the plugins live. The mavros package holds the core nodes, the Router and UAS, and the standard plugins, while mavros_extras holds the optional ones, covering cameras, gimbals and terrain among others. The split matters operationally, since a deployment that only needs flight control does not have to load the camera and gimbal plugins, and the extras are exactly the set that tends to break when a firmware release changes something.

## Installing it and pointing it at a flight controller

The quick start is three commands. First the package, and then the GeographicLib datasets, which the README calls mandatory:

```shell
sudo apt install ros-${ROS_DISTRO}-mavros
sudo ros2 run mavros install_geographiclib_datasets.sh
```

The second command exists because MAVROS needs geodetic data for conversions between geographic and local coordinates, and the datasets are large enough that they are not bundled with the package.

Then the launch, against a flight controller or a simulated one:

```shell
ros2 launch mavros node.launch \
  fcu_url:=udp://127.0.0.1:14550@127.0.0.1:14557
```

The URL syntax carries the transport and both ends of the link, and the local address and port are the ones a simulator on the same machine would use.

To check that it works, the README suggests echoing the sensor stream:

```shell
ros2 topic echo /mavros/imu/data
```

Getting IMU data out of a topic that is publishing at sensor rate is the right smoke test, because it proves the link is up in both directions without commanding the vehicle to do anything.

The documentation covers binary, source and container installs in the installation guide, and the examples directory has task control and waypoint missions. There is also a devcontainer in the repository, which matters for the contributors rather than for the operators.

## Six packages, and what each one is for

The package table is short and each entry earns its place.

mavros is the core, with the Router and UAS nodes and the standard plugins. mavros_extras is the optional plugin set, covering cameras, gimbals and terrain among others. mavros_msgs holds the ROS 2 message and service interfaces, which is the contract your application depends on and the package to look at when you want to know what a topic carries.

libmavconn is the MAVLink transport library, and the note that it is usable outside ROS is the interesting part. That means the MAVLink side of the problem can be reused in a component that is not a ROS node, which is what makes the proxy and router arrangements possible, and it is a reasonable choice for anyone who wants MAVLink handling without adopting the whole stack.

test_mavros holds the hand-tests and the SITL manual for PX4 and ArduPilot, which is the part that tells you how the project is actually validated. Hand-tests are the manual procedure for checking a specific behaviour against a specific autopilot, and the SITL manual covers the simulated case.

mavros_examples holds beginner-friendly ROS 2 example scripts, covering task control, waypoint missions and offboard. Offboard deserves a note, since it is the mode where an external computer sends position or velocity setpoints rather than a preloaded mission, and it is the first thing people want once the link is up.

The per-package C++ and Python API documentation is published on the ROS documentation site, so the packages are consumable from either language.

## Where MAVROS is the wrong tool

The first wrong-tool case is work inside the autopilot itself. If you are adding a flight mode, a new estimator or a driver in PX4 or ArduPilot, you are writing flight-stack code, not ROS 2 topics, and MAVROS is downstream of all of that. It is a bridge for the application side.

The second is a project that does not use ROS 2. The whole value proposition is that a ROS 2 application can talk to a drone without knowing MAVLink. If the rest of your stack is not ROS, you have added a large translation layer to get back to where you started, and libmavconn on its own would be the smaller answer.

The third is the ground control station case, and the README is honest about the boundary. MAVROS can proxy between a ground station, the FCU and multiple ROS processes over a single link, and that is a routing convenience, not a replacement for a GCS. Anything where a human flies the vehicle through a full ground station interface is a different product.

There is also the version matrix to plan for. The README lists build status for ROS 2 Humble, Jazzy, Kilted, Lyrical and Rolling, so the bridge tracks the ROS distribution cycle, and a project pinned to a distribution that ages out of that list will eventually be on a bridge release that no longer builds for it.

## Three licence files, and a release every few weeks

The repository carries four licence files, LICENSE-BSD.txt, LICENSE-GPLv3.txt, LICENSE-LGPLv3.txt and LICENSE.md, which is what a project with several separately licensed components looks like. The project licence is recorded as a custom licence that GitHub cannot classify, so the licence files and the LICENSE.md are the place to read rather than a badge.

That structure is not unusual for this kind of bridge. The ROS 2 side has its own licensing expectations, the transport library can be reused on its own, and the message definitions are a public interface that third parties build against. Separate files let each piece carry the terms that apply to it.

On versions, the release list shows 2.16.0 on 2026-09-27, 2.15.1 on 2026-08-22 and 2.15.0 on 2026-08-08. So minor, patch and minor inside two months, which for an infrastructure component is a brisk and healthy cadence. The repository is not archived, and the last push was on 2026-10-16, days before this review. The default branch is ros2, which reflects that the ROS 2 version is the development line rather than a leftover name.

The supporting files are those of a mature project. There is an AGENTS.md and a CONTRIBUTING.md, a SECURITY.md for reporting problems, a mkdocs.yml for the documentation build, a dependencies.rosinstall file for the ROS dependency resolution, a.devcontainer/ for a reproducible development environment, a.codespellrc for the spell checker, and a tools/ directory for the build helpers.

## Conclusion

Adopt MAVROS if you build drone software in ROS 2 and want to stop writing MAVLink parsing, and pin the release you use against the ROS 2 distribution you run, since the project ships a build for each of Humble, Jazzy, Kilted, Lyrical and Rolling. Do not adopt it if you are working on the flight stack itself in PX4 or ArduPilot, where MAVLink is native, and do not expect it to be a simulator, since it is a bridge and not a model of the vehicle. Before you deploy, run the GeographicLib dataset install step, which the quick start treats as mandatory, and read the plugin reference to know exactly which topics your autopilot's messages map to.

## FAQ

### What does MAVROS do for a drone application?

It turns a MAVLink autopilot such as PX4, ArduPilot or Flix into ROS 2 topics, services and parameters. Telemetry out, including autopilot state, IMU, GPS, attitude and battery, arrives as sensor_msgs and mavros_msgs topics, and arming, takeoff, landing, mode changes, mission uploads and geofence uploads go through ROS 2 services.

### How do I install MAVROS and start the bridge?

Install the package with sudo apt install ros-${ROS_DISTRO}-mavros and then run sudo ros2 run mavros install_geographiclib_datasets.sh, which the README treats as mandatory. Launch it with ros2 launch mavros node.launch fcu_url:=udp://127.0.0.1:14550@127.0.0.1:14557, then check the link with ros2 topic echo /mavros/imu/data.

### Which ROS 2 distributions does MAVROS build for?

The README shows build status for ROS 2 Humble, Jazzy, Kilted, Lyrical and Rolling, and states that it supports Humble and newer ROS 2 releases. The most recent release is 2.16.0, dated 2026-09-27, and the default branch is ros2.

### What is the difference between mavros and mavros_extras?

The mavros package holds the core nodes, the Router and UAS, and the standard plugins, while mavros_extras holds the optional plugins, covering cameras, gimbals and terrain among others. Both are built on a plugin architecture that translates each MAVLink message.

### Can MAVROS be used without ROS?

Partly. The libmavconn package is the MAVLink transport library and is described as usable outside ROS, which is what makes the proxy and router arrangements possible. The MAVROS node itself, the plugin set and the message interfaces are ROS 2 components.

## Sources

- [Issues](https://github.com/mavlink/mavros/issues)
- [mavlink/mavros on GitHub](https://github.com/mavlink/mavros)
- [README](https://github.com/mavlink/mavros/blob/ros2/README.md)
- [Releases](https://github.com/mavlink/mavros/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mavlink-mavros
