Skip to content

evannsmc/nmpc_acados_px4

Repository files navigation

Nonlinear NMPC for PX4-ROS2 Deployment

Status ROS 2 Compatible PX4 Compatible Docker: PX4-ROS2-Docker Solver: ACADOS evannsmc.com

A ROS 2 Nonlinear Model Predictive Controller (NMPC) for quadrotors using the Acados solver. Formulates the tracking problem with an error-based cost in Euler angle representation and uses atan2-based yaw wrapping for correct angular error computation.

This package implements a well-established NMPC technique and was built during my PhD at Georgia Tech's FACTSLab to serve as the baseline against which my novel control strategy — Newton-Raphson Flow — is benchmarked. See the newton_raphson_px4 controller for that comparison.

📖 Table of Contents

Workspace Layout (read this first)

nmpc_acados_px4 is not standalone — it is a ROS 2 package that imports from its sibling packages (quad_platforms, quad_trajectories, ROS2Logger) and the PX4 message definitions (px4_msgs). For these dependencies to resolve, all of them must live side-by-side under the src/ directory of a single ROS 2 workspace so that colcon build discovers and builds them together:

ros2px4_ws/                  # your ROS 2 workspace (any name)
└── src/
    ├── nmpc_acados_px4/      # this package
    ├── quad_platforms/       # platform abstraction (mass, geometry, limits)
    ├── quad_trajectories/    # trajectory definitions
    ├── ROS2Logger/           # CSV experiment logging (imported as `ros2_logger`)
    └── px4_msgs/             # PX4 ROS 2 message definitions

Then build once from the workspace root so every package is sourced into the same overlay:

cd ros2px4_ws
colcon build --symlink-install
source install/setup.bash

If you clone nmpc_acados_px4 on its own and try to build it, the import of quad_platforms / ros2_logger and the px4_msgs dependency will fail — the other packages simply aren't on the ROS 2 package path. Cloning them as siblings under the same src/ is what makes the dependencies "work out."

Note: ROS2Logger is the GitHub repository name; the package it installs (and the name you import) is ros2_logger. Acados and SciPy are installed separately (see Acados Setup below), not as workspace packages.

Approach

This controller solves a finite-horizon optimal control problem at every timestep:

  1. Model — 9D state [x, y, z, vx, vy, vz, roll, pitch, yaw] with 4D input [thrust, p, q, r]
  2. Error-based cost — the stage cost penalizes [position_err, velocity_err, euler_err, input_err] (13D); the terminal cost drops the input term (9D)
  3. Wrapped yaw error — uses atan2(sin(yaw - yaw_ref), cos(yaw - yaw_ref)) to avoid discontinuities at +/-pi
  4. Acados solver — generates and compiles C code for the QP sub-problems, enabling real-time MPC

Key Features

  • Platform-aware Acados cache — solver artifacts are reused when the platform/mass and NMPC formulation stamp still match, and regenerated automatically when they do not
  • Error-state cost formulation — references are passed as stage-wise parameters, not embedded in the cost
  • Nonlinear least squares — cost type is NONLINEAR_LS with configurable weight matrices
  • Input constraints — hard bounds on thrust [0, 27] N and body rates [-0.8, 0.8] rad/s
  • PX4 integration — publishes attitude setpoints and offboard commands via px4_msgs
  • Structured logging — optional CSV logging via ros2_logger

Cost Weights

Stage cost (13D):

Component Weight Dimension
Position error 2e3 3
Velocity error 2e1 3
Roll/pitch error 2e1 2
Yaw error 2e2 1
Thrust 1e1 1
Body rates (p, q) 1e3 2
Yaw rate (r) 1e2 1

Terminal cost (9D): same as stage cost without input terms (position 1e3, velocity 1e1, roll/pitch 1e1, yaw 1e2).

Usage

source install/setup.bash

# Fly a figure-8 in simulation
ros2 run nmpc_acados_px4 run_node --platform sim --trajectory fig8_horz

# Hardware flight with logging
ros2 run nmpc_acados_px4 run_node --platform hw --trajectory helix --log

# fig8_contraction with feedforward, logged with _ff marker in filename
ros2 run nmpc_acados_px4 run_node --platform sim --trajectory fig8_contraction --ff --log
# -> logs to: sim_nmpc_acados_px4_fig8_contraction_ff_1x.csv

CLI Options

Flag Description
--platform {sim,hw} Target platform (required)
--trajectory {hover,yaw_only,circle_horz,...} Trajectory type (required)
--hover-mode {1..8} Hover sub-mode (1-4 for hardware)
--log Enable CSV data logging
--log-file NAME Custom log filename
--double-speed 2x trajectory speed
--short Short variant (fig8_vert)
--spin Enable yaw rotation
--flight-period SEC Custom flight duration
--ff Mark log filename with _ff (only valid with fig8_contraction)

Dependencies

Package Structure

nmpc_acados_px4/
├── nmpc_acados_px4/
│   ├── run_node.py              # CLI entry point and argument parsing
│   └── ros2px4_node.py          # ROS 2 node (subscriptions, publishers, control loop)
└── nmpc_acados_px4_utils/
    ├── controller/
    │   └── nmpc/
    │       ├── generate_nmpc.py # NMPC problem formulation and C-code generation
    │       └── acados_model.py  # Quadrotor Euler dynamics model for Acados
    ├── px4_utils/               # PX4 interface and flight phase management
    ├── transformations/         # Yaw adjustment utilities
    ├── main_utils.py            # Helper functions
    └── jax_utils.py             # JAX configuration

Installation

There are four ways to set this up, from easiest to most manual. If you just want it running, use option 1 (Docker + script). All of them produce the same workspace layout.

# Path Effort When to use
1 Docker + script easiest You want the fastest, most reproducible setup. Script clones everything and links it to the container.
2 Docker (manual) easy Same container, but you prefer running the vcs import / make steps yourself.
3 Script (native) medium You build directly on the host (no Docker) and want the workspace laid out for you.
4 Manual (native) most manual You want full control of every clone and build step on the host.

The Docker image already ships ROS 2, a prebuilt px4_msgs overlay, and the Python deps (acados interface, SciPy/JAX). Native builds (options 3–4) require you to install ROS 2, acados, and px4_msgs yourself.

1. Docker + script (recommended)

The bundled script clones PX4-ROS2-Docker, lays out src/ with every sibling package, and symlinks the workspace to the container's mount point so make run works with no arguments:

./scripts/setup_ws_docker.sh            # full controller stack
./scripts/setup_ws_docker.sh --minimal  # only what NMPC needs

--help lists options (--ws, --docker, --https). Here px4_msgs is intentionally not cloned into src/ — the image ships a prebuilt copy at /opt/ws_px4_msgs. Then, from the Docker repo: make buildmake runmake build_ros.

2. Docker (manual)

Follow the PX4-ROS2-Docker README: clone it, vcs import the controller packages into your workspace src/, then make run / make build_ros. Identical result to option 1, done by hand.

3. Script (native, no Docker)

To build on the host, this script lays out the workspace including px4_msgs and can optionally build it:

./scripts/setup_ws_native.sh                 # lay out ~/ros2px4_ws/src
./scripts/setup_ws_native.sh --minimal --build  # only NMPC's deps, then colcon build

Run it from this checkout and it symlinks the current repo into the workspace instead of re-cloning. You still need ROS 2, acados, and SciPy installed (see Acados Setup).

4. Manual (native, no Docker)

Clone this package and its sibling dependencies into one workspace src/, then build from the workspace root:

mkdir -p ros2px4_ws/src && cd ros2px4_ws/src

git clone git@github.com:evannsmc/nmpc_acados_px4.git
git clone git@github.com:evannsmc/quad_platforms.git
git clone git@github.com:evannsmc/quad_trajectories.git
git clone git@github.com:evannsmc/ROS2Logger.git
git clone -b v1.16_minimal_msgs git@github.com:evannsmc/px4_msgs.git  # PX4 v1.16 minimal messages

cd .. && colcon build --symlink-install
source install/setup.bash

Acados and SciPy still need to be installed separately — see Acados Setup below.

Hardware with Motion Capture

For hardware flights that rely on an external motion-capture system for state estimation (instead of onboard GPS/VIO), clone the bridge for your mocap system plus its supporting packages into your workspace src/, alongside this controller:

cd <your_ws>/src

# Pick the bridge for your mocap system:
git clone git@github.com:evannsmc/vicon4px4.git        # Vicon
git clone git@github.com:evannsmc/optitrack4px4.git    # OptiTrack

# Supporting packages for the mocap → PX4 pipeline (skip px4_msgs if already cloned):
git clone -b v1.16_minimal_msgs git@github.com:evannsmc/px4_msgs.git
git clone git@github.com:evannsmc/mocap_msgs.git
git clone git@github.com:evannsmc/mocap_px4_relays.git

cd .. && colcon build --symlink-install

See the vicon4px4 and optitrack4px4 READMEs for system-specific configuration (rigid-body/frame names, host/IP, and ROS_DOMAIN_ID).

Acados Setup

Acados must be installed separately before building this package. Follow the steps below or the official instructions.

1) Install Acados

Clone and build from source:

git clone https://github.com/acados/acados.git
cd acados
git submodule update --recursive --init
mkdir -p build
cd build
cmake -DACADOS_WITH_QPOASES=ON ..
# add more optional arguments e.g. -DACADOS_WITH_DAQP=ON
make install -j4

2) Install the Acados Python interface

Install the template as per the Python interface instructions:

pip install -e <acados_root>/interfaces/acados_template

Add these environment variables to your shell init (e.g., ~/.bashrc), then source ~/.bashrc:

acados_root="your_acados_root"  # e.g. "/home/user/acados"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$acados_root/lib"
export ACADOS_SOURCE_DIR="$acados_root"

3) Install t_renderer binaries

Required for rendering C code templates:

  1. Download the correct binaries from the t_renderer releases
  2. Place the binary in <acados_root>/bin
  3. Rename it to t_renderer (e.g. t_renderer-v0.2.0-linux-arm64 -> t_renderer)
  4. Make it executable:
chmod +x <acados_root>/bin/t_renderer

4) Verify the installation

python3 <acados_root>/examples/acados_python/getting_started/minimal_example_ocp.py

If it runs and plots with no errors, you're done!

Papers and Repositories

American Control Conference 2024 — paper | Personal repo | FACTSLab repo

Transactions on Control Systems Technology 2025 — paper | Personal repo | FACTSLab repo

Transactions on Robotics 2025 | Personal repo | FACTSLab repo

Related Work

Website

This project is part of the evannsmc open-source portfolio.

License

MIT

Releases

No releases published

Packages

 
 
 

Contributors