Y
Published on

PX4 and Pixhawk Quadcopter Development Tutorial

Authors
  • avatar
    Name
    Yinhuan Yuan
    Twitter

Table of Contents

  1. Introduction
  2. PX4 vs ArduPilot
  3. System Architecture
  4. Hardware Requirements
  5. Development Environment Setup
  6. Firmware Installation
  7. Initial Configuration
  8. Sensor Calibration
  9. Flight Modes
  10. Parameter Tuning
  11. SITL Simulation
  12. MAVLink and MAVROS
  13. Custom Development
  14. Debugging and Logs
  15. Advanced Features

Introduction

PX4 is a professional-grade open-source autopilot software designed for autonomous vehicles. When combined with Pixhawk hardware, it provides a robust platform for quadcopter development with emphasis on modularity, real-time performance, and safety. This tutorial covers everything from basic setup to advanced development techniques.

Key Features of PX4

  • Real-time operating system (NuttX)
  • Modular architecture
  • Hardware abstraction layer
  • Extensive simulation support
  • Professional-grade safety features
  • Active research community

PX4 vs ArduPilot

PX4 Advantages

  • Modern Architecture: Cleaner, more modular codebase
  • Better Simulation: Superior SITL and Gazebo integration
  • Research-Friendly: Preferred in academic/research settings
  • ROS Integration: Native MAVROS support
  • Development Tools: Better toolchain and debugging

ArduPilot Advantages

  • Feature-Rich: More vehicle types and features
  • Mature Ecosystem: Larger user base
  • Hardware Support: Wider hardware compatibility
  • Documentation: More extensive wiki

Choose PX4 When:

  • Developing custom controllers
  • Integrating with ROS/ROS2
  • Requiring professional certification
  • Working on research projects
  • Need advanced simulation

System Architecture

PX4 Software Stack

┌─────────────────────────────────────┐
Applications Layer    (Missions, Safety, Commands)├─────────────────────────────────────┤
Flight Stack Layer  (Controllers, Estimators, Mixers)├─────────────────────────────────────┤
Middleware Layer (uORB)    (Inter-process Communication)├─────────────────────────────────────┤
Drivers Layer    (Sensors, Actuators, Comms)├─────────────────────────────────────┤
Operating System (NuttX)└─────────────────────────────────────┘

Key Components

uORB (Micro Object Request Broker)

  • Publish-subscribe messaging system
  • Enables modular communication
  • Real-time safe
  • Type-safe message passing

Flight Tasks

  • Modular flight mode implementation
  • Easy to extend and customize
  • Clean interfaces between modes

EKF2 (Extended Kalman Filter)

  • State estimation
  • Sensor fusion
  • Handles GPS, IMU, barometer, magnetometer

Hardware Requirements

Supported Pixhawk Boards

Development Boards

  • Pixhawk 4: Recommended for development
  • Pixhawk 6C: Latest generation
  • Pixhawk 6X: High-performance option
  • Holybro Durandal: Robust alternative

Budget Options

  • Pixhawk 2.4.8: Legacy but functional
  • mRo Pixhawk: Compatible alternative
  • CUAV V5+: Good price/performance

Quadcopter Components

Frame and Motors

Frame: 450-550mm for development
Motors: 920-1000KV brushless
ESCs: 30A with DShot support preferred
Props: 10-12 inch, balanced

Sensors

  • GPS: M8N/M9N with compass
  • Optical Flow: PX4Flow (optional)
  • Range Finder: TFMini/Benewake (optional)
  • Airspeed: Not needed for copters

Communication

  • RC System: 8+ channel recommended
  • Telemetry: SiK radio or WiFi
  • Companion Link: USB or UART

Wiring Configuration

Standard Pixhawk 4 Connections:
┌─────────────────────────┐
Pixhawk 4├─────────────────────────┤
POWER1: Power ModulePOWER2: Backup PowerGPS1: GPS/CompassRC IN: ReceiverMAIN 1-4: Motor ESCsTELEM1: Ground StationTELEM2: CompanionUSB: Development/Config└─────────────────────────┘

Development Environment Setup

Operating System Preparation

# Update system
sudo apt update && sudo apt upgrade -y

# Install dependencies
sudo apt install -y \
    git \
    python3-pip \
    python3-setuptools \
    python3-dev \
    build-essential \
    ccache

Windows (Using WSL2)

# Install WSL2
wsl --install

# Install Ubuntu 20.04
wsl --install -d Ubuntu-20.04

# Continue with Ubuntu instructions

macOS

# Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install tools
brew install git python3 ccache

PX4 Development Tools

Install PX4 Toolchain

# Clone PX4 Firmware
git clone https://github.com/PX4/PX4-Autopilot.git --recursive
cd PX4-Autopilot

# Run setup script
bash ./Tools/setup/ubuntu.sh

# Restart terminal or source profile
source ~/.bashrc

Install QGroundControl

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

# Or install via snap
sudo snap install qgroundcontrol

Install Additional Tools

# MAVLink tools
pip3 install --user pymavlink mavproxy

# Analysis tools
pip3 install --user pyulog matplotlib

# ROS integration (optional)
sudo apt install ros-noetic-mavros ros-noetic-mavros-extras

Firmware Installation

Building PX4 Firmware

Standard Build

cd PX4-Autopilot

# Configure for Pixhawk 4
make px4_fmu-v5_default

# Other common targets:
# make px4_fmu-v3_default  # Pixhawk 2.4.8
# make px4_fmu-v6c_default # Pixhawk 6C
# make holybro_durandal-v1_default

Custom Build Configuration

# Menu-based configuration
make px4_fmu-v5_default menuconfig

# Clean build
make clean
make px4_fmu-v5_default

Flashing Firmware

Using QGroundControl

  1. Connect Pixhawk via USB
  2. Open QGroundControl
  3. Go to Vehicle Setup → Firmware
  4. Select PX4 Flight Stack
  5. Choose version (stable/developer/custom)
  6. Follow prompts

Command Line Flashing

# Build and upload
make px4_fmu-v5_default upload

# If device not found
# Unplug and replug while command waits

DFU Mode Recovery

# For bricked boards
# 1. Unplug Pixhawk
# 2. Hold bootloader button
# 3. Plug in USB while holding button
# 4. Release after 3 seconds

# Flash via DFU
make px4_fmu-v5_default upload

Initial Configuration

QGroundControl Setup

Vehicle Configuration

1. Connect Pixhawk
2. Vehicle SetupSummary
3. Select Airframe:
   - Generic Quadcopter X
   - Apply and Restart

Sensor Orientation

Vehicle SetupSensorsSet Orientations
- ROTATION_NONE for standard mounting
- Adjust if mounted differently

Essential Parameters

System Parameters

# Access via Parameters tab
SYS_AUTOSTART: 4001 (Generic Quadcopter)
SYS_AUTOCONFIG: 1 (Reset parameters)
CBRK_SUPPLY_CHK: 0 (Enable power checks)

Safety Parameters

COM_RC_LOSS_T: 0.5 (RC loss timeout)
COM_DL_LOSS_T: 10 (Datalink loss timeout)
NAV_RCL_ACT: 2 (Return on RC loss)
NAV_DLL_ACT: 0 (Hold on datalink loss)

Sensor Calibration

Magnetometer Calibration

Vehicle SetupSensorsCompass
1. Start calibration
2. Rotate vehicle in all orientations
3. Complete when progress reaches 100%
4. Check mag field strength (185-585 mGauss)

Accelerometer Calibration

Vehicle SetupSensorsAccelerometer
1. Place vehicle level
2. Start calibration
3. Follow orientation instructions:
   - Level
   - Nose down
   - Nose up
   - Left side
   - Right side
   - Upside down

Gyroscope Calibration

Vehicle SetupSensorsGyroscope
1. Keep vehicle still
2. Start calibration
3. Wait for completion
4. Do not move during process

Level Horizon Calibration

Vehicle SetupSensorsLevel Horizon
1. Place on perfectly level surface
2. Click calibrate
3. Verify artificial horizon matches

Radio Calibration

Vehicle SetupRadio
1. Turn on transmitter
2. Start calibration
3. Move all sticks to extremes
4. Move all switches
5. Click Next/OK when complete

ESC Calibration

Vehicle SetupPower
1. Remove props!
2. Set PWM_MIN and PWM_MAX
3. Perform ESC calibration sequence
4. Or use DShot (no calibration needed)

Flight Modes

PX4 Flight Mode Structure

Manual Modes

  • Manual: Direct stick control (fixed-wing only)
  • Stabilized: Self-leveling
  • Acro: Rate control, no leveling
  • Rattitude: Stabilized center, acro extremes

Assisted Modes

  • Altitude: Altitude hold with position drift
  • Position: Full position and altitude hold
  • Hold: Stops and hovers at current position

Autonomous Modes

  • Mission: Follows waypoints
  • Return: Return to launch
  • Land: Automated landing
  • Follow Me: Follows ground station
  • Orbit: Circles point of interest

Flight Mode Configuration

Vehicle SetupFlight Modes
- Assign modes to RC channels
- Configure mode switch
- Set kill switch (recommended)
Channel 5 (3-position switch):
- Position 1: Stabilized
- Position 2: Position
- Position 3: Mission

Channel 6 (2-position switch):
- Kill switch / Emergency stop

Channel 7 (2-position switch):
- Return to Launch

Parameter Tuning

PID Tuning Overview

MC (Multicopter) Rate Controller

MC_ROLLRATE_P: 0.15 (default)
MC_ROLLRATE_I: 0.2
MC_ROLLRATE_D: 0.003

MC_PITCHRATE_P: 0.15
MC_PITCHRATE_I: 0.2
MC_PITCHRATE_D: 0.003

MC_YAWRATE_P: 0.2
MC_YAWRATE_I: 0.1
MC_YAWRATE_D: 0.0

Position Controller

MPC_XY_P: 0.95 (position P gain)
MPC_XY_VEL_P_ACC: 1.8 (velocity P gain)
MPC_Z_P: 1.0 (altitude P gain)
MPC_Z_VEL_P_ACC: 4.0 (vertical velocity P)

Tuning Process

1. Rate Controller Tuning

# Enable high-rate logging
param set SDLOG_PROFILE 1

# Fly in Acro mode
# Adjust P gains first
# Add D for damping
# Finally tune I for tracking

2. Attitude Controller Tuning

# Fly in Stabilized mode
# Adjust MC_ROLL_P and MC_PITCH_P
# Typical range: 6-10

3. Position Controller Tuning

# Fly in Position mode
# Tune MPC_XY_P for position holding
# Adjust MPC_XY_VEL_P_ACC for velocity response

Auto-tuning

# Enable autotune mode
param set MC_AT_EN 1

# Fly in autotune mode
# Perform requested maneuvers
# Land to save parameters

SITL Simulation

Gazebo Simulation Setup

Install Gazebo

# Install Gazebo 11
sudo apt install gazebo11 libgazebo11-dev

# Install PX4 SITL requirements
pip3 install --user jinja2 empy toml numpy packaging

Run SITL

cd PX4-Autopilot

# Basic quadcopter simulation
make px4_sitl gazebo

# With specific world
make px4_sitl gazebo_typhoon_h5

# Headless mode
HEADLESS=1 make px4_sitl gazebo

jMAVSim Simulation

# Lighter weight simulation
make px4_sitl jmavsim

# Console commands in SITL
commander takeoff
commander land
commander mode position

SITL with QGroundControl

# Terminal 1: Run SITL
make px4_sitl gazebo

# Terminal 2: QGroundControl
./QGroundControl.AppImage

# QGC auto-connects to SITL

Multi-Vehicle Simulation

# Launch multiple instances
Tools/gazebo_sitl_multiple_run.sh -n 3

# Connect to different instances
# MAV_SYS_ID must be unique
- Binary protocol
- Message-based
- Platform independent
- Bandwidth efficient
# Python example
from pymavlink import mavutil

# Create connection
master = mavutil.mavlink_connection('udp:127.0.0.1:14550')

# Wait for heartbeat
master.wait_heartbeat()

# Request data stream
master.mav.request_data_stream_send(
    master.target_system,
    master.target_component,
    mavutil.mavlink.MAV_DATA_STREAM_ALL,
    10,  # Hz
    1    # Start
)

# Read attitude
while True:
    msg = master.recv_match(type='ATTITUDE', blocking=True)
    print(f"Roll: {msg.roll}, Pitch: {msg.pitch}")

MAVROS Integration

Installation

# ROS Noetic
sudo apt install ros-noetic-mavros ros-noetic-mavros-extras

# Install geographiclib
wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh
sudo bash install_geographiclib_datasets.sh

Basic MAVROS Usage

# Launch MAVROS
roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557"

# Topics available
rostopic list

# Arm vehicle
rosservice call /mavros/cmd/arming "value: true"

# Set mode
rosservice call /mavros/set_mode "custom_mode: 'OFFBOARD'"

MAVROS Example Script

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from mavros_msgs.srv import CommandBool, SetMode

class OffboardControl:
    def __init__(self):
        rospy.init_node('offboard_control')
        
        # Publishers
        self.local_pos_pub = rospy.Publisher(
            '/mavros/setpoint_position/local',
            PoseStamped,
            queue_size=10
        )
        
        # Subscribers
        self.state_sub = rospy.Subscriber(
            '/mavros/state',
            State,
            self.state_callback
        )
        
        # Services
        self.arming_client = rospy.ServiceProxy(
            '/mavros/cmd/arming',
            CommandBool
        )
        self.set_mode_client = rospy.ServiceProxy(
            '/mavros/set_mode',
            SetMode
        )
        
        self.current_state = State()
        
    def state_callback(self, msg):
        self.current_state = msg
        
    def send_setpoint(self, x, y, z):
        pose = PoseStamped()
        pose.pose.position.x = x
        pose.pose.position.y = y
        pose.pose.position.z = z
        self.local_pos_pub.publish(pose)
        
    def set_mode(self, mode):
        return self.set_mode_client(custom_mode=mode)
        
    def arm(self):
        return self.arming_client(value=True)

Custom Development

PX4 Module Development

Module Structure

// my_module.cpp
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>

class MyModule : public ModuleBase<MyModule>, public ModuleParams
{
public:
    MyModule();
    ~MyModule() = default;
    
    static int task_spawn(int argc, char *argv[]);
    static int custom_command(int argc, char *argv[]);
    static int print_usage(const char *reason = nullptr);
    
    void run() override;
    
private:
    // Parameters
    DEFINE_PARAMETERS(
        (ParamFloat<px4::params::MY_PARAM>) _my_param
    )
};

CMakeLists.txt

px4_add_module(
    MODULE my_module
    MAIN my_module
    SRCS
        my_module.cpp
    DEPENDS
        modules__uORB
)

Custom Flight Mode

Flight Task Implementation

// FlightTaskMyMode.hpp
#pragma once

#include "FlightTask.hpp"

class FlightTaskMyMode : public FlightTask
{
public:
    FlightTaskMyMode() = default;
    virtual ~FlightTaskMyMode() = default;
    
    bool activate(const vehicle_local_position_s &last_setpoint) override;
    bool update() override;
    
private:
    void _updateSetpoints();
};

uORB Message Creation

Message Definition

# my_message.msg
uint64 timestamp
float32 my_value
float32[3] my_array
uint8 my_status

Using Custom Message

#include <uORB/topics/my_message.h>

// Advertise
orb_advert_t _my_msg_pub = orb_advertise(ORB_ID(my_message), nullptr);

// Publish
my_message_s msg{};
msg.timestamp = hrt_absolute_time();
msg.my_value = 42.0f;
orb_publish(ORB_ID(my_message), _my_msg_pub, &msg);

// Subscribe
int _my_msg_sub = orb_subscribe(ORB_ID(my_message));

Debugging and Logs

Console Access

# Via QGroundControl
# Analyze → MAVLink Console

# Common commands
help
top
listener sensor_combined
param show MC_ROLLRATE_P
dmesg

NSH Console

# Direct serial connection
screen /dev/ttyACM0 57600

# Or via MAVLink
./Tools/mavlink_shell.py

Log Analysis

Download Logs

# Using QGroundControl
# Analyze → Log Download

# Or via script
python3 Tools/LogDownload.py --device /dev/ttyACM0

ULog Analysis

# Install tools
pip3 install pyulog

# Convert to CSV
ulog2csv log_file.ulg

# Info about log
ulog_info log_file.ulg

# Plot data
python3 Tools/ulog_analysis.py log_file.ulg

FlightPlot

- Java-based log analyzer
- Real-time plotting
- Multiple graph types
- Statistical analysis

Common Issues

GPS Problems

# Check GPS status
listener vehicle_gps_position

# Parameters to check
param show GPS_*
param show EKF2_GPS_*

IMU Issues

# Check sensor data
listener sensor_accel
listener sensor_gyro

# Calibration status
param show CAL_ACC*
param show CAL_GYRO*

Motor Problems

# Test motors
motor_test test -m 1 -p 50  # Test motor 1 at 50%

# Check mixer
mixer load /dev/pwm_output0 etc/mixers/quad_x.main.mix

Advanced Features

Precision Landing

IR-Lock Setup

# Hardware: IR-Lock sensor + beacon
# Parameters:
PLND_EST_EN: 1
PLND_MODE: 1 (IR-Lock)
PLND_OFFSET_X: 0.0
PLND_OFFSET_Y: 0.0

Computer Vision Landing

# Using MAVROS
import rospy
from mavros_msgs.msg import LandingTarget

# Publish landing target
pub = rospy.Publisher(
    '/mavros/landing_target/raw',
    LandingTarget,
    queue_size=1
)

target = LandingTarget()
target.header.stamp = rospy.Time.now()
target.target_num = 0
target.angle_x = 0.1  # radians
target.angle_y = 0.1
target.distance = 5.0  # meters
pub.publish(target)

Obstacle Avoidance

Using Distance Sensors

# Parameters for rangefinder
SENS_EN_MB12XX: 1
SENS_MB12_0_ROT: 0 (forward)
MPC_COL_AVOID: 1

Computer Vision Avoidance

// Publish obstacle_distance message
#include <uORB/topics/obstacle_distance.h>

obstacle_distance_s obs{};
obs.timestamp = hrt_absolute_time();
obs.min_distance = 100;  // cm
obs.max_distance = 2000; // cm
obs.distances[0] = 150;  // Front distance
orb_publish(ORB_ID(obstacle_distance), _obs_pub, &obs);

Custom Mixer

Mixer File Format

# Custom X configuration
R: 4x

# Motor 1 (front right, CCW)
M: 1
S: 0 0  10000  10000     0 -10000  10000
S: 0 1  10000  10000 10000      0  10000
S: 0 2  10000  10000     0      0  10000
S: 0 3      0  20000 10000      0  10000

# Repeat for motors 2-4

Safety Features

Geofence

# Parameters
GF_ACTION: 2 (RTL on breach)
GF_ALTMODE: 0 (GPS altitude)
GF_COUNT: -1 (use uploaded fence)
GF_MAX_HOR_DIST: 1000 (meters)
GF_MAX_VER_DIST: 100 (meters)

Flight Termination

# Emergency motor stop
CBRK_FLIGHTTERM: 0 (enable)
FD_FAIL_P: 60 (max pitch)
FD_FAIL_R: 60 (max roll)

Best Practices

Development Workflow

  1. Always simulate first

    • Test in SITL before real hardware
    • Use unit tests for modules
    • Verify parameters in simulation
  2. Version control

    git checkout -b feature/my-feature
    git commit -m "descriptive message"
    git push origin feature/my-feature
    
  3. Code style

    # Format code
    make format
    
    # Check style
    make check_format
    

Safety Guidelines

  1. Pre-flight checks

    • Verify all calibrations
    • Check battery voltage
    • Confirm GPS lock
    • Test failsafes
  2. During development

    • Remove props when testing
    • Use kill switch
    • Have safety pilot
    • Test in open areas
  3. Parameter management

    # Save parameters
    param save
    
    # Export for backup
    param export params.txt
    
    # Reset to defaults
    param reset_all
    

Resources

Official Documentation

Community

Learning Resources

Tools and Software

Conclusion

PX4 with Pixhawk provides a professional-grade platform for quadcopter development, offering excellent simulation capabilities, clean architecture, and strong ROS integration. Success with PX4 comes from understanding its modular structure, leveraging its simulation tools, and following systematic development practices.

Key takeaways:

  • Start with SITL simulation
  • Master the parameter system
  • Understand uORB messaging
  • Use proper debugging tools
  • Engage with the community

Whether you're building research platforms, commercial products, or hobby projects, PX4's flexibility and robustness make it an excellent choice for serious drone development.