Advanced receiver firmware for micro quadcopter based on XIAO ESP32-S3 with professional modular design, cascaded PID control, and ESP-NOW telemetry.
This is a complete refactored drone receiver firmware that transformed from a single 437-line Arduino sketch into a professional, modular embedded system. The firmware implements sophisticated flight control algorithms while maintaining 100% behavioral compatibility with the original code.
- Dual Control Modes: ANGLE mode (roll/pitch) + RATE mode (yaw)
- Advanced PID Control: Cascaded PIDs with anti-windup and conditional integration
- ESP-NOW Communication: Bi-directional (RC uplink + telemetry downlink)
- X-Frame Mixer: Optimized for CW/CCW motor arrangement with anti-clip
- Professional Safety: Arming logic, failsafe, throttle gating
- Modular Architecture: 23 files with clean separation of concerns
- Board: Seeed Studio XIAO ESP32-S3
- CPU: ESP32-S3 @ 240 MHz
- Framework: Arduino + ESP-IDF APIs
- Language: C++17 with PlatformIO
Pin Mapping:
โโโ M1 (Front-Left, CW) โ GPIO 7, LEDC Ch0
โโโ M2 (Front-Right, CCW)โ GPIO 4, LEDC Ch1
โโโ M3 (Rear-Left, CW) โ GPIO 3, LEDC Ch2
โโโ M4 (Rear-Right, CCW) โ GPIO 1, LEDC Ch3
PWM: 12 kHz, 10-bit resolution (0-1023)
Interface: IยฒC @ 400 kHz
โโโ SDA โ GPIO 6
โโโ SCL โ GPIO 5
Configuration:
โโโ Gyroscope: ยฑ500 dps range
โโโ Accelerometer: ยฑ2g range
โโโ DLPF: ~42 Hz bandwidth
โโโ Calibration: 500-sample gyro bias on boot
Mode: Bidirectional
โโโ Uplink: RC command reception
โโโ Downlink: Telemetry transmission @ 2 Hz
โโโ Channel: 1 (configurable)
โโโ Range: ~100m line-of-sight
# Install PlatformIO
pip install platformio
# Clone and build
git clone <repository-url>
cd drone-rx-firmware
pio run
# Upload to board
pio run -t upload
# Monitor serial output
pio device monitor -b 115200- Connect XIAO ESP32-S3 via USB-C
- Wire MPU6050: SDAโGPIO6, SCLโGPIO5, VCCโ3.3V, GNDโGND
- Connect Motors: GPIO 7,4,3,1 to motor controllers
- Power: 1S LiPo (3.7V) with appropriate current capability
- Set Controller MAC: Edit
CTRL_MAC[]intelemetry.cpp - Tune PIDs: Modify constants in
config.h - Adjust Parameters: Flight limits, deadbands, etc. in
config.h
The firmware expects RC packets in this exact binary format:
struct RcPacket {
uint8_t magic; // 0xA5
uint8_t version; // 1
uint16_t seq; // Sequence number
uint16_t thr; // Throttle: 0..1000
int16_t yaw; // Yaw: -1000..1000
int16_t pitch; // Pitch: -1000..1000
int16_t roll; // Roll: -1000..1000
uint8_t flags; // bit0 = ARM (1=armed)
uint8_t rssi_hint; // Optional RSSI
uint16_t crc; // CRC-16/X.25
} __attribute__((packed));Real-time flight data transmitted at 2 Hz to ground station:
struct TelemetryPacket {
uint8_t magic; // 0xB5
uint8_t version; // 1
uint16_t seq; // Sequence
uint32_t ms; // Timestamp
// Setpoints (degrees ร 10 for precision)
int16_t setAngleRoll_x10, setAnglePitch_x10;
int16_t setYawRate_dps;
// Current attitude (degrees ร 10)
int16_t roll_deg_x10, pitch_deg_x10;
// Angular rates (deg/s)
int16_t rollRate_dps, pitchRate_dps, yawRate_dps;
// PID outputs
int16_t outRoll, outPitch, outYaw;
// Motor mixer values (0-1000)
uint16_t m1, m2, m3, m4;
// Status
uint16_t thr; // Throttle
uint8_t armed; // Armed state
uint8_t linkAlive; // RC link status
uint16_t crc; // CRC-16/X.25
} __attribute__((packed));RC Input โ Deadband โ Setpoints
โ
IMU โ Attitude Estimation (Complementary Filter)
โ
Angle PID โ Rate Setpoint โ Rate PID โ Mixer โ Motors
โ
Gyro Rates
- Roll/Pitch: ANGLE mode with cascaded control
- Outer loop: Angle PID (degrees โ deg/s)
- Inner loop: Rate PID (deg/s โ motor output)
- Yaw: Direct RATE mode with conditional integration
- Throttle: Direct pass-through with arming ramp
- Arming Logic: Requires both link + ARM flag
- Soft Ramping: 0.5s ramp-up on ARM, instant cutoff on DISARM
- Failsafe: 200ms RC timeout โ automatic disarm
- Throttle Gating: No stabilization below 5% throttle
- Anti-Windup: Conditional integration to prevent PID saturation
Default gains optimized for micro quadcopters:
// Angle PIDs (degrees โ deg/s)
#define PID_ANGLE_ROLL_KP 3.0f
#define PID_ANGLE_ROLL_KD 0.05f
// Rate PIDs (deg/s โ output)
#define PID_RATE_ROLL_KP 0.12f
#define PID_RATE_ROLL_KD 0.002f
// Yaw with integral term
#define PID_RATE_YAW_KP 0.15f
#define PID_RATE_YAW_KI 0.02f
#define PID_RATE_YAW_KD 0.001f- Start Conservative: Reduce all gains by 50%
- Tune Rate PIDs First: Increase Kp until oscillations appear, back off 20%
- Add Damping: Increase Kd to reduce oscillations
- Tune Angle PIDs: Similar process for outer loop
- Add Yaw Integration: Minimal Ki to eliminate steady-state error
firmware/
โโโ include/ # Header files (interfaces)
โ โโโ config.h # All configuration constants
โ โโโ types.h # Data structures & types
โ โโโ pid.h # PID controller classes
โ โโโ imu.h # IMU sensor interface
โ โโโ mixer.h # Motor mixing algorithms
โ โโโ safety.h # Arming & failsafe logic
โ โโโ telemetry.h # Downlink telemetry
โ โโโ [8 more...] # Other module interfaces
โโโ src/ # Implementation files
โโโ main.cpp # Main control loop
โโโ pid.cpp # PID implementations
โโโ imu.cpp # MPU6050 driver
โโโ [7 more...] # Module implementations
- Single Responsibility: Each module has one clear purpose
- Clean Interfaces: Well-defined APIs between modules
- Zero Heap: No dynamic allocation in main control loop
- ISR Safety: Radio callbacks only touch volatile buffers
- Configurable: All parameters centralized in
config.h
- Slew Limiting: 800 duty/s rate limit prevents voltage sag
- Idle Floor: 8% minimum PWM when armed for instant response
- Anti-Clip Mixer: Preserves control authority when motors saturate
- Motor Scaling: Per-motor trim for CW/CCW torque balance
- Complementary Filter: 98% gyro integration + 2% accelerometer
- Configurable Mapping: Easy IMU orientation changes
- Bias Calibration: Automatic gyro offset correction
- Packet Validation: Magic bytes + version + CRC verification
- ISR-Safe Reception: Minimal processing in interrupt context
- Non-Blocking Transmission: Telemetry never blocks control loop
T: Motor test sequence (20% power, 400ms each)
ARM:1 THR:450 setAng R:15.2 P:-8.1 ang R:14.8 P:-7.9
rate R:125.4 P:-89.2 Y:12.3 out R:45.2 P:-23.1 Y:8.7
base:450.0 m:[523 389 427 495]
- IMU Fail: Check I2C wiring and 3.3V power
- ESP-NOW Fail: Verify controller MAC address
- Motor Issues: Test with 'T' command, check PWM connections
- No ARM: Ensure RC link active and ARM flag set
- Control Loop: ~500 Hz (2ms typical, max 20ms)
- IMU Reading: 400 kHz I2C, ~1ms
- Motor Update: 12 kHz PWM, hardware-generated
- Telemetry: 2 Hz downlink, <1ms processing
- Memory: <32KB flash, <4KB RAM
RC Reception: <5ms (ESP-NOW + validation)
Control Calc: ~2ms (PID + mixer + filters)
Motor Output: <1ms (PWM register update)
Total Latency: <8ms (stick to motor response)
- Battery Monitoring: ADC-based voltage sensing
- Flight Modes: Acro, Horizon, GPS hold
- Blackbox Logging: SD card flight data recording
- Parameter Tuning: Runtime PID adjustment via telemetry
- Multiple Profiles: Switchable flight characteristics
- Additional Sensors: Barometer, magnetometer, GPS
- Advanced Control: Optical flow, position hold
- Smart Features: Return-to-home, waypoint navigation
- Connectivity: WiFi configuration, smartphone app
This firmware is designed for educational and research purposes.
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push branch (
git push origin feature/amazing-feature) - Open Pull Request
- ๐ Documentation: Check
README.mdand code comments - ๐ Issues: Use GitHub Issues for bug reports
- ๐ฌ Discussions: GitHub Discussions for questions
- ๐ง Direct: Contact maintainers for critical issues
๐ Happy Flying!