Let’s build a full quadcopter flight controller using [Arduino](https://www.ampheo.com/c/development-board-arduino) + MPU6050, with PID control for pitch, roll, and yaw. This setup will stabilize all three axes and drive 4 ESCs for brushless motors.

**System Overview**

**Hardware Required**
* [Arduino Uno](https://www.ampheo.com/product/a000046-25542493) / Nano / Mega
* MPU6050 (6-axis IMU)
* 4× ESCs (PWM compatible)
* 4× Brushless motors (2 CW + 2 CCW)
* [Power supply](https://www.onzuu.com/category/external-internal-power-supply) (LiPo + BEC for 5V to Arduino)
* Optional: RC receiver (for user control)
**Wiring (Example for Arduino Uno)**

**Code: Full 3-Axis PID Stabilization**
**Libraries Needed:**
* Wire.h
* MPU6050 (by Jeff Rowberg)
* Servo.h
**[Arduino](https://www.ampheoelec.de/c/development-board-arduino) Code (Simplified)**
```
cpp
#include <Wire.h>
#include <MPU6050.h>
#include <Servo.h>
MPU6050 mpu;
Servo esc1, esc2, esc3, esc4;
float pitch, roll, yaw;
float gyroX, gyroY, gyroZ;
float accX, accY, accZ;
float dt = 0.01;
unsigned long prevTime;
// PID gains (adjust for tuning)
float kp = 1.5, ki = 0.0, kd = 0.5;
float pitchI, pitchD, pitchErr, pitchPrevErr;
float rollI, rollD, rollErr, rollPrevErr;
int baseThrottle = 1150; // hover point
void setup() {
Serial.begin(9600);
Wire.begin();
mpu.initialize();
esc1.attach(3); // Front
esc2.attach(5); // Right
esc3.attach(6); // Back
esc4.attach(9); // Left
// Arm ESCs
esc1.writeMicroseconds(baseThrottle);
esc2.writeMicroseconds(baseThrottle);
esc3.writeMicroseconds(baseThrottle);
esc4.writeMicroseconds(baseThrottle);
delay(3000); // Wait for ESCs
prevTime = millis();
}
void loop() {
unsigned long now = millis();
dt = (now - prevTime) / 1000.0;
prevTime = now;
int16_t ax, ay, az, gx, gy, gz;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
accX = ax / 16384.0;
accY = ay / 16384.0;
accZ = az / 16384.0;
gyroX = gx / 131.0;
gyroY = gy / 131.0;
gyroZ = gz / 131.0;
// Complementary filter for pitch and roll
float accPitch = atan2(accY, accZ) * 180 / PI;
float accRoll = atan2(-accX, accZ) * 180 / PI;
pitch += gyroX * dt;
roll += gyroY * dt;
pitch = 0.98 * pitch + 0.02 * accPitch;
roll = 0.98 * roll + 0.02 * accRoll;
yaw += gyroZ * dt; // Optional for basic yaw control
// PID - Pitch
pitchErr = 0 - pitch;
pitchI += pitchErr * dt;
pitchD = (pitchErr - pitchPrevErr) / dt;
pitchPrevErr = pitchErr;
float pitchPID = kp * pitchErr + ki * pitchI + kd * pitchD;
// PID - Roll
rollErr = 0 - roll;
rollI += rollErr * dt;
rollD = (rollErr - rollPrevErr) / dt;
rollPrevErr = rollErr;
float rollPID = kp * rollErr + ki * rollI + kd * rollD;
// Combine throttle + PID to control each motor
int m1 = baseThrottle + pitchPID - rollPID; // Front
int m2 = baseThrottle - pitchPID - rollPID; // Right
int m3 = baseThrottle - pitchPID + rollPID; // Back
int m4 = baseThrottle + pitchPID + rollPID; // Left
// Limit motor values (1000–2000us)
esc1.writeMicroseconds(constrain(m1, 1000, 2000));
esc2.writeMicroseconds(constrain(m2, 1000, 2000));
esc3.writeMicroseconds(constrain(m3, 1000, 2000));
esc4.writeMicroseconds(constrain(m4, 1000, 2000));
Serial.print("Pitch: "); Serial.print(pitch);
Serial.print(" | Roll: "); Serial.println(roll);
}
```
**What This Code Does:**
* Stabilizes pitch and roll using gyro + accel data
* Runs PID loop for both axes
* Outputs adjusted PWM values to 4 ESCs
* Optional: yaw control can be added using gyroZ
**Next Steps for Real Drone Flight:**
1. Tune PID gains carefully (start small, increase gradually)
2. Integrate RC receiver for manual throttle/yaw/pitch/roll input
3. Add arming/safety switch
4. Implement altitude hold (barometer) or GPS navigation