Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/PX4/PX4-Autopilot/llms.txt

Use this file to discover all available pages before exploring further.

MAVLink is a lightweight binary messaging protocol designed for the drone ecosystem. PX4 uses MAVLink as the primary interface for communicating with ground control stations (GCS) like QGroundControl, autopilot SDKs like MAVSDK, and companion computers. It carries telemetry, commands, parameter reads and writes, mission uploads and downloads, and file transfers — all multiplexed over a single link.
MAVLink messages are unauthenticated by default. Any device that can send MAVLink packets to the vehicle can execute commands, including shell access, file operations, and flight termination. Enable message signing and follow security hardening best practices before deploying in production.

Protocol fundamentals

MAVLink messages are the core data unit of the protocol. Each message has a numeric ID, a name (e.g., HEARTBEAT, ATTITUDE, COMMAND_LONG), and a fixed set of typed fields. Messages are compact — with a constrained maximum size — and are sent with no built-in acknowledgement semantics. Microservices are higher-level protocols built on top of raw messages. They add request/response semantics, retransmission, and sequencing for operations that cannot fit in a single message. PX4 implements the following microservices:
MicroservicePurpose
Command ProtocolSend commands with acknowledgement and retransmission (COMMAND_LONG / COMMAND_ACK)
Parameter ProtocolRead and write named float/int parameters (PARAM_REQUEST_READ, PARAM_SET, PARAM_VALUE)
Mission ProtocolUpload, download, and clear waypoint missions (MISSION_ITEM_INT, MISSION_ACK)
File Transfer Protocol (FTP)Transfer files to/from the flight controller over MAVLink
Camera ProtocolInterface with MAVLink-capable cameras for capture and settings

Default UDP ports

When running SITL, or when a companion computer connects to PX4 over Ethernet or a serial-to-UDP bridge, PX4 binds to two UDP ports by default:
PortPurpose
14550Ground Control Station (QGroundControl connects here automatically)
14540Companion computer / offboard SDK (MAVSDK, MAVROS default target)
On hardware, MAVLink typically runs over UART (serial) rather than UDP. The mavlink start -d /dev/ttyS1 -b 57600 command starts a MAVLink instance on a specific serial port. Multiple MAVLink instances can run simultaneously on different ports.
PX4 publishes telemetry as a set of configurable streams — each stream maps a uORB topic (or combination of topics) to a MAVLink message type and sends it at a defined rate. You can adjust stream rates at runtime or via parameters.
# List all active streams and their current rates
mavlink stream -l

# Set the ATTITUDE stream to 50 Hz on instance 0
mavlink stream -n ATTITUDE -r 50 -i 0

# Start a new MAVLink instance on a serial port at 921600 baud
mavlink start -d /dev/ttyS3 -b 921600
Common default streams include:
MAVLink MessageSource uORB TopicDefault Rate
HEARTBEAT1 Hz
ATTITUDEvehicle_attitude10–50 Hz
LOCAL_POSITION_NEDvehicle_local_position10–30 Hz
GLOBAL_POSITION_INTvehicle_global_position10 Hz
GPS_RAW_INTsensor_gps1–5 Hz
VFR_HUDmultiple topics4 Hz
BATTERY_STATUSbattery_status1 Hz
SYS_STATUSvehicle_status1 Hz

Key message types

Every MAVLink participant must send HEARTBEAT at 1 Hz. It announces the node’s presence, system type (MAV_TYPE), autopilot type (MAV_AUTOPILOT), and current base mode and custom mode (which encodes the PX4 flight mode). Loss of HEARTBEAT from the GCS for more than a configured timeout triggers a datalink failsafe.
HEARTBEAT
  type:           MAV_TYPE_QUADROTOR
  autopilot:      MAV_AUTOPILOT_PX4
  base_mode:      MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_SAFETY_ARMED
  custom_mode:    (encodes PX4 main mode + sub mode)
  system_status:  MAV_STATE_ACTIVE
Used by the Command Protocol to send a single command with up to seven float parameters. PX4 replies with COMMAND_ACK and a result code. If no acknowledgement is received within the timeout, the SDK retransmits.
COMMAND_LONG
  target_system:    1
  target_component: 1
  command:          MAV_CMD_NAV_TAKEOFF       (22)
  confirmation:     0
  param1:           0       # Pitch (ignored for multicopter)
  param2:           0       # Empty
  param3:           0       # Empty
  param4:           NaN     # Yaw (NaN = use current heading)
  param5:           NaN     # Latitude (NaN = use current)
  param6:           NaN     # Longitude (NaN = use current)
  param7:           2.5     # Altitude above home [m]
Sends a position, velocity, or acceleration setpoint to PX4 in the local NED frame. Used by offboard control systems (MAVSDK, MAVROS) running in OFFBOARD mode. The type_mask field selects which fields are active.
SET_POSITION_TARGET_LOCAL_NED
  time_boot_ms:     <ms since boot>
  target_system:    1
  target_component: 1
  coordinate_frame: MAV_FRAME_LOCAL_NED (1)
  type_mask:        0b0000_1111_1000_0000  # Use only position fields
  x:                5.0    # North [m]
  y:                0.0    # East [m]
  z:               -3.0    # Down [m] (negative = up)
  vx: vy: vz:       0.0
  afx: afy: afz:    0.0
  yaw:              0.0    # [rad]
  yaw_rate:         0.0    # [rad/s]
PX4 must receive SET_POSITION_TARGET_LOCAL_NED at more than 2 Hz to remain in OFFBOARD mode. If the stream stops, it falls back to the configured failsafe mode.
The Parameter Protocol lets a GCS read all parameters from PX4 and write individual values. A full parameter download (PARAM_REQUEST_LIST) can return thousands of PARAM_VALUE messages. Each parameter has a 16-character name, a float value, and a type field.
PARAM_SET
  target_system:    1
  target_component: 1
  param_id:         "MPC_XY_VEL_MAX\0"   # Null-padded to 16 chars
  param_value:      5.0
  param_type:       MAV_PARAM_TYPE_REAL32
PX4 exposes a remote NuttX shell session over MAVLink, enabling you to run shell commands on the flight controller without a physical serial connection.
Open QGroundControl and navigate to Analyze Tools → MAVLink Console. You can type shell commands directly into the console and see their output.
PX4 builds against common.xml by default, which covers the vast majority of standard use cases. In the main branch, SITL builds also include development.xml for experimental messages.
# Rebuild with a specific dialect (rarely needed — common.xml is the default)
make px4_sitl_default
Message definition XML files are located in the MAVLink submodule:
mavlink/include/mavlink/v2.0/
├── common/
│   └── common.xml        # Standard messages
├── development/
│   └── development.xml   # Draft / in-development messages
└── standard/
    └── standard.xml      # Finalized standard messages
PX4 supports multiple simultaneous MAVLink instances — one for the GCS, one for a companion computer, one for a telemetry radio, and so on. Each instance runs as a separate context within the mavlink module.
# Start instance for GCS on UDP port 14550
mavlink start -x -u 14550 -r 4000000

# Start instance for companion computer on UART at 921600 baud
mavlink start -d /dev/ttyS3 -b 921600 -m onboard

# Start instance for low-bandwidth telemetry radio on UART at 57600 baud
mavlink start -d /dev/ttyS1 -b 57600 -m normal
The -m flag selects a MAVLink profile (sometimes called a mode), which pre-configures which streams are enabled and at what rate:
ProfileDescription
normalStandard GCS profile; balanced stream rates
onboardHigh-rate profile for companion computers; more topics, higher frequency
osdReduced set for on-screen displays
magicMinimal heartbeat-only output
configConfiguration-focused profile
1

Identify or define the MAVLink message

Use an existing message from common.xml or add a custom message to a dialect XML file. Custom messages must be added to PX4-Autopilot/mavlink/include/mavlink/v2.0/<dialect>/ and regenerated.
2

Create a stream class

In src/modules/mavlink/streams/, create a new .hpp file that subclasses MavlinkStream. Override get_name(), get_id(), and send().
#include "../mavlink_stream.h"
#include <uORB/topics/my_topic.h>

class MavlinkStreamMyMessage : public MavlinkStream
{
public:
    const char *get_name() const override { return "MY_MESSAGE"; }
    uint16_t    get_id()   const override { return MAVLINK_MSG_ID_MY_MESSAGE; }

    bool send() override
    {
        my_topic_s data{};
        if (_sub.update(&data)) {
            mavlink_my_message_t msg{};
            msg.timestamp = data.timestamp / 1000; // us → ms
            msg.value     = data.value;
            mavlink_msg_my_message_send_struct(_mavlink->get_channel(), &msg);
            return true;
        }
        return false;
    }

private:
    uORB::Subscription _sub{ORB_ID(my_topic)};
};
3

Register the stream

Add your stream class to the stream factory in src/modules/mavlink/mavlink_main.cpp so PX4 can find it when the stream is requested by name.
4

Enable the stream

Start the stream at a desired rate using the mavlink stream command or set it as a default in the MAVLink profile configuration.
mavlink stream -n MY_MESSAGE -r 10 -i 0

Build docs developers (and LLMs) love