Mavio #
A minimalistic library for transport-agnostic
MAVLink communication. It supports no-std
(and no-alloc
) targets.

repository
crates.io
API docs
issues
Features #
Mavio is a building block for more sophisticated tools. It is entirely focused on one thing: to include absolute minimum of functionality required for correct communication with everything that speaks MAVLink protocol.
- Supports both
MAVLink 1
andMAVLink 2
protocol versions. - Provides intermediate MAVLink packets decoding as “frames” that contain only header, checksum and signature being deserialized. Which means that client don’t have to decode the entire message for routing and verification.
- Supports optional high-level message decoding by utilizing MAVLink abstractions generated by MAVSpec.
- Includes standard MAVLink dialects enabled by Cargo features.
- Implements message verification via checksum.
- Includes tools for message signing.
In other words, Mavio implements all stateless features of MAVLink protocol. Which means that it does not provide support for message sequencing, automatic heartbeats, etc. The client is responsible for implementing these parts of the protocol by their own or use a dedicated library. We’ve decided to keep Mavio as simple and catchy as an 8-bit melody.
At the same time, Mavio is flexible and tries to dictate as few as possible. In particular:
- It supports custom dialects or may work with no dialect at all (for intermediate decoding). The latter is useful if you want to simply route or sign messages.
- Can read and write messages to anything that implements
std::io::Read
andstd::io::Write
traits. - Compatible with
no_std
targets. For such cases the library provides simplified versions ofRead
andWrite
traits. - Support asynchronous I/O via Tokio.
Install #
Install Mavio with cargo:
cargo add mavio
Usage #
For details, please check API documentation.
Receiving MAVLink Frames #
Connect as a TCP client, receive 10 frames, and decode any received
HEARTBEAT
message:
use std::net::TcpStream;
use mavio::{Frame, Receiver};
use mavio::dialects::minimal as dialect;
use dialect::Message;
fn main() -> mavio::errors::Result<()> {
let mut receiver = Receiver::new(TcpStream::connect("0.0.0.0:5600")?);
for i in 0..10 {
let frame = receiver.recv()?;
if let Err(err) = frame.validate_checksum(dialect::spec()) {
eprintln!("Invalid checksum: {err:?}");
continue;
}
if let Ok(Message::Heartbeat(msg)) = dialect::decode(frame.payload()) {
println!(
"HEARTBEAT #{}: mavlink_version={:#?}",
frame.sequence(),
msg.mavlink_version,
);
}
}
}
A slightly more elaborated use-case can be found in
tcp_client.rs
example.
Sending MAVLink Frames #
Listen to TCP port as a server, send 10 HEARTBEAT
messages
to any connected client using MAVLink 2 protocol, then disconnect a client.
use std::net::TcpStream;
use mavio::{Frame, Sender};
use mavio::protocol::MavLinkVersion;
use mavio::dialects::minimal as dialect;
use dialect::Message;
use dialect::enums::{MavAutopilot, MavModeFlag, MavState, MavType};
fn main() -> mavio::errors::Result<()> {
let mut sender = Sender::new(TcpStream::connect("0.0.0.0:5600")?);
let mavlink_version = MavLinkVersion::V2;
let system_id = 15;
let component_id = 42;
for sequence in 0..10 {
let message = dialect::messages::Heartbeat {
type_: MavType::FixedWing,
autopilot: MavAutopilot::Generic,
base_mode: MavModeFlag::TEST_ENABLED
& MavModeFlag::CUSTOM_MODE_ENABLED,
custom_mode: 0,
system_status: MavState::Active,
mavlink_version: 3,
};
println!("MESSAGE #{}: {:#?}", sequence, message);
let frame = Frame::builder()
.set_sequence(sequence)
.set_system_id(system_id)
.set_component_id(component_id)
.build_for(&message, mavlink_version)?;
sender.send(&frame)?;
println!("FRAME #{} sent: {:#?}", sequence, frame);
}
}
Check tcp_server.rs
for a slightly more elaborated use-case.
API Notes #
This section provides a general API overview. For further details, please check API documentation.
I/O #
Mavio provides two basic I/O primitives: Sender
and
Receiver
. These structs send and receive instances of
Frame
.
Sender
and Receiver
are generic over std::io::Write
and
std::io::Read
accordingly. That means you can communicate MAVLink
messages over various transports which implements these traits including UDP, TCP, Unix sockets, and files. It is also
easy to implement custom transport.
No-std #
For no-std
targets Mavio provides custom implementations of Read
and Write
traits. You can implement them for
hardware-specific communication (like serial ports).
Async I/O #
For asynchronous I/O Mavio provides AsyncSender
and
AsyncReceiver
which work in the same fashion as their
synchronous counterparts, except using Tokio
. To enable asynchronous support, add tokio
feature
flag.
Encoding/Decoding #
Upon receiving, MAVLink Frame
s can be validated and decoded
into MAVLink messages. Frames can be routed, signed, or forwarded to another system/component ID without decoding.
Note!
MAVLink checksum validation requires
CRC_EXTRA
byte which its turn depends on a dialect specification. That means, if you are performing dialect-agnostic routing from a noisy source or from devices which implement outdated message specifications, you may forward junk messages. In case of high-latency channels you might want to enforce compliance with a particular dialect to filter incompatible messages.
To decode a frame into a MAVLink message, you need to use a specific dialect. Standard MAVLink dialects are available
under mavio::dialects
and can be enabled by the corresponding
feature flags:
minimal
β minimal dialect required to expose your presence to other MAVLink devices.standard
β a superset ofminimal
dialect which expected to be used by almost all flight stack.common
β minimum viable dialect with most of the features, a building block for other future-rich dialects.ardupilotmega
β feature-full dialect used by ArduPilot. In most cases this dialect is the go-to choice if you want to recognize almost all MAVLink messages used by existing flight stacks.all
β meta-dialect which includes all other standard dialects including these which were created for testing purposes. It is guaranteed that namespaces of the dialects inall
family do not collide.- Other dialects from MAVLink XML definitions:
asluav
,avssuas
,csairlink
,cubepilot
,development
,icarous
,matrixpilot
,paparazzi
,ualberta
,uavionix
. These do not includepython_array_test
andtest
dialects which should be either generated manually or as a part ofall
meta-dialect.
Custom Dialects #
Concrete implementations of dialects are generated by MAVSpec check its
documentation for details. You may also found useful to review
build.rs
, if you want to generate
your custom dialects.