On 29 January 2022, the Beating Retreat ceremony at Vijay Chowk in Delhi flew a formation of 1,000 drones built by the IIT-Delhi-incubated startup BotLab Dynamics, tracing patterns in the night sky over the capital. No pilot touched a joystick. Each drone knew its own position to within a few centimetres, held that position while banking, climbing and holding station in a swarm of a thousand neighbours, and did so without colliding or drifting out of formation for the duration of the show. That is not a GPS-navigation problem in the sense a car's map app solves it. A car can be a few metres off its lane and the driver corrects. A drone that is a few metres off in a thousand-drone formation either collides with a neighbour or breaks the picture. The gap between "know roughly where you are" and "hold a position to centimetre precision while a physical vehicle is trying to tip over under you" is exactly what this chapter is about: how a drone estimates its own state from noisy sensors, and how it converts that estimate into motor commands fast enough and accurately enough to stay stable in the air.
Two problems sit underneath every drone autonomy stack, and they are genuinely different problems even though marketing language blurs them together. The first is state estimation: given noisy, low-rate, sometimes-missing sensor readings, what is the drone's actual position, velocity, and orientation right now? The second is control: given that estimate and a desired trajectory, what should each of the four (or six, or eight) motors do, updated hundreds of times per second, to make the actual state track the desired one? Path planning, the part most people think of first when they hear "drone navigation," sits on top of both: it decides where the drone should go, but it is useless without an accurate answer to "where am I" and a fast-enough answer to "how do I get there without flipping over."
Reference frames: the language the whole stack speaks in
Before any of this makes sense, fix the coordinate systems. A drone's autopilot reasons in at least two frames simultaneously. The inertial frame (commonly NED: North-East-Down, or the GPS-friendly ENU: East-North-Up) is fixed to the Earth and is where waypoints, GPS fixes, and the mission plan live. The body frame is fixed to the drone itself, with its x-axis out the nose, y-axis out the right wing, z-axis down through the belly, and it is where the IMU (inertial measurement unit) actually measures. The drone's orientation relative to the inertial frame is described by three Euler angles: roll (φ, rotation about the body x-axis, tipping side to side), pitch (θ, rotation about the body y-axis, nose up or down), and yaw (ψ, rotation about the body z-axis, turning left or right).
Every control decision requires converting between these frames using a rotation matrix built from φ, θ, ψ. A thrust command is generated in the body frame (motors push "down" relative to the drone's own belly), but the desired direction of travel is specified in the inertial frame (fly north). Get the rotation wrong and a nose-up drone accelerates backward instead of forward. Production autopilots (PX4, ArduPilot) use quaternions internally rather than raw Euler angles specifically because Euler angles have a well-known failure mode called gimbal lock, where two of the three rotation axes align and one degree of freedom is lost, producing a mathematically or wildly unstable attitude estimate near pitch = ±90°. A student encountering Euler angles for the first time can reason entirely in roll/pitch/yaw for this chapter; just know that "why does the real flight controller use quaternions" has this specific answer, not a vague "they're more efficient."
The sensing problem: nothing measures the truth directly
A drone's IMU contains a 3-axis accelerometer and a 3-axis gyroscope, typically sampled at 500 Hz to 8 kHz. Neither sensor, alone, gives you attitude. The gyroscope measures angular rate (degrees per second), not angle, so getting an angle out of it means integrating over time, and any small constant bias in the sensor (a few tenths of a degree per second is typical for a commodity MEMS gyro) integrates into an angle error that grows without bound. Leave a drone sitting still on a table and integrate raw gyro output for sixty seconds; the "estimated" roll angle will have wandered several degrees away from zero, even though the drone never moved.
The accelerometer measures specific force, which at rest is dominated by gravity, so when the drone is not accelerating you can back out roll and pitch from the direction of the measured gravity vector: roll ≈ atan2(a_y, a_z). This does not drift over time, because it is a fresh measurement every sample, not an accumulated one. But it is noisy on every individual sample (vibration from the propellers alone can add several degrees of instantaneous error) and it is wrong whenever the drone is actually accelerating, because then the sensor is measuring gravity plus manoeuvre acceleration, not gravity alone.
So the two sensors have complementary failure modes: the gyro is accurate over short timescales and drifts over long ones; the accelerometer is accurate over long timescales (on average, its noise cancels out) and is unreliable instant to instant. This is precisely what a complementary filter exploits.
Worked example: fusing gyro and accelerometer for roll angle
The filter update is:
roll_est(t) = alpha * (roll_est(t-1) + gyro_rate * dt) + (1 - alpha) * roll_accel(t)
The first term is the gyro's short-term prediction (trusted heavily, weight alpha close to 1); the second is the accelerometer's independent, drift-free but noisy measurement (given a small corrective weight 1 - alpha). Take alpha = 0.98, a sample interval dt = 0.1 s (10 Hz, slowed down from a real 100+ Hz IMU purely so the arithmetic is traceable by hand), and a gyro that reads a constant 5°/s about the roll axis (this reading is a mix of the drone's true 4.5°/s roll rate plus a 0.5°/s sensor bias the filter does not know about). The accelerometer, independently and noisily, reports roll values of 1.0°, 0.9°, and 1.3° on three successive samples. Starting from roll_est(0) = 0°:
Step 1 (t = 0.1 s): gyro-predicted roll = 0 + 5°/s × 0.1 s = 0.5°. Fused estimate = 0.98 × 0.5 + 0.02 × 1.0 = 0.49 + 0.02 = 0.51°.
Step 2 (t = 0.2 s): gyro-predicted roll = 0.51 + 0.5 = 1.01°. Fused estimate = 0.98 × 1.01 + 0.02 × 0.9 = 0.9898 + 0.018 = 1.0078°.
Step 3 (t = 0.3 s): gyro-predicted roll = 1.0078 + 0.5 = 1.5078°. Fused estimate = 0.98 × 1.5078 + 0.02 × 1.3 = 1.477644 + 0.026 = 1.5036°.
Notice the estimate tracks the gyro's integration almost exactly, nudged very slightly toward whatever the accelerometer says each step. That 2% correction looks negligible over three steps, but it is what keeps the estimate bounded over a long flight: the 0.5°/s bias, uncorrected, would add roughly 0.5° of error every second forever; the accelerometer's small but constant pull keeps yanking the estimate back toward the true gravity-referenced angle, so the drift saturates at a small steady-state offset instead of growing indefinitely. This is a first-order approximation of what a full Extended Kalman Filter (EKF) does with a formally derived, time-varying gain instead of a fixed alpha, but the mechanism, fast unreliable sensor plus slow reliable sensor equals a bounded, responsive estimate, is identical.
def complementary_filter(prev_roll_deg, gyro_rate_dps, accel_roll_deg, dt, alpha=0.98):
predicted = prev_roll_deg + gyro_rate_dps * dt
return alpha * predicted + (1 - alpha) * accel_roll_deg
roll = 0.0
dt = 0.1
alpha = 0.98
samples = [(5.0, 1.0), (5.0, 0.9), (5.0, 1.3)] # (gyro_rate_dps, accel_roll_deg)
for gyro_rate, accel_roll in samples:
roll = complementary_filter(roll, gyro_rate, accel_roll, dt, alpha)
print(round(roll, 4))
# 0.51
# 1.0078
# 1.5036
Real flight stacks extend this idea into an EKF that fuses gyro, accelerometer, magnetometer (for absolute yaw reference against magnetic north), barometer (for altitude, since GPS vertical accuracy is typically two to three times worse than horizontal), and GPS or RTK-GPS (for absolute position at 5-10 Hz, or up to 20 Hz for RTK) into a single state vector of position, velocity, attitude, and sensor biases, all updated on every new measurement using the actual statistical uncertainty of each sensor rather than a hand-picked constant like alpha.
Control: turning "where I should be" into motor commands
Once the drone knows its state, it needs to act on it. A quadrotor has exactly four actuators (motor speeds) but needs to control four independent things simultaneously: total thrust (altitude), roll, pitch, and yaw. Trying to compute "motor 1 should spin at exactly this RPM to achieve the desired trajectory" in one step is a hard, nonlinear, tightly coupled problem. Production autopilots instead use a cascaded control architecture: a stack of nested PID (Proportional-Integral-Derivative) loops, each one converting a higher-level error into a setpoint for the loop below it, with the innermost loop running fastest because it is closest to the physically unstable part of the system.
A PID controller computes its output as u = Kp·e + Ki·∫e dt + Kd·(de/dt), where e is the error between setpoint and current value. Kp reacts to the error right now, Ki eliminates steady-state error that persists over time (a constant wind pushing the drone off-station, for instance), and Kd damps the response by reacting to how fast the error is changing, preventing overshoot. The cascade, from outermost to innermost, is: position controller (position error → desired velocity, ~50 Hz, uses the EKF's position estimate, ultimately traceable to GPS/RTK) → velocity controller (velocity error → desired attitude, ~50 Hz) → attitude controller (attitude error → desired angular rate, ~250 Hz) → rate controller (angular rate error → torque command, ~1 kHz, uses the gyro almost directly since it is the fastest, least-filtered signal available). The rate loop runs fastest because an uncontrolled quadrotor is aerodynamically unstable on the order of tens of milliseconds; the outer loops can afford to be slower because position and velocity change relatively gradually.
Worked example: pitch correction and motor mixing
Take a drone in X-configuration (four motors: front-left FL, front-right FR, rear-left RL, rear-right RR) that has drifted to a pitch of +3° (nose up) with zero desired pitch, an angular rate of 0.5°/s (still rotating nose-up), and an accumulated integral error of -1.2 (already tracked by the controller from recent history). Using attitude-loop gains Kp = 4, Ki = 0.5, Kd = 1 (teaching-scale units, chosen so the output maps directly onto a 0-100 motor-command scale):
Error e = setpoint − current = 0 − 3 = −3°. Derivative term de/dt = −(pitch rate) = −0.5°/s, because as pitch keeps increasing, the error (0 − pitch) keeps decreasing.
τ_pitch = Kp·e + Ki·I + Kd·(de/dt) = 4×(−3) + 0.5×(−1.2) + 1×(−0.5) = −12 − 0.6 − 0.5 = −13.1
A negative pitch torque command means "pitch nose down," which is exactly the correction a +3° nose-up drone needs. To execute it, the motor mixer distributes τ_pitch across front and rear motor pairs: reducing front-motor thrust and increasing rear-motor thrust rotates the drone nose-down (Newton's second law for rotation: net torque equals moment of inertia times angular acceleration, produced here by the unequal front/rear thrust). With a base hover throttle of 50 (on a 0-100 scale) split evenly before correction:
def pid_pitch(error, integral, derivative, kp=4, ki=0.5, kd=1):
return kp * error + ki * integral + kd * derivative
tau = pid_pitch(error=-3, integral=-1.2, derivative=-0.5) # -13.1
base_throttle = 50
front_cmd = base_throttle + tau / 2 # FL, FR
rear_cmd = base_throttle - tau / 2 # RL, RR
print(tau, front_cmd, rear_cmd)
# -13.1 43.45 56.55
Front motors drop to 43.45 and rear motors rise to 56.55, on a scale where 100 is maximum thrust. This is a simplified linear mixing rule; a real mixing matrix also accounts for the moment arm of each motor and simultaneously blends in the roll and yaw torque commands and the throttle command from the outer loops, but the mechanism, more thrust on one side than the other produces a rotation, is exactly this.
Path planning: deciding where to go before deciding how to get there
Everything above assumes the drone already has a target position. Generating that target, especially around obstacles, is the path-planning layer, and it operates at a much lower update rate than the control loops (typically 1-10 Hz, since obstacles do not move as fast as the drone's own attitude). Two families dominate. Grid-based search (A*) discretises the flight volume into cells, marks cells occupied by known obstacles (buildings, trees, other drones in the formation) as blocked, and finds the lowest-cost path using an admissible heuristic, typically straight-line (Euclidean) distance to the goal, which never overestimates the true remaining cost and so guarantees the shortest path is found. This is the natural choice when the environment is known in advance and can be represented on a fixed grid, for example an agricultural spraying drone flying a pre-mapped field under India's Kisan Drone scheme, where crop rows and known obstacles like electricity poles are fixed before the flight starts.
When the space is high-dimensional or largely unknown, grid search becomes too expensive to run in real time, and sampling-based planners like RRT (Rapidly-exploring Random Tree) take over: instead of exploring every cell, RRT randomly samples points in free space and incrementally grows a tree of feasible, collision-free paths toward the goal, trading a solution guaranteed to be shortest for one that is found fast enough to matter. A warehouse or forest-canopy drone reacting to obstacles detected by an onboard depth camera in real time, where the map is not known until the drone is already flying through it, is the natural RRT case. Whichever planner runs, its output is a sequence of waypoints handed to the position controller at the top of the cascade described above, which is why a planning failure and a control failure look identical from the outside (the drone flies into something) but are fixed in completely different parts of the stack.
The diagram: the full closed loop
The misconception worth correcting explicitly
The most common wrong mental model a student brings to this topic is: "the drone has GPS, so it always knows exactly where it is, and navigation is just telling it coordinates to fly to." Three things are wrong with this at once. First, civilian GPS without augmentation is accurate to roughly 2-5 metres horizontally and typically two to three times worse vertically, nowhere near the centimetre precision a 1,000-drone formation show needs; that show is only possible because it uses RTK-GPS, where a fixed ground base station with a precisely surveyed position broadcasts correction signals that let each drone's receiver resolve its position to 1-2 cm. Second, GPS updates at only 5-10 Hz (RTK a bit faster), while the rate control loop keeping the drone from tumbling runs at roughly 1 kHz; if the flight controller only acted on GPS updates, the drone would be aerodynamically unstable between fixes. That gap is exactly why the IMU, running two orders of magnitude faster, and the EKF fusing it with GPS exist: the high-rate sensor keeps the drone stable moment to moment, and the low-rate absolute sensor keeps that fast estimate from drifting over the course of a flight. Third, GPS fails outright indoors, under dense tree canopy, or between tall buildings (signal multipath and blockage), which is precisely why indoor and close-obstacle drones lean on other absolute references, visual-inertial odometry from onboard cameras, LiDAR, or ultra-wideband beacons, fused through the same EKF architecture in place of, or alongside, GPS. Navigation is never one sensor; it is always an estimator reconciling several imperfect ones.
Active recall
Attempt each question before reading its answer.
- Using the complementary-filter example, if alpha were lowered from 0.98 to 0.90 (trusting the gyro less), recompute roll_est after Step 1 only (gyro = 5°/s, accel = 1.0°, dt = 0.1 s, roll_est(0) = 0°).
- In one or two sentences, explain why pushing alpha closer to 1.0 makes the filter more vulnerable to long-term gyro bias drift, even though it also reduces sensitivity to accelerometer noise.
- In the pitch-control worked example, if Kd is raised from 1 to 3 (more derivative damping) while error (-3°), integral (-1.2) and derivative (-0.5°/s) stay unchanged, recompute τ_pitch and the resulting front/rear motor commands (base throttle 50).
- If the drone's base throttle rises from 50 to 90 because of a heavier payload, recompute the front and rear motor commands using the original τ_pitch = -13.1. Which motor pair is now closer to the 100 saturation limit?
- A drone holding position outdoors flies briefly under a flyover and loses GPS lock for 1.5 seconds. Using the block diagram, name which loop(s) keep functioning normally during that gap and which loop becomes unreliable, and explain why the drone does not immediately destabilise.
- Explain why a 1,000-drone formation show uses RTK-GPS fused with IMU data rather than either sensor alone. Name one specific failure mode each sensor would produce by itself.
Answers
1. The gyro-predicted term is unaffected by alpha: predicted = 0 + 5×0.1 = 0.5°. With alpha = 0.90: roll_est = 0.90×0.5 + 0.10×1.0 = 0.45 + 0.10 = 0.55° (versus 0.51° at alpha = 0.98). Lower alpha pulls the estimate further toward the accelerometer's 1.0° reading.
2. As alpha approaches 1, the filter's output approaches pure gyro integration, and the accelerometer's corrective weight (1 - alpha) shrinks toward zero. A constant gyro bias then integrates almost unchecked, since only a vanishingly small fraction of each update pulls the estimate back toward the (unbiased, on average) accelerometer reading; the steady-state drift the bias settles at scales roughly with bias × dt / (1-alpha), so it grows as alpha → 1.
3. τ_pitch = 4×(-3) + 0.5×(-1.2) + 3×(-0.5) = -12 - 0.6 - 1.5 = -14.1. Front = 50 + (-14.1)/2 = 50 - 7.05 = 42.95. Rear = 50 - (-14.1)/2 = 50 + 7.05 = 57.05. More damping produces a slightly larger corrective torque here because the derivative term itself is more heavily weighted, widening the front/rear split.
4. With τ_pitch = -13.1 unchanged: Front = 90 + (-13.1)/2 = 90 - 6.55 = 83.45. Rear = 90 - (-13.1)/2 = 90 + 6.55 = 96.55. The rear motor pair (RL/RR) is far closer to the 100 saturation ceiling. This matters beyond arithmetic: a heavier payload eats into the headroom every control loop needs to actually execute its computed correction, so the same τ_pitch that easily corrected a lightly-loaded drone can saturate a motor on a heavily-loaded one, at which point the physical thrust differential falls short of what the controller asked for and the correction is weaker than the PID math assumes.
5. The attitude controller (D, ~250 Hz) and rate controller (E, ~1 kHz) keep running normally, because they depend on the gyroscope and accelerometer, not GPS. The position controller (B, ~50 Hz) becomes unreliable, because its input is the EKF's position estimate, which during the dropout falls back to dead-reckoning: integrating IMU-derived velocity forward in time without a GPS correction. Over 1.5 seconds this accumulates only a small, bounded position error (the IMU is accurate over short intervals, per the complementary-filter discussion), so the drone continues holding attitude and roughly holding position; it does not tumble, because the loops keeping it aerodynamically stable never depended on GPS in the first place.
6. GPS alone: standalone civilian GPS resolves position only to a few metres and updates at 5-10 Hz, which is both too coarse (drones in a tight formation would be unable to maintain safe separation) and too slow (no correction between fixes lets the drone's actual position wander before the next update arrives). IMU alone: without any absolute reference, gyro and accelerometer integration drift without bound over a multi-minute show, so each drone's estimated position would diverge further from its true position as the show goes on, eventually breaking formation even if it started perfectly synced. RTK-GPS supplies the missing centimetre-level absolute accuracy at a low rate; IMU supplies the missing high-rate responsiveness; the EKF fuses both so the drone is simultaneously precise and fast-reacting.
Think About It
Think about this: How would you explain drone navigation and control systems to a friend who has never seen a computer? What real-world analogy would you use? Imagine you had to build a system using these concepts — what would be your first step? Try this: before moving on, write down three things you learned and one question you still have.
Practice Exercises
Now it is time to practice! Complete these challenges to solidify your understanding:
- Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
- Exercise 2: Find a real-world example where drone navigation and control systems is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
- Exercise 3: Create a mind-map connecting drone navigation and control systems to at least 3 other topics you have studied.
Key Takeaways — Summary and Recap
Let us recap what we covered: the core ideas behind drone navigation and control systems, how they connect to real-world applications, and why they matter for your journey in computer science. Remember these key points as you move forward. For competitive exam preparation (CBSE, JEE, BITSAT), focus on understanding the WHY behind each concept, not just the WHAT.