I built a quadrotor and its flight-control software from scratch, from raw IMU registers to motor PWM. A separate MATLAB study explores navigation estimation and constrained control without presenting simulation as flight evidence.
Hardware
Custom 3D-printed plus-configuration frame, EMAX ECO II 1700 KV motors, 7-inch three-blade propellers, 40 A PWM ESCs and a 4S 2200 mAh battery. First remote-controlled flight: October 2025.

Simulation
The current MATLAB repository model has 12 motion states and four squared-rotor-speed inputs. PID, LQR and constrained linear MPC run at 20 Hz; the nonlinear plant, IMU and navigation EKF advance at 200 Hz.
Historical visualisations: the following Simulink/Simscape image, hover/circle clips and plots document earlier work. They are preserved but are not the current comparison or hardware flight recordings.
Earlier simulated hover and circle tracking, with wind-force visualisation.

Current MATLAB study
A 2 m-radius circle at 2.5 m altitude, with a 30 s period and smooth start. All controllers share motor bounds and command-rate limits. Sensed cases use the same EKF design and matched noise sequences, never ground-truth controller feedback.
With wind and 40 ms motor lag, recorded 3D tracking RMS is 5.63 cm (LQR), 5.17 cm (MPC) and 11.39 cm (PID). Simulation only: assumed fixed RTK-GNSS/magnetic aiding, not physical flight accuracy or a universal controller ranking.

Electronics
- Processor: STM32G431KBT6, Cortex-M4 at 170 MHz.
- Active sensor: MPU6050 accelerometer/gyro over I2C.
- RC: four PWM channels, interrupt-driven input capture and digital low-pass filtering.
- Output: four ESC PWM signals.
- Carrier board: ultrasonic rangefinder, ESP32 and PWM breakout. These peripherals are not evidence of an active altitude/navigation loop in the public firmware.
Embedded control


A nominal 1 ms loop reads the IMU, estimates roll/pitch, runs control and updates ESC PWM; polling TIM6 pads the remaining period. The MPU6050 is configured for 200 Hz output, so loop reads are not necessarily fresh 1 kHz measurements. Boot includes stationary gyro averaging and an ESC calibration sequence. Timing is nominal, not a measured deadline guarantee.
The checked-in path uses a complementary attitude filter and roll/pitch PD. Yaw mixing and thrust are command inputs, not closed-loop heading or altitude estimates. The main loop zeros roll/pitch/yaw stick references for level-reference testing. A scalar angle KF is an alternative.
Attitude fusion and PD
χ̂k = (1 − λ)(χ̂k−1 + Tωmapped)
+ λχacc,k, λ = 0.02
e = χref − χ̂
τχ = kpe + kdLPF(Δe/T)
χ: roll/pitch. Board mapping: roll uses −gy, pitch uses gx; this is not a general 3D attitude solution.
The alternate scalar KF integrates gyro angle: A = H = 1, B = T, with accelerometer correction. Gain/covariance update each sample; there is no explicit gyro-bias state.
State-space models
Rigid-body dynamics and mixing
Thrust/drag scale with ui = ωi2. For position r, navigation velocity v and Euler angles η = [φ, θ, ψ]T:
[T, τx, τy, τz]T = Mu
M =ktktktktlkt0−lkt00lkt0−lktd−dd−dl: arm length; kt: thrust coefficient; d: rotor drag coefficient. Inverse mixing, nonnegative bounding, square root, then ESC conversion.
ṙ = v
v̇ = (T/m)Rbne3 − ge3 + Fw/m
IΩ̇ = τ − Ω × (IΩ)
Ω = E(η)η̇
R rotates body to navigation axes. E maps ZYX Euler rates to body rates. Fw: simulated wind. I: diagonal body inertia.
Hover model: LQR and MPC
At level hover: T = mg, uh = mg/(4kt). Linearising gives ẍ = gθ, ÿ = −gφ. With x = [r; η; v; η̇] and δu = u − uh1:
ẋ = Ax + Bδu
A =00I30000I30G000000G =0g0−g00000B =06×4BvBηA is 12×12; displayed entries are 3×3 blocks.
Ad = exp(ATs)
Bd = ∫0Tsexp(At)B dt
xk+1 = Adxk + Bdδuk
uk = uh1 − K(x̂k − xref,k)
Exact zero-order hold, Ts = 0.05 s. LQR uses state-error/motor-effort costs. Wind and motor lag are absent from the LQR/MPC design model but present in the disturbed test plant.
MPC: 40-sample prediction (2 s), 20 control moves, first move applied. Motor bounds and 0.2uh command-step limits are constraints. Simulation PID: position PI/velocity feedback requests acceleration; attitude control generates torque with feedforward and anti-windup. Neither runs in the published STM32 path.
Navigation EKF: simulation only
The 15-state additive Euler-angle EKF estimates ζ = [r; v; η; ba; bg]. The accelerometer measures body specific force:
ṙ = v
v̇ = Rbn(fm − ba) − ge3
η̇ = E−1(Ωm − bg)
ḃa = wa, ḃg = wg
Bias random walks; averaged adjacent IMU samples, Δt = 0.005 s.
Integrate constant acceleration over one sample, then linearise at the estimate. The resulting 15×15 transition uses 3×3 blocks:
R = Rbn. Ja: attitude derivative of rotated specific force; Jq: attitude derivative of Euler-rate mapping. MATLAB uses central-difference Jacobians. This is a local EKF model, not constant LTI.
Simulated RTK-GNSS at 10 Hz corrects position/velocity; magnetic field readings at 20 Hz correct attitude:
zmag = RTmn + nmag
Jm: attitude derivative of the magnetic prediction. Sequential corrections use Joseph covariance updates. Assumed RTK accuracy requires a fixed solution; outages, latency and vibration are not validated.
Controllers receive reordered estimated position, Euler angles, velocity and bias-corrected Euler rates. Truth is only used for the plant, sensor synthesis and scoring.
Hardware tests and validation
I progressed from simulation to suspended-axis tuning and remote-controlled flight in October 2025. The preserved electronics images and older controller/estimator plots above are development material, not proof that MEKF, altitude KF or drag-based velocity estimation runs in the current public firmware.
Repository host tests cover C estimation and mixing modules, not the complete sensor driver or flashed firmware. MATLAB tests cover plant linearisation, motor constraints and noisy/disturbed navigation runs. They do not establish a flight-ready autonomous stack. RTK integration and autonomous flight remain future work.
The drone was mainly tuned in simulation and later on tuned by axis by hanging the drone on strings. This led to rather unstable flight, especially using the pid controller. The ESP with wifi connectivity then allowed fine tuning during flight to stabilize the drone.



