Skip to main content
Home/Guides/PX4 Autopilot Guide 2026
🚁 Drone DevUpdated June 2026 · PX4 v1.15

PX4 Autopilot Guide 2026

Complete guide to PX4 v1.15: build from source, SITL simulation with Gazebo, QGroundControl configuration, pymavlink offboard control, and native ROS 2 integration via XRCE-DDS.

PX4 v1.15Gazebo HarmonicQGroundControlpymavlinkROS 2 XRCE-DDSPixhawk 6CMAVLink

1. Installation & SITL

Get PX4 running in simulation before touching any hardware.

Clone PX4 and install dependencies

Clone the PX4-Autopilot repo and run the ubuntu_sim.sh dependency script.

# Clone PX4-Autopilot (stable release v1.15)
git clone --recurse-submodules https://github.com/PX4/PX4-Autopilot.git
cd PX4-Autopilot

# Install all dependencies (compilers, SITL tools, Gazebo)
bash Tools/setup/ubuntu.sh

# Reload environment
source ~/.bashrc

💡 ubuntu.sh installs gcc-arm-none-eabi, gstreamer, Gazebo Harmonic, and all Python deps. Run on Ubuntu 22.04 or 24.04.

Build and run SITL simulation

Build PX4 for SITL with Gazebo and start a simulated quadcopter. No real hardware needed.

# Build PX4 for SITL with Gazebo Harmonic (recommended 2026)
make px4_sitl gz_x500

# This builds PX4 and launches:
#   - PX4 SITL process
#   - Gazebo Harmonic with x500 quadcopter model
#   - MAVLink ground station link on UDP 14550

# In the PX4 shell that opens, type:
commander arm
commander takeoff

# You should see the drone take off in Gazebo.

Connect QGroundControl to SITL

QGroundControl (QGC) auto-connects to SITL via UDP on launch. Use it to upload parameters, plan missions, and monitor telemetry.

# Download QGroundControl AppImage (Linux)
wget https://d176tv9ibo4jno.cloudfront.net/latest/QGroundControl.AppImage
chmod +x QGroundControl.AppImage
./QGroundControl.AppImage

# QGC auto-discovers PX4 SITL on UDP 14550.
# For real hardware via USB:
#   - Plug in Pixhawk USB → QGC detects /dev/ttyACM0 auto
# For telemetry radio:
#   - QGC → Application Settings → Comm Links → Add → UDP port 14550

💡 PX4 listens on UDP 14550 (GCS), 14540 (offboard), and 14557 (forward). All three ports are available in SITL.

3. Native ROS 2 — XRCE-DDS (PX4 v1.14+)

PX4's native uORB-to-ROS2 bridge. No MAVROS, sub-millisecond latency, direct topic access.

PX4 native ROS 2 via XRCE-DDS (PX4 v1.14+)

PX4 v1.14+ ships XRCE-DDS client built-in. Run the Micro XRCE-DDS Agent on the companion computer to bridge uORB topics to ROS 2 natively — no MAVROS.

# Install Micro XRCE-DDS Agent
pip install -U micro-xrce-dds-agent

# Or build from source (for ROS 2 Jazzy)
git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent
cd Micro-XRCE-DDS-Agent
mkdir build && cd build
cmake .. -DUXRCE_BUILD_SHARED_LIBS=ON
make -j$(nproc)
sudo make install

# Start the agent (UDP for SITL, serial /dev/ttyS0 for hardware)
MicroXRCEAgent udp4 -p 8888

# In another terminal, start PX4 SITL
make px4_sitl gz_x500

# PX4 XRCE client auto-connects to agent.
# In ROS 2:
ros2 topic list | grep /fmu

💡 XRCE-DDS gives sub-millisecond latency from PX4 uORB topics to ROS 2. All PX4 internal messages (VehicleOdometry, SensorGps, VehicleCommand) publish directly.

ROS 2 offboard control node

Write a ROS 2 node that arms PX4 and commands it in offboard mode using native uORB topics.

import rclpy
from rclpy.node import Node
from px4_msgs.msg import (
    OffboardControlMode, TrajectorySetpoint,
    VehicleCommand, VehicleStatus
)
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy, DurabilityPolicy

class OffboardControl(Node):
    def __init__(self):
        super().__init__('offboard_control')

        qos = QoSProfile(
            reliability=ReliabilityPolicy.BEST_EFFORT,
            durability=DurabilityPolicy.TRANSIENT_LOCAL,
            history=HistoryPolicy.KEEP_LAST,
            depth=1
        )

        self.offboard_pub = self.create_publisher(OffboardControlMode, '/fmu/in/offboard_control_mode', qos)
        self.traj_pub = self.create_publisher(TrajectorySetpoint, '/fmu/in/trajectory_setpoint', qos)
        self.cmd_pub = self.create_publisher(VehicleCommand, '/fmu/in/vehicle_command', qos)

        self.timer = self.create_timer(0.1, self.timer_callback)  # 10Hz
        self.counter = 0

    def arm(self):
        cmd = VehicleCommand()
        cmd.command = VehicleCommand.VEHICLE_CMD_COMPONENT_ARM_DISARM
        cmd.param1 = 1.0  # arm
        cmd.from_external = True
        self.cmd_pub.publish(cmd)

    def engage_offboard(self):
        cmd = VehicleCommand()
        cmd.command = VehicleCommand.VEHICLE_CMD_DO_SET_MODE
        cmd.param1 = 1.0  # custom mode
        cmd.param2 = 6.0  # offboard
        self.cmd_pub.publish(cmd)

    def timer_callback(self):
        # Must publish offboard mode setpoints at >2Hz before switching to offboard
        mode = OffboardControlMode()
        mode.position = True
        self.offboard_pub.publish(mode)

        setpoint = TrajectorySetpoint()
        setpoint.position = [0.0, 0.0, -5.0]  # NED frame: -Z = up 5m
        setpoint.yaw = 0.0
        self.traj_pub.publish(setpoint)

        if self.counter == 10:  # After 1s of setpoints, arm and switch
            self.arm()
            self.engage_offboard()
        self.counter += 1

def main():
    rclpy.init()
    node = OffboardControl()
    rclpy.spin(node)
    rclpy.shutdown()

if __name__ == "__main__":
    main()

💡 PX4 requires the offboard setpoint stream to run for >0.5s before accepting VEHICLE_CMD_DO_SET_MODE offboard. The 10-counter delay above ensures this.

4. PX4-Compatible Flight Controllers 2026

FCChipIMUPriceBest for
Pixhawk 6CSTM32H753ICM-42688-P × 2$279Best for research + ROS 2
Pixhawk 6XSTM32H753ICM-42688-P × 3$399Triple IMU redundancy — critical systems
Holybro Kakute H7STM32H743ICM42688-P$49Best budget FC for PX4
mRo Control Zero H7STM32H743ICM-42688-P$189Compact form factor for tight builds