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. ![1_R4VRDgKRKOV6ZHccD0GWzA](https://hackmd.io/_uploads/rJXWDIRBll.jpg) **System Overview** ![企业微信截图_20250711170346](https://hackmd.io/_uploads/rkNYm8RHge.png) **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)** ![企业微信截图_20250711170436](https://hackmd.io/_uploads/HJP37ICrge.png) **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