Manless Aerial Device
This is a 1000 line Arduino ESP32 / RP2040 / STM32 flight controller, forked from dRehmFlight. A functional DIY flight controller can be build for under $10 from readily available development boards and sensor breakout boards. Ideal if you want to try out new flight control concepts, without first having to setup a build environment and without having to read through thousands lines of code to find the spot where you want to change something.
madflight/madflight.ino
is a demo program for a quadcopter, but can be easily adapted to control your plane or VTOL craft. The source code has extensive documentation explaning what the settings and functions do.
Flight tested on ESP32, RP2040, and STM32F405 microcontrollers with the Arduino IDE. It mainly uses plain Arduino functionality: Serial, Wire, and SPI. One custom hardware dependent library is used for PWM. Therefor, it can fairly easily ported to other 32 bit microcontrollers that support the Arduino framework. Also porting to other build environments like PlatformIO or CMake should not be a huge effort.
- Development board:
- RP2040 (e.g. Raspberry Pi Pico)
- or ESP32 (e.g. Espressiv DevKitC)
- or STM32 (e.g. Black Pill or a flight controller)
- SPI IMU sensor (BMI270, MPU9250, MP6500, or MPU6000), if not available then use an I2C IMU sensor (MPU6050 or MPU9150)
- RC Receiver: ELRS, CRSF, SBUS, DMSX, or PPM
- BEC or DC-DC converter to power your board from a battery
- ESC (OneShot125 or 50-490Hz PWM) and/or servos (50-490Hz PWM)
- GPS Module (Serial)
- Barometer (I2C BMP280, MS5611)
- Magnetometer (I2C QMC5883L)
- Current/Voltage Sensor (ADC or I2C INA226)
- Optical Flow Sensor (I2C)
- Open madflight/madflight.ino in the Arduino IDE.
- Setup the USER-SPECIFIED DEFINES section in the main code, and configure the pins in hw_XXX.h (see below for default pinouts)
- Connect your IMU (gyro/acceleration) sensor as shown below.
- Compile and upload madflight. Connect the Serial Monitor at 115200 baud and check the messages. Type 'help' to see the available CLI commands.
- Check that IMU sensor and AHRS are working correctly: use CLI print commands to show gyro, accelerometer, magnetometer and roll/pitch/yaw.
- Use CLI to calibate the sensor.
- Connect radio receiver to your development board according to the configured pins.
- Edit the RC RECEIVER CONFIG section in the main code. Either match you RC equipment to the settings, or change the settings to match your RC equipment.
- Check your radio setup: Use CLI print commands to show pwm and scaled radio values.
- Connect motors (no props) and battery and check that motor outputs are working correctly. For debugging, use CLI to show motor output.
- Mount props, go to an wide open space, and FLY!
By default madflight has these safety features enabled:
- Motors only rotate when armed.
- Arming Procedure: set throttle low then flip the arm switch from disarmed to armed.
- Kill Switch: when the arm switch is in the disarm position, disarm and stop motors until re-armed.
- Failsafe: when radio connection is lost, disarm and stop motors until re-armed.
- Armed Low Throttle: motors run at low speed, to give visible armed indication.
- LED armed/disarmed indicator.
I enjoy hacking around with electronics and I'm attempting to write some decent code for this project. If you enjoy it as well, please leave some feedback in the form of Stars, Issues, Pull Requests, or Discussions. Thanks!
- Keep it simple!!!
- No external dependencies, all module libraries included in
src
directory. - Coded for readability, not for speed or smallest size.
- The flight controller madflight.ino runs standard
setup()
andloop()
. - The madflight.ino uses the following modules:
loop
Main loop controlimu
Inertial Measurement Unit, retrieves accelerometer, gyroscope, and magnetometer sensor dataahrs
Attitude Heading Reference System, estimates roll, yaw, pitchrcin
RC INput, retrieves RC receiver datacontrol
PID controller and output mixerout
Output to motors and servosmag
Magnetometer (external)baro
Barometergps
GPS receiverbb
Black Box data loggercli
Command Line Interface for debugging, configuration and calibrationcfg
Read and save configuration to flashhw
Hardware specific code for STM32, RP2040 and ESP32
- Most modules are interfaced through a global object, for example
imu.gx
is the current gyro x-axis rate in degrees per second for the selected IMU chip. - The header
src/interfaces.h
defines the module interfaces. - The module implementations are in subdirectories of the
src
directory. Here you find the module header file, e.g.src/imu/imu.h
. There might also be an .ino module test program, e.g.src/imu/imu.ino
. - The module files are usually header only, that is, the header also includes the implemention.
SPI sensor: (highly recommended over I2C)
Sensor Dev Board
SCL/SCLK <---> SPI_SCLK
SDA/SDI <---> SPI_MOSI
ADD/SDO <---> SPI_MISO
NCS <---> IMU_CS
INT <---> IMU_EXTI
VCC <---> 3V3
GND <---> GND
I2C sensor:
Sensor Dev Board
SCL <---> I2C_SCL
SDA <---> I2C_SDA
INT <---> IMU_EXTI
VCC <---> 3V3
GND <---> GND
This pinout can be configured as needed in hw_ESP32.h
Function | GPIO | Board | GPIO | Function |
---|---|---|---|---|
3V3 out | 3V3 | Antenna side | GND | GND |
reset button | EN | 23 | I2C_SDA | |
SPI_MISO | VP 36 input only | 22 | I2C_SCL | |
IMU_EXTI | VN 39 input only | 1 TX | USB Serial Debug TX | |
BAT_V | 34 input only | 3 RX | USB Serial Debug RX | |
RCIN_RX | 35 input only | 21 | SPI_MOSI | |
RCIN_TX | 32 | GND | GND | |
PWM1 | 33 | 19 | SPI_SCLK | |
PWM2 | 25 | 18 | IMU_CS | |
PWM3 | 26 | strap 5 | GPS_TX | |
PWM4 | 27 | 17 | GPS_RX | |
PWM5 | 14 | 16 | PWM11 | |
PWM6 | 12 | 4 | PWM10 | |
GND | GND | boot 0 | PWM9 | |
PWM7 | 13 | strap 2 | LED | |
nc | D2 9 flash | strap 15 | PWM8 | |
nc | D3 10 flash | flash 8 D1 | nc | |
nc | CMD 11 flash | flash 7 D0 | nc | |
5V in (*) | 5V | USB connector | flash 6 CLK | nc |
Note: During boot the input voltage levels (pull up/pull down) on strap pins have a configuration function, therefor these pins are used as output only.
(*) 5V input via diode from BEC. Without a diode take care not connect USB and the battery at the same time!
This pinout can be configured as needed in hw_RP2040.h
Function | GPIO | Board | GPIO | Function |
---|---|---|---|---|
RCIN_TX | 0 | USB connector | VBUS | nc |
RCIN_RX | 1 | VSYS | 5V input via diode (*) | |
- | GND | GND | - | |
PWM1 | 2 | EN | nc | |
PWM2 | 3 | 3.3V out | 3V3 | |
PWM3 | 4 | VREF | nc | |
PWM4 | 5 | 28_A2 | BAT_V | |
- | GND | GND | - | |
PWM5 | 6 | 27_A1 | FREE | |
PWM6 | 7 | 26_A0 | FREE | |
GPS_TX | 8 | RUN | reset button to GND | |
GPS_RX | 9 | 22 | IMU_EXTI | |
- | GND | GND | - | |
PWM7 | 10 | 21 | I2C_SCL | |
PWM8 | 11 | 20 | I2C_SDA | |
PWM9 | 12 | 19 | SPI_MOSI | |
PWM10 | 13 | 18 | SPI_SCLK | |
- | GND | GND | - | |
PWM11 | 14 | 17 | IMU_CS | |
PWM12 | 15 | JTAG pins | 16 | SPI_MISO |
(*) 5V input via diode from BEC. Without a diode take care not connect USB and the battery at the same time!
This pinout can be configured as needed in hw_STM32.h
Function | GPIO | Board | GPIO | Function |
---|---|---|---|---|
- | VB | SWD pins | 3V3 | - |
LED | C13 | G | - | |
FREE | C14 | 5V | 5V input (*) | |
FREE | C15 | B9 | PWM10(t4) | |
- | R | B8 | PWM9(t4) | |
FREE | A0 | B7 | I2C_SCL | |
FREE | A1 | B6 | I2C_SDA | |
GPS_TX | A2 | B5 | PWM8(t3) | |
GPS_RX | A3 | B4 | PWM7(t3) | |
IMU_CS | A4 | B3 | RCIN_RX | |
SPI_SCLK | A5 | A15 | RCIN_TX | |
SPI_MISO | A6 | A12 | USB_DP | |
SPI_MOSI | A7 | A11 | USB_DN | |
BAT_I | B0 | A10 | PWM6(t1) | |
BAT_V | B1 | A9 | PWM5(t1) | |
FREE | B2 | A8 | PWM4(t1) | |
IMU_EXTI | B10 | B15 | PWM3(t1) | |
- | 3V3 | B14 | PWM2(t1) | |
- | G | B13 | PWM1(t1) | |
- | 5V | USB connector | B12 | FREE |
Board: LED: C13, key button: A0
PWM1-6 are connected to timer1, PWM7-8 to timer3 and PWM9-10 to timer4. PWM pins connected to the same timer operate at the same frequency.
(*) 5V input via diode from BEC. Without a diode take care not connect USB and the battery at the same time!
- Add support for RP2040, ESP32, and STM32
- Dropped Teensy support, but could be re-added by creating a hw_TEENSY.h file. (I just don't have the hardware to test on)
- Moved all hardware specific code to hw_XXX.h and added hardware specific libraries
- Reduced the number of global variables
- Oneshot is implemented as PWM up to 3.9kHz
- New libs for IMU sensors
- Changed arming logic
- Loop rate set to 1kHz to match IMU sensor rate
- Interrupt driven IMU operation by default, but setup/loop still possible
In increasing order of complexity.
- lobodol/drone-flight-controller Arduino ATmega328P, single 700 line ino file, no libs
- dRehmFlight Arduino Teensy 4
- madflight Arduino RP2040, ESP32, and STM32
- Crazyflie STM32F405
- esp-drone ESP32 (forked from Crazyflie)
- Betaflight STM32 F4/F7/H7
- inav STM32 F4/F7/H7
- Ardupilot STM32 F4/F7/H7 or Linux based
This code is a shared, open source flight controller for small micro aerial vehicles and is intended to be modified to suit your needs. It is NOT intended to be used on manned vehicles. I do not claim any responsibility for any damage or injury that may be inflicted as a result of the use of this code. Use and modify at your own risk. More specifically put:
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Logo image copyright (c) 1975 Deutsches MAD Magazine. This project is not associated with MAD Magazine.