pamoja-mavlink 0.1.17

MAVLink for pamoja: build, parse, and sign v1/v2 frames (CRC-16/MCRF4XX, per-message CRC_EXTRA, MAVLink 2 SHA-256 signing), a typed common dialect with MAVLink 2 extension fields, the mission, command, and offboard protocols as sans-IO state machines, and a vehicle modelled as a pamoja Device driven over real serial, UDP, and TCP links. Hand-written from the mavlink.io spec, no_std and allocation-free at the core, and exercised against ArduPilot and PX4 SITL.
Documentation

pamoja-mavlink

MAVLink for pamoja: build, parse, and sign v1/v2 frames (CRC-16/MCRF4XX, per-message CRC_EXTRA, MAVLink 2 SHA-256 signing), a typed common dialect with MAVLink 2 extension fields, the mission, command, and offboard protocols as sans-IO state machines, and a vehicle modelled as a pamoja Device driven over real serial, UDP, and TCP links. Hand-written from the mavlink.io spec, no_std and allocation-free at the core, and exercised against ArduPilot and PX4 SITL.

The same capability in every language

Language Package Reference
Rust pamoja-mavlink reference, docs.rs, install
TypeScript @pamoja/mavlink reference, install
Python pamoja-mavlink reference, install
C# Pamoja.Mavlink reference, install

The MAVLink wire protocol for the pamoja SDK.

MAVLink is the language drones speak: PX4 and ArduPilot autopilots and MAVSDK ground stations all exchange MAVLink frames, so talking to a vehicle means putting exactly the right bytes on the wire and trusting the bytes that come back. This crate is that byte layer, hand-written from the MAVLink specification and pinned to its reference values rather than guessed from memory:

  • crc16_mcrf4xx - the CRC-16/MCRF4XX every frame carries, the checksum that lets a receiver reject a frame mangled in transit, anchored to the catalogue check value.
  • Frame - the v1 and v2 frame on the wire, which both assembles a frame to send and parses one received, verifying the checksum and the per-message message_crc_extra seed so a corrupt or mismatched frame never reaches the application.
  • Parser - a streaming parser that turns the bytes a link delivers into whole frames, resynchronizing on noise so a serial port or UDP socket just works.
  • signing - MAVLink 2 message signing: the SHA-256 signature and the monotonic timestamp that let a ground station trust a command came from the vehicle it expects and was not replayed.
  • dialect - a broad, typed slice of the common dialect (HEARTBEAT, the command, parameter, and mission protocols, and core telemetry), plus message shapes as data: a MessageDescriptor gives any message's bytes named fields, and a builder describes one this crate does not type, so a vendor or private dialect is usable at runtime.
  • protocol - the mission, command, and offboard exchanges as pure, allocation-free state machines: the rules of order, matching, and retransmission that turn single messages into a real conversation with an autopilot, with no IO of their own. Each machine also takes a Frame at a time and hands back the frame to send, so a caller holding a link writes no decoding or dispatch of its own.

The protocol core is no_std and allocation-free, so the same framing runs on a microcontroller flight controller. The default std feature adds the async layer: the byte-stream link seam and an in-process software-in-the-loop autopilot (link), the vehicle device model that presents an autopilot as a pamoja Device, and the real drivers (UDP, TCP, and serial behind the serial feature) that carry MAVLink to a real or simulated autopilot.

Examples

use pamoja_mavlink::dialect::{Heartbeat, Message};
use pamoja_mavlink::{Frame, Header};

// Announce this node as an onboard controller.
let heartbeat = Heartbeat {
    custom_mode: 0,
    type_: 18, // MAV_TYPE_ONBOARD_CONTROLLER
    autopilot: 0,
    base_mode: 0,
    system_status: 4, // MAV_STATE_ACTIVE
    mavlink_version: 3,
};

// Encode it into a v2 frame, then read it back the way a peer would.
let mut payload = [0u8; 255];
let len = heartbeat.encode(&mut payload);
let frame = Frame::encode_v2(Header::new(1, 1, 0), Heartbeat::ID, &payload[..len], Heartbeat::CRC_EXTRA)?;

let received = Frame::parse(frame.as_bytes(), Heartbeat::CRC_EXTRA)?;
let decoded = Heartbeat::decode(received.payload())?;
assert_eq!(decoded.system_status, 4);

License

MIT - part of the pamoja workspace: one memory-safe Rust core with bindings for every language.