Bristlemouth MAVLink Integration

Bristlemouth now supports the MAVLink messaging protocol, opening the door to autonomous aquatic vehicle deployments with ArduPilot and PX4-based systems.
Until now, Bristlemouth has connected ocean sensors to platforms and data pipelines. This integration extends Bristlemouth into vehicle systems!

What is MAVLink?

MAVLink is a lightweight messaging protocol for communicating with drones and onboard drone components [1]. The protocol is extremely useful for planning missions remotely through the use of a ground control station. The ground control station communicates coordinates to a controller on the vehicle by means of remote telemetry (Iridium Satellite, Starlink, etc.) using the MAVLink command protocol [2]. Metrics are then streamed between the controller and onboard components (motors, IMUs, companion computers, other sensors) and sent back to the ground control station providing remote status of the vehicle.

Why is this important to Bristlemouth?

This unlocks a whole new opportunity for Bristlemouth to be used with autonomous aquatic vehicles including USVs and ROVs (Remotely Operated Vehicles). The two main autopilot systems that utilize MAVLink are Ardupilot [3] and PX4 [4] (which are both open source platforms). Ardupilot is the most prevalent in the aquatic space with ArduRover [5] (used for surface vehicles) and ArduSub [6] (used for sub-surface vehicles) autopilot platforms. The biggest name in this space utilizing MAVLink/Ardupilot is BlueRobotics [7] (who are the maintainers of ArduSub). BlueRobotics has both USV and ROV systems. MAVLink is also open source and aligns with the values and goals of Bristlemouth, creating and expanding an open ocean data platform.

The MAVLink integration was developed for a joint project between Sofar Ocean and Online Oceans called Spotter Scout, a Bristlemouth-enabled Unmanned Surface Vehicles (USV) launching in 2026. On this platform, Bristlemouth connects both the ocean sensing payload (waves, weather, subsurface data) and the vehicle’s control systems on the same network.

Why Bristlemouth?

MAVLink is intentionally transport-agnostic, it is a messaging protocol not a networking protocol, it defines what gets communicated, but leaves how messages move through a system entirely up to the underlying network. In aquatic deployments, that distinction matters immensely. Subsea and surface environments present unique networking challenges: environmental concerns make wired connections difficult, power budgets are tight, and latency can directly affect vehicle safety and mission success.

This is where Bristlemouth adds real value. Bristlemouth is a networking protocol built for the challenges in aquatic communications, designed to route messages efficiently across a network of nodes. Rather than broadcasting MAVLink messages across the entire network, Bristlemouth routes them directly to the specific component they’re intended for — whether that’s a thruster controller, an IMU, or a companion computer. This targeted routing reduces unnecessary network traffic, lowers latency, and cuts the power overhead of nodes that would otherwise have to process messages irrelevant to them. The physical cabling of the 10BASE-T1L [8] [9] implementation also help reduce the complexity of cable management and improve long dwell endurance.

On a solar-powered USV designed for 6+ month deployments, every milliwatt matters. Reducing unnecessary message processing across the network directly extends operational endurance.

Integration Overview

MAVLink has been integrated as a part of Bristlemouth Middleware [10] to complement the current resource based routing [9]. This allows for streamlined communication between nodes on the network. Receiving and transmitting messages are made trivial by a simple API. Routing is handled in Bristlemouth L2 [10].

MAVLink offers microservices which define higher-level protocols that MAVLink systems can adopt in order to be more inter-operable [11]. The most important of these services is the heartbeat protocol [12]. Heartbeats help components on the network determine who exists on the network (are there motors, temperature sensors, autopilot controllers, etc) and is also is leveraged in the routing of MAVLink messages in Bristlemouth.

In the future, more microservices are planned to be integrated to provide a seamless experience for developers looking to leverage these protocols such as the parameter parameter or file transfer protocol.

How To Integrate

There is an initial example application available in the bm_protocol repository which translates MAVLink messages from an Ardupilot autopilot controller to the Bristlemouth network. The autopilot controllers stream MAVLink messages over UART. This application essentially acts as a UART to Bristlemouth MAVLink message bridge [13]. The following diagram shows an example of this application:

After initializing the Bristlemouth network stack, all that needs to be done to have your mote/Bristlemouth device support the MAVLink middleware is invoke the function bm_mavlink_init [14]. Your device is now ready to receive and transmit MAVLink messages!

During initialization of the MAVLink messages, the developer will indicate which MAVLink messages they wish to receive, the following is an example for a system interested in Raw Pressure [15] and Motor RPM [16]:

#include "bm_mavlink.h"

void pressure_cb(mavlink_message_t *msg, mavlink_status_t *status) {
  (void)status;
  
  mavlink_raw_pressure_t pressure;
  mavlink_msg_raw_pressure_decode(msg, &pressure);
  
  bm_debug("Pressure Sensor: %u %u | %lld | %d | %dC |\n",
      msg->sysid,
      msg->compid,
      pressure.time_usec,
      pressure.press_abs,
      pressure.temperature);
}

void motor_rpm_cb(mavlink_message_t *msg, mavlink_status_t *status) {
  (void)status;
  
  mavlink_raw_rpm_t rpm;
  mavlink_msg_raw_rpm_decode(msg, &rpm);
  
  bm_debug("Motor RPM: %u %u | %d | %0.3frpm |\n",
    msg->sysid,
    msg->compid,
    rpm.index,
    rpm.frequency);
}

void init(void) {
  static BmMavLinkRxEntry rx_cb_lut[] = {
    { pressure_cb, MAVLINK_MSG_ID_RAW_PRESSURE },
    { motor_rpm_cb, MAVLINK_MSG_ID_RAW_RPM },
  };
  uint8_t sys_id = 1;
  uint8_t comp_id = 1;
 
  bm_mavlink_init(sys_id, comp_id, rx_cb_lut, array_size(rx_cb_lut));
}

The following is an example of how to send a MAVLink Raw Pressure Message [15]:

#include "bm_mavlink.h" //includes MAVLink required headers

...

BmErr send_mavlink_pressure(void) {
  mavlink_message_t msg;
  uint8_t system_id = bm_mavlink_get_sys_id(); // Assigned system ID
  uint8_t component_id = bm_mavlink_get_comp_id(); // Assigned component ID
     
  uint64_t time_us = bm_rtc_get_micro_seconds();
  float pressure = 0;
  float temperature = 0;
  if (!pressureSamplerGetLatest(pressure, temperature)) {
    return BmENODATA;
  }
  
  // Pack pressure message
  uint16_t len = mavlink_msg_raw_pressure_pack(system_id,												    component_id,
								    &msg,
								    time_us,
							        static_cast<int16_t>(pressure),
								    0, // Differential pressure 1
								    0, // Differential pressure 2
								    static_cast<int16_t>(temperature));
	
  // Serialize message and send on Bristlemouth
  return bm_mavlink_transmit(&msg, len);
}

References:

[1] MAVLink developer guide
[2] MAVLink command protocol
[3] Ardupilot Documentation
[4] PX4 Documentation
[5] ArduRover Documentation
[6] ArduSub Documentation
[7] BlueRobotics Webpage
[8] Texas Instruments - 10BASE-T1L Benefits
[9] Bristlemouth Specification
[10] Bristlemouth Technology Stack
[11] MAVLink Microservices
[12] MAVLink Heartbeat Protocol
[13] Bristlemouth MAVLink Bridge Source Code
[14] Bristlemouth MAVLink header file
[15] MAVLink Raw Pressure Messages
[16] MAVLink RPM Messages

1 Like