This package is the culmination of 3 papers on Newton-Raphson Flow for Quadrotor Control.
This package allows for fast, accuate, and computationally efficient control via the Newton-Raphson Flow (NR Flow) controller developed by Dr. Yorai Wardi and others. We introduce integral CBFs (I-CBFs) to smoothly limit control actuation.
The NR Flow controller is an integral-based control strategy based on a continuous time flow-version of the known newton-raphson iterative algorithm for finding the zeros of functions. It has been shown to have desirable theoretical properties in previous work, including known tracking error bounds, and we show in our hardware implementations that it compares favorably to the native control stack of PX4 Autopilot, as well as NMPC. Notably, it outperforms NMPC in terms of speed and computational efficiency (measured by joules of energy expended by the CPU), and on complex trajectories it may even outperform NMPC due to computational constraints. This is an ideal controller when facing on-board computational limitations. In particular, we test and deploy this on an on-board Raspberry Pi 4 Model B on a Holybro x500V2 quadrotor and we compare it against the NMPC controller available in my NMPC_PX4 package.
📖 Table of Contents
newton_raphson_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/
├── newton_raphson_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.bashIf you clone newton_raphson_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:
ROS2Loggeris the GitHub repository name; the package it installs (and the name youimport) isros2_logger. JAX/jaxlib are installed separately into your Python environment (already present in the PX4-ROS2-Docker image's venv), not as workspace packages.
- Newton-Raphson control law — iterative inversion of the system Jacobian for feedback linearization
- Integral CBF safety constraints — optional barrier functions to enforce input constraints (enabled by default)
- JAX JIT-compiled — all control computations are JIT-compiled for real-time performance
- PX4 integration — publishes attitude setpoints and offboard commands via
px4_msgs - Structured logging — optional CSV logging via ROS2Logger with automatic analysis notebook generation
| Parameter | Value | Description |
|---|---|---|
ALPHA |
[20, 30, 30, 30] |
Control gains [x, y, z, yaw] |
USE_CBF |
True |
Enable integral Control Barrier Functions |
# Source your ROS 2 workspace
source install/setup.bash
# Fly a circle in simulation
ros2 run newton_raphson_px4 run_node --platform sim --trajectory circle_horz
# Fly a helix on hardware with logging
ros2 run newton_raphson_px4 run_node --platform hw --trajectory helix --log
# Hover mode 3, double speed, with yaw spin
ros2 run newton_raphson_px4 run_node --platform sim --trajectory hover --hover-mode 3 --double-speed --spin
# fig8_contraction with feedforward, logged with _ff marker in filename
ros2 run newton_raphson_px4 run_node --platform sim --trajectory fig8_contraction --ff --log
# -> logs to: sim_nr_std_fig8_contraction_ff_1x.csv| 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 |
Enable feedforward and mark log filename with _ff (any trajectory) |
When the fig8_contraction trajectory is selected, the node computes a differential-flatness feedforward at each control step using the same approach as the contraction controller (flat_to_x_u from quad_trajectories).
How it works:
- The flat output
[px, py, pz, psi](t)is differentiated twice viajax.jacfwdto recover velocity and acceleration. - From acceleration, the feedforward specific thrust
fand Euler angles[phi, th, psi]are computed analytically (flat-output inversion). - A third differentiation gives
u_ff = [df, dphi, dth, dpsi]— the rates of thrust, roll, pitch, and yaw. - The angular rate feedforward
u_ff[1:4] = [dphi, dth, dpsi]is added directly to the NR control output[roll_rate, pitch_rate, yaw_rate], providing a baseline that the NR feedback corrects around rather than building up from zero.
The thrust component u_ff[0] = df is not added to the NR thrust output (they live in different units: df is in m/s³, NR thrust is in N), so NR handles thrust authority through position tracking as normal.
- quad_trajectories — trajectory definitions
- quad_platforms — platform abstraction
- ROS2Logger — experiment logging
- px4_msgs — PX4 ROS 2 message definitions (use the
v1.16_minimal_msgsbranch for PX4 v1.16) - JAX / jaxlib
newton_raphson_px4/
├── newton_raphson_px4/
│ ├── run_node.py # CLI entry point and argument parsing
│ └── ros2px4_node.py # ROS 2 node (subscriptions, publishers, control loop)
└── newton_raphson_px4_utils/
├── controller/
│ ├── newton_raphson_px4.py # Newton-Raphson control law
│ └── nr_utils.py # Dynamics, Jacobians, CBF functions
├── px4_utils/ # PX4 interface and flight phase management
├── transformations/ # Yaw adjustment utilities
├── main_utils.py # Helper functions
└── jax_utils.py # JAX configuration
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_msgsoverlay, and the Python deps (JAX in its venv). Native builds (options 3–4) require you to install ROS 2, JAX, andpx4_msgsyourself.
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 Newton-Raphson 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, and JAX is already in its venv. Then, from the Docker repo: make build → make run → make build_ros.
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.
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 NR's deps, then colcon buildRun it from this checkout and it symlinks the current repo into the workspace instead of re-cloning. You still need ROS 2 and JAX installed (pip install --upgrade "jax[cpu]").
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/newton_raphson_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.bashJAX/jaxlib must be installed in your Python environment separately.
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-installSee the vicon4px4 and optitrack4px4 READMEs for system-specific configuration (rigid-body/frame names, host/IP, and ROS_DOMAIN_ID).
MIT
This project is part of the evannsmc open-source portfolio.
American Control Conference 2024 - see paper here
Personal Version of Repository
Official FACTSLab Repository
Transactions on Control Systems Technology 2025 - see paper here
Personal Version of Repository
Official FACTSLab Repository
Transactions on Robotics 2025
Personal Version of Repository
Official FACTSLab Repository