An open-source, high-performance micro-quadcopter flight controller firmware built for the dual-core ESP32-WROOM-32 (Xtensa LX6). It features hardware-accelerated 400 kHz I2C sensor fusion, 20 kHz PWM motor drive, and a dual-pipeline input arbiter multiplexing a high-speed STM32 nRF24 SBUS radio receiver and a zero-latency WebSocket Web Dashboard over local SoftAP.
The firmware exploits the asymmetric dual-core architecture of the ESP32-WROOM-32 using FreeRTOS task pinning to ensure the real-time flight control loop is never interrupted by networking or TCP/IP jitter.
┌─────────────────────────────────────────────────────────┐
│ ESP32-WROOM-32 SILICON │
└────────────────────────────┬────────────────────────────┘
│
┌───────────────────────────────┴───────────────────────────────┐
│ │
┌────────────▼────────────┐ ┌────────────▼────────────┐
│ CORE 0 │ │ CORE 1 │
│ (Networking Core) │ │ (Flight Control) │
└────────────┬────────────┘ └────────────┬────────────┘
│ │
┌─────────┴─────────┐ ┌─────────┴─────────┐
│ WiFi SoftAP │ │ IMU (MPU6050) │
│ (SSID: "DRONE") │ │ 400kHz Fast I2C │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
┌─────────┴─────────┐ ┌─────────┴─────────┐
│ HTTP Web Server │ │ SBUS Receiver │
│ (Port 80 HTML5) │ │ UART2 100k 8E2 │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
┌─────────┴─────────┐ ┌─────────┴─────────┐
│ WebSockets (81) │ │ Input Arbiter │
│ 100ms Telemetry │ │ Setpoints/Safety │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
│ Shared Telemetry Snapshot & Control Spinlock (Thread-Safe) │
└───►───────────────────────────────────────────────────────◄───┤
│
┌─────────┴─────────┐
│ Cascaded PID │
│ Angle & Rate │
└─────────┬─────────┘
│
┌─────────┴─────────┐
│ LEDC Motor Mixer │
│ 20kHz Coreless │
└───────────────────┘
- Core 0 (Networking & Dashboard Task):
- Manages the
802.11 b/g/nSoftAP network (192.168.4.1). - Serves the integrated HTML5/JS Glassmorphism Ground Control Station over HTTP Port 80.
- Handles bidirectional WebSocket communication (Port 81), parsing incoming command streams and broadcasting live attitude/telemetry packets at 10 Hz.
- Manages the
- Core 1 (Deterministic 250 Hz Flight Loop):
- Executes a strictly timed 4000 µs loop.
- Reads raw 6-DOF gyroscope and accelerometer registers over 400 kHz I2C with complementary attitude estimation.
- Ingests inverted Futaba/FrSky SBUS frames at 100 kbps over hardware UART2.
- Computes outer angle and inner rate PID loops.
- Drives 4 coreless DC motors using 20 kHz ultrasonic PWM via ESP32 LEDC timers.
- Samples battery voltage on dedicated ADC1 (GPIO 34) without interference from the WiFi radio.
| Component / Subsystem | Pin Name | ESP32 GPIO | Peripheral Channel | Wiring & Hardware Notes |
|---|---|---|---|---|
| STM32 SBUS Receiver | RX2 |
GPIO 16 | UART2_RX |
Connect to STM32 UART2 TX (Inverted 100k 8E2). |
| MPU6050 IMU SDA | I2C_SDA |
GPIO 21 | I2C0_SDA |
400 kHz I2C Data (Requires 4.7kΩ pull-up to 3.3V). |
| MPU6050 IMU SCL | I2C_SCL |
GPIO 22 | I2C0_SCL |
400 kHz I2C Clock (Requires 4.7kΩ pull-up to 3.3V). |
| Motor 1: Front-Right | M1_FR |
GPIO 19 | LEDC_CH0 |
CCW Rotation. Driven via N-MOSFET (20 kHz PWM). |
| Motor 2: Rear-Left | M2_RL |
GPIO 18 | LEDC_CH1 |
CCW Rotation. Driven via N-MOSFET (20 kHz PWM). |
| Motor 3: Front-Left | M3_FL |
GPIO 23 | LEDC_CH2 |
CW Rotation. Driven via N-MOSFET (20 kHz PWM). |
| Motor 4: Rear-Right | M4_RR |
GPIO 25 | LEDC_CH3 |
CW Rotation. Driven via N-MOSFET (20 kHz PWM). |
| Battery Sense (ADC1) | BATT_ADC |
GPIO 34 | ADC1_CH6 |
Input-only. |
| Status LED | STATUS_LED |
GPIO 2 | GPIO |
Active-HIGH onboard LED on ESP32 DevKit. |
X-QUAD MOTOR ORIENTATION
▲ FRONT (Heading)
│
M3 (FL, CW) │ M1 (FR, CCW)
[GPIO 23] │ [GPIO 19]
\ │ /
\ │ /
\────┴────/
│ ESP32 │
│ WROOM32 │
/────┬────\
/ │ \
/ │ \
M2 (RL, CCW) │ M4 (RR, CW)
[GPIO 18] │ [GPIO 25]
│
REAR
The Input Arbiter (input_arbiter.h) provides seamless multiplexing between the physical 2.4 GHz nRF24/STM32 radio receiver and the emergency/auxiliary WiFi Web Dashboard.
INPUT ARBITRATION MATRIX
┌───────────────────────────────────────────────────────────────────────────┐
│ RADIO ACTIVE? FAILSAFE BIT? AUX1 DELEGATION? WIFI ACTIVE? │ ACTIVE │
├───────────────────────────────────────────────────────────────┼───────────┤
│ YES NO NO ANY │ RADIO │
│ YES NO YES YES │ WIFI │
│ YES NO YES NO │ RADIO │
│ NO -- -- YES │ WIFI │
│ NO -- -- NO │ DISARM/FS │
│ YES YES -- NO │ DISARM/FS │
└───────────────────────────────────────────────────────────────────────────┘
-
Channel 1 (Roll / Aileron):
$1000 \dots 2000,\mu\text{s} \longrightarrow -30.0^\circ \dots +30.0^\circ$ (Angle Mode). -
Channel 2 (Pitch / Elevator):
$1000 \dots 2000,\mu\text{s} \longrightarrow -30.0^\circ \dots +30.0^\circ$ (Angle Mode). -
Channel 3 (Throttle):
$1000 \dots 2000,\mu\text{s} \longrightarrow 0 \dots 255$ PWM (Headroom reserved for PID). -
Channel 4 (Yaw / Rudder):
$1000 \dots 2000,\mu\text{s} \longrightarrow -180^\circ/\text{s} \dots +180^\circ/\text{s}$ (Rate Mode). -
Channel 5 (AUX1 — Control Delegation Switch):
-
$< 1300,\mu\text{s}$ : Physical Radio Control. -
$> 1700,\mu\text{s}$ : Delegate control authority to WiFi WebSocket dashboard.
-
-
Channel 6 (AUX2 — Arm Switch):
-
$> 1500,\mu\text{s}$ : Armed (Enforces throttle$< 5%$ safety interlock before spin-up). -
$< 1500,\mu\text{s}$ : Disarmed.
-
-
Channel 7 (AUX3 — Flight Mode):
-
$< 1500,\mu\text{s}$ : Stabilized Angle Mode (Self-leveling cascaded PID). -
$> 1500,\mu\text{s}$ : Acro / Rate Mode (Direct rate gyro tracking).
-
-
Radio Signal Loss: If the STM32 receiver loses nRF24 link, it asserts SBUS Byte 23 Flag Bit 3 (
0x08). -
Dual Signal Loss Failsafe: If SBUS failsafe is asserted AND WiFi heartbeat times out (
$> 500\text{ ms}$ ),motors_disarm()is invoked instantaneously ($0\text{ ms}$ delay), shutting off all 4 PWM channels and zeroing PID integrators. -
Critical Battery Disarm: If battery voltage drops below
$3.00\text{ V}$ ($1\text{S LiPo}$ cutoff), the flight controller performs an emergency auto-disarm.
- PlatformIO Core (CLI) or PlatformIO IDE (VS Code extension).
- USB-to-UART drivers (CP2102 / CH340) installed.
# Clone the repository
git clone https://github.com/iD024/ESP32FlightController.git
cd ESP32FlightController
# Compile firmware for ESP32-WROOM-32
pio run -e esp32dev
# Upload to ESP32 (specify port if not auto-detected)
pio run -e esp32dev --target upload
# Launch serial telemetry monitor (115200 baud)
pio device monitor -b 115200- Place the drone on a flat, level, stationary surface.
- Power on the board. The status LED will turn solid ON during calibration.
- The MPU6050 samples 2000 gyro/accelerometer readings to compute precise zero-rate offsets and level gravity vectors.
- When calibration completes, the LED issues 3 rapid blinks, indicating the drone is ready for arming.
The flight controller hosts an onboard HTML5/JS Ground Station stored in flash memory.
┌─────────────────────────────────────────────────────────────┐
│ COMET DRONE GROUND CONTROL STATION │
│ │
│ Attitude: Roll: +2.14° Pitch: -0.85° Yaw: 142.30° │
│ Battery : [██████████] 4.12 V (92%) Loop: 250 Hz │
│ Link : Active (RADIO SBUS) Arm Status: DISARMED │
│ │
│ [Motor FR: 0] [Motor RL: 0] [Motor FL: 0] [Motor RR: 0] │
└─────────────────────────────────────────────────────────────┘
-
Connect to SoftAP:
-
SSID:
DRONE -
Password:
drone1234
-
SSID:
-
Launch Dashboard:
- Open any browser and navigate to
http://192.168.4.1.
- Open any browser and navigate to
-
Real-Time Telemetry:
- Displays 3D artificial horizon / attitude angles (
$\text{Roll}, \text{Pitch}, \text{Yaw}$ ). - Individual real-time motor PWM outputs (
$M_1 \dots M_4$ ). - Battery voltage and percentage calculation with visual alerts.
- Active control source indicator (
RADIO (SBUS)vsWIFI (WebSocket)).
- Displays 3D artificial horizon / attitude angles (
Connect over USB Serial to tune PID gains live without recompiling:
| Command | Description | Example |
|---|---|---|
RP:<val> |
Set Roll Rate |
RP:0.55 |
RI:<val> |
Set Roll Rate |
RI:0.12 |
RD:<val> |
Set Roll Rate |
RD:0.035 |
PP:<val> |
Set Pitch Rate |
PP:0.55 |
PI:<val> |
Set Pitch Rate |
PI:0.12 |
PD:<val> |
Set Pitch Rate |
PD:0.035 |
AP:<val> |
Set Roll Angle |
AP:2.20 |
BP:<val> |
Set Pitch Angle |
BP:2.20 |
MT:<0-3> |
Test spin individual motor at low speed | MT:0 |
MS |
Emergency stop all motors | MS |
ST |
Print comprehensive system status report | ST |
Distributed under the MIT License. See LICENSE for details.