After the Betaflight firmware, configurator, and Blackbox Explorer posts, dRehmFlight VTOL is a useful change of angle.

Betaflight is the polished FPV firmware ecosystem.

dRehmFlight is closer to a teaching bench.

It is an Arduino/Teensy flight-controller codebase for people who want to understand, modify, and prototype stabilization logic for unusual VTOL aircraft.

That makes it interesting for the same reason the ExpressLRS recovery story was interesting: when hardware is involved, source code is not abstract.

It touches pins, sensors, timing, radio input, arming logic, ESC output, and safety assumptions.

dRehmFlight VTOL is an open-source Arduino-compatible flight-controller project built around Teensy, an IMU, receiver input, attitude estimation, PID control, and custom motor/servo mixing for experimental VTOL aircraft.

dRehmFlight GitHub Source Code dRehmFlight VTOL Project Page RC Groups Support Thread License: GPL-3.0

What is dRehmFlight?

dRehmFlight is flight-controller firmware for custom radio-control aircraft.

The important part is not that it can stabilize a normal quad.

The important part is that the code is intentionally readable and concentrated enough that you can follow the full path:

receiver input
  -> desired roll, pitch, yaw, throttle
  -> IMU data
  -> attitude estimate
  -> PID controller
  -> custom motor and servo mixer
  -> ESC and servo output

That is the workflow hidden inside every serious flight controller.

dRehmFlight exposes it in a way that is friendly to Arduino users.

The upstream project is clear about its purpose: it is for hobbyists, hackers, non-coders, teaching, rapid prototyping, and unusual VTOL experiments. It is not presented as a commercial or performance replacement for mature flight-controller packages.

That honesty is good.

It sets the right expectation before anyone tries to put code on aircraft hardware.

Why It Matters

Most drone firmware discussions quickly become tool discussions:

  • which target to flash
  • which configurator tab to open
  • which preset to apply
  • which UART should carry CRSF
  • which blackbox trace proves the tune is good

Those are practical questions.

But they can hide the actual control loop.

dRehmFlight is useful because it lets you inspect the control loop directly.

In the latest Beta 1.3 sketch I inspected, the main loop is legible:

armedStatus()
getIMUdata()
Madgwick(...)
getDesState()
controlANGLE()
controlMixer()
scaleCommands()
throttleCut()
commandMotors()
getCommands()
failSafe()
loopRate(2000)

That is a compact way to learn what flight-controller firmware is doing before you get lost in a larger embedded codebase.

Repository Snapshot

I cloned and inspected:

repo: https://github.com/nickrehm/dRehmFlight
HEAD: 0df49c5d
describe: 0df49c5
license: GPL-3.0
latest sketch inspected: Versions/dRehmFlight_Teensy_BETA_1.3

Recent repository activity in this checkout was mostly README maintenance plus a fix for an asin NaN possibility when pitch is 90 degrees.

The project layout is simple:

Path What It Contains
README.md project overview, hardware, software, tutorial links, flight examples
dRehmFlight VTOL Documentation.pdf long-form setup and concept documentation
Versions/dRehmFlight_Teensy_BETA_1.3/ latest Arduino/Teensy sketch inspected
dRehmFlight_Teensy_BETA_1.3.ino main flight-controller sketch
radioComm.ino receiver input setup and radio channel handling
src/MPU6050, src/MPU9250 bundled IMU support code
src/SBUS, src/DSMRX, src/TFMPlus bundled receiver/sensor support libraries

This is not a Docker project.

It is not a browser PWA.

It is embedded Arduino-style firmware for a physical flight controller.

Hardware and Software

The default build is centered on:

  • Teensy 4.0
  • Teensy 4.1 compatibility with the same pin mappings
  • GY-521 MPU6050 6-axis IMU over I2C
  • optional MPU9250 over SPI
  • Arduino IDE
  • Teensyduino

The default receiver and IMU choices are visible at the top of the Beta 1.3 sketch:

#define USE_PWM_RX
//#define USE_PPM_RX
//#define USE_SBUS_RX
//#define USE_DSM_RX

#define USE_MPU6050_I2C
//#define USE_MPU9250_SPI

That is the first design clue.

The project is meant to be edited.

Changing receiver type or IMU type is not hidden behind a GUI profile. You edit the sketch and build it for your hardware.

Receiver Support

The receiver options in Beta 1.3 are:

Receiver Mode Where It Fits
PWM Separate signal wire per radio channel
PPM Multiple channels on one timed signal
SBUS Digital serial receiver protocol common in RC
Spektrum DSM DSM satellite receiver support added in Beta 1.3

That also explains what is not there by default.

I did not see CRSF/ExpressLRS receiver support in the default sketch options.

That matters if you are coming from the ExpressLRS and Betaflight world.

An ExpressLRS receiver can be part of many aircraft, but dRehmFlight would need either a supported receiver output mode or additional CRSF parsing work in the code.

The Control Loop

The main loop is where dRehmFlight earns the post.

It reads like a small flight-control textbook translated into Arduino functions:

  1. Check arming state.
  2. Read IMU data.
  3. Estimate attitude with Madgwick.
  4. Convert radio input into desired roll, pitch, yaw, and throttle.
  5. Run one of the PID controllers.
  6. Mix the control outputs into motor and servo commands.
  7. Scale commands into pulse ranges.
  8. Apply throttle cut.
  9. Send motor and servo outputs.
  10. Read new radio commands and apply failsafe behavior.
  11. Hold the loop at 2 kHz.

The default loop rate call is explicit:

loopRate(2000);

That is useful for learning because timing is part of control.

PID gains, filters, sensor sampling, and ESC updates do not exist in isolation.

The Mixer Is the Best Part

The most important function for custom aircraft is controlMixer().

The default mixer is a normal quad-style example:

m1_command_scaled = thro_des - pitch_PID + roll_PID + yaw_PID;
m2_command_scaled = thro_des - pitch_PID - roll_PID - yaw_PID;
m3_command_scaled = thro_des + pitch_PID - roll_PID + yaw_PID;
m4_command_scaled = thro_des + pitch_PID + roll_PID - yaw_PID;

Then unused motor and servo outputs are set to zero.

For a normal FPV quad, that is not exciting.

For a custom VTOL, it is the exact point of the project.

This is where a tiltrotor, tailsitter, cyclocopter, tricopter, biplane VTOL, or odd servo-driven experiment becomes your aircraft instead of a preset.

That also means this is the dangerous part.

The mixer decides what physical actuator moves when the controller asks for roll, pitch, yaw, or throttle.

If that mapping is wrong, the aircraft can react in the opposite direction.

Outputs

The sketch has two output families:

  • up to six motor outputs using OneShot125-style ESC pulses
  • up to seven servo or conventional PWM-style outputs

The OneShot125 motor commands are scaled into 125 to 250 microsecond pulses:

m1_command_PWM = m1_command_scaled * 125 + 125;

The servo-style outputs are scaled into the familiar 0 to 180 range used by Arduino servo APIs.

That split is useful for VTOL work.

Not every aircraft is just four motors.

Some designs need motors plus tilt servos, aerodynamic control surfaces, vectoring surfaces, or other actuators.

Local Trial

I checked the local Arduino CLI state:

arduino-cli version
arduino-cli core list

The machine has Arduino CLI available, but only the ESP32 core was installed in the current CLI environment.

Then I tried the expected Teensy compile shape:

git clone https://github.com/nickrehm/dRehmFlight.git
cd dRehmFlight
arduino-cli compile --fqbn teensy:avr:teensy40 Versions/dRehmFlight_Teensy_BETA_1.3

That failed before compiling project code:

Platform 'teensy:avr' not found: platform not installed
Platform teensy:avr is not found in any known index
Maybe you need to add a 3rd party URL?

So the local result is:

Arduino CLI: present
ESP32 core: installed
Teensy core: not installed in Arduino CLI
dRehmFlight compile: blocked by missing Teensy board platform

That is not a dRehmFlight failure.

It means the local CLI environment was not prepared for Teensy builds.

The upstream path remains Arduino IDE plus Teensyduino.

How I Would Try It Safely

For a real experiment, I would separate the workflow into phases:

  1. Read the documentation before wiring anything.
  2. Build the default Teensy and MPU6050 setup first.
  3. Confirm receiver channel input over serial diagnostics.
  4. Confirm IMU orientation and calibration with props removed.
  5. Understand throttle cut and failsafe behavior.
  6. Test output direction with motors disabled or props removed.
  7. Modify controlMixer() only after the default loop is understood.
  8. Tether or restrain early tests according to the aircraft type.

This is not bureaucracy.

It is the cost of writing code that moves hardware.

Where It Fits Beside Betaflight

Betaflight and dRehmFlight are both open flight-controller firmware projects, but they are optimized for different users.

Project Best Fit
Betaflight FPV multirotors, common flight-controller boards, configurator workflows, blackbox analysis, presets, broad community support
dRehmFlight Arduino/Teensy learning, custom VTOL prototypes, readable control-loop experiments, unusual mixers

If you have a normal FPV quad, Betaflight is the practical default.

If you want to learn how a flight controller works from source, or build a strange aircraft that does not fit a normal mixer, dRehmFlight is more interesting.

That is why this project belongs after the Betaflight posts.

It is not the next layer of the same production stack.

It is the educational mirror.

FAQ

Final Thoughts

dRehmFlight is not impressive because it has the biggest feature list.

It is impressive because it keeps the flight-controller idea visible.

You can read the loop.

You can find the mixer.

You can see where receiver input becomes desired state, where IMU data becomes attitude, where PID output becomes actuator commands, and where safety gates are applied.

That is exactly the kind of project worth studying after Betaflight.

Betaflight shows how a mature FPV firmware ecosystem works.

dRehmFlight shows the control loop with fewer layers between you and the code.