Skip to the content
FixTheRobot Explore Robotics / UAV / Module 5 / M5-T16

UAV Systems Engineering · Module 5

M5-T16: Disturbance rejection and wind compensation

Wind is an unmeasured force. You can reject it with integrators, cancel it with an observer, or estimate it from the vehicle’s own motion.

  • Lesson 16 of 17
  • UAV Guidance, Navigation and Control (GNC)
  • Established engineering
  • About 7 minutes to read

A multirotor in wind is a controller with an unmodelled external force. Integral action eventually removes constant offsets, but gusts need faster action. A disturbance observer treats the force as an extra state and cancels it; the same idea in an EKF turns the vehicle into a crude anemometer.

Learning objectives

After this lesson, you should be able to:

  • Model wind as a constant plus gust disturbance entering the translational dynamics.
  • Compare integral action with a disturbance observer for rejection speed and noise sensitivity.
  • Estimate wind from airspeed-like quantities using a drag model and state the assumptions.
  • List what limits the wind speed in which a vehicle can hold position.

Conceptual explanation

Established Integral action and disturbance observers are standard control methods. Wind estimation from drag depends on a calibrated drag model for the specific vehicle: the coefficients below are illustrative, not measured values for any real aircraft.

Wind enters a multirotor mainly through aerodynamic drag, which depends on the velocity relative to the air, and through changes in rotor thrust. For small speeds a linear model is often used: the drag force is proportional to the relative velocity, so the vehicle in a steady wind ww experiences a force that tilts it into the wind and needs a steady lean to hold position.

Approaches to rejection, in order of complexity:

  • Integral action in the velocity or position loop removes steady offsets, at the cost of lag and windup risk.
  • Disturbance observer (DOB): estimate the lumped disturbance dd from the difference between the measured acceleration and the model-predicted acceleration, and subtract it in the command.
  • Wind estimation in the EKF: augment the state with the wind velocity and use the drag model so that the horizontal acceleration measured by the IMU makes the wind observable (PX4’s EKF2 can estimate wind this way and also uses airspeed if present; check the documentation for your version).
  • Robust or adaptive control (for example L1 adaptive control) which adapts the compensation online.
Disturbance rejection optionsThe disturbance (wind, payload shift, ground effect) acts on the plant. Integral action removes constant offsets slowly; a disturbance observer estimates it and cancels it faster; a feedforward from a wind estimate uses a model of the drag.Disturbancewind, payloadPlantvehicleEstimateobserver / EKFCompensatefeed-forwardResidualintegral actionEstimating then cancelling is faster than waiting for the integrator, but only as good as the estimate.
Where each technique sits. Faster compensation needs a better disturbance estimate.
Animation of three position controllers meeting a sudden constant wind force at five seconds. A proportional-derivative controller settles with a steady offset. Adding integral action removes the offset but only after a slow overshoot. A disturbance observer estimates the wind from the model mismatch and cancels it, giving a smaller peak and a quicker return to zero. Strips show position and the wind estimate.
Disturbance rejection: integral action accumulates the position error; a disturbance observer estimates the lumped force from v˙\dot{v} − uu and subtracts it. The observer is faster but relies on the model and amplifies noise with its bandwidth. Point mass with a 1.5 m/s21.5\,\mathrm{m}/\mathrm{s}^{2} step disturbance at t=5 st=5\,\mathrm{s}; PD, PD + II, PD + observer; computed. (Looping, about 6 seconds; drawn and computed for this course with illustrative values.)

Engineering intuition

Integral action is a person slowly leaning on a door until it stops moving: it works, but only after the door has already moved. A disturbance observer is a person who feels the push immediately and pushes back with the same force: faster, but if the person misjudges the push, the door still moves.

The limit is always physical. Holding position in wind ww requires tilting enough that the horizontal thrust component equals the drag. For a given drag coefficient the maximum tilt (set by thrust margin) fixes the maximum wind. No controller beats that; it can only avoid wasting margin. In gusts, remaining thrust margin is what lets the vehicle recover, so flying close to the thrust limit in strong wind is the dangerous regime.

Mathematical formulation

Translational dynamics with a lumped disturbance acceleration dd (including wind-induced drag): p¨=u+d\ddot{p}=u+d, where uu is the commanded acceleration from the controller. A disturbance observer with gain LL (first-order) estimates it as:

First-order disturbance observer
d^˙=L((v˙−u)−d^)or equivalentlyd^˙=L(v˙meas−u−d^)\dot{\hat d} = L\left((\dot v - u) - \hat d\right) \quad\text{or equivalently}\quad \dot{\hat d} = L\left(\dot v_{\text{meas}} - u - \hat d\right)
Command with the estimate subtracted
u=unominal−d^u = u_{\text{nominal}} - \hat d

In practice v˙\dot{v} is not measured directly; the equivalent form uses an auxiliary variable z=d^−L vz=\hat{d}-L\,v: z˙=−L(z+L v+u)\dot{z}=-L(z+L\,v+u), d^=z+L v\hat{d}=z+L\,v, which needs only vv and uu. The error of the estimate obeys e˙d=−L ed+d˙\dot{e}_{d}=-L\,e_{d}+\dot{d}, so a constant disturbance is estimated with time constant 1/L and a ramp with a steady error ḋ/L: a larger LL gives a faster estimate and more noise gain.

With a linear drag model Fdrag=−kd(v−w)F_{\text{drag}}=-k_{d}(v-w) (per unit mass, kdk_{d} in 1/s), holding position (v=0)(v=0) in wind ww needs a horizontal acceleration kd wk_{d}\,w, so the lean angle is θ=arctan⁡(kd w/g)\theta =\arctan (k_{d}\,w/g) for small vertical acceleration. The maximum holdable wind for a tilt limit θmax⁡\theta _{\max} is

Maximum holdable wind (linear drag)
wmax⁡=gtan⁡θmax⁡kdw_{\max} = \frac{g\tan\theta_{\max}}{k_d}

For example with an illustrative kd=0.5 s−1k_{d}=0.5\,\mathrm{s}^{-1} and θmax⁡=25∘\theta _{\max}=25^{\circ}, wmax⁡=9.81×0.466/0.5=9.1 m/sw_{\max}=9.81\times 0.466/0.5=9.1\,\mathrm{m}/\mathrm{s}: a vehicle-specific measurement is required to know the real value.

dd
lumped disturbance acceleration (m/s2)(m/s^{2}).
LL
observer bandwidth (1/s).
kdk_{d}
linear drag coefficient per unit mass (1/s).
ww
wind velocity (m/s).

Architecture and data flow

IMU and position/velocity estimate → disturbance observer or EKF wind states → feed-forward added to the commanded acceleration → position controller. With an airspeed sensor, the relative airspeed directly supplies w=v−vairw=v-v_{\text{air}}, which makes the estimate faster and observable in steady flight. Alongside, a monitor checks the lean angle and thrust margin against the vehicle’s wind limit and triggers return or landing when the margin is exhausted.

Real-world UAV applications

  • Position hold and precision landing in wind.
  • Inspection close to structures where wind is turbulent.
  • Ship deck landing with gusts and air-wake.
  • Estimating wind for meteorological data or for planning energy use.

Implementation example

This runs as shown. A point mass with a PD position controller faces a constant acceleration disturbance of 1.5 m/s21.5\,\mathrm{m}/\mathrm{s}^{2} that switches on at t=5 st=5\,\mathrm{s}. The test compares: PD only (steady offset), PD with integral action (slow recovery), and PD with a disturbance observer (fast recovery), and confirms the ordering of the peak and settling errors. It also reproduces the maximum holdable wind arithmetic.

import numpy as np

def run(mode, dt=0.002, T=20.0, Kp=4.0, Kd=3.5, Ki=2.5, L=8.0, dist=1.5):
    p = v = I = z = 0.0; peak = 0.0; late = []
    for k in range(int(T / dt)):
        t = k * dt; d = dist if t >= 5.0 else 0.0
        dhat = z + L * v if mode == 'dob' else 0.0
        u = -Kp * p - Kd * v - (I if mode == 'int' else 0.0) - dhat
        if mode == 'int': I += Ki * p * dt
        if mode == 'dob': z += -L * (z + L * v + u) * dt           # observer: dhat = z + L v, estimate of the disturbance acceleration
        v += (u + d) * dt; p += v * dt
        if t >= 5.0: peak = max(peak, abs(p))
        if t >= 15.0: late.append(abs(p))
    return peak, np.mean(late)
res = {m: run(m) for m in ('pd', 'int', 'dob')}
for m, (pk, ss) in res.items(): print(f"{m:>3}: peak {pk:.3f} m, error at 15-20 s {ss:.4f} m")
assert res['pd'][1] > 0.3 and res['int'][1] < 0.01 and res['dob'][1] < 0.01 and res['dob'][0] < res['int'][0] < res['pd'][0] + 1e-9
g, kd, th = 9.81, 0.5, np.radians(25); print(f"w_max = {g * np.tan(th) / kd:.1f} m/s (illustrative k_d)")
assert abs(g * np.tan(th) / kd - 9.15) < 0.1
PD alone leaves a steady offset; integral action removes it slowly; a disturbance observer removes it faster with a smaller peak.

Common engineering mistakes

Integral action with no anti-windup

Windup in saturation produces large overshoot after a gust.

Observer bandwidth too high

Noise on the velocity estimate is amplified into the command.

Using a drag model from another vehicle

The wind estimate is biased by the wrong coefficient.

No margin check

In strong wind the thrust margin vanishes and recovery from a gust is impossible.

Treating gusts as constants

A gust has dynamics faster than the integrator; the integrator lags and the DOB bandwidth must be chosen accordingly.

Failure modes

Failure modes, symptoms and causes
Failure modeHow it shows upLikely cause
Vehicle drifts downwindGradual offset in position holdNo integral action or too weak; wind beyond the lean limit
Oscillation after a gustOvershoot and ringingIntegrator windup or an over-aggressive observer
Bad wind estimateEstimate wanders or is biasedWrong drag model, poor excitation, or vibration in the accelerometer
Loss of altitude in a gustSudden sinkThrust saturated by the combined lean and gust demand

Debugging approach

  1. Plot the commanded lean angle and the estimated wind against time and compare with a reference anemometer.
  2. Check the thrust margin and saturation flags.
  3. Replay a recorded gust through the controller in simulation.
  4. Test the response to a step disturbance (tethered pull or simulated wind) and measure the recovery time.

Practical exercises

  1. Sweep the observer bandwidth LL from 1 to 40 and plot the peak error and the sensitivity to velocity noise (add 0.05 m/s noise).
  2. Replace the constant disturbance with a 1 Hz sinusoid and compare the three controllers.
  3. Compute the maximum holdable wind for kd=0.3 s−1k_{d}=0.3\,\mathrm{s}^{-1} and 20∘20^{\circ} tilt.
  4. Add actuator saturation and anti-windup to the integrator.

Interview questions

Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.

Question 1

Compare integral action with a disturbance observer.

Model answer

Integral action removes constant offsets slowly and risks windup; a disturbance observer estimates the disturbance from model mismatch and cancels it quickly, but its noise gain grows with bandwidth and it relies on the model.

Question 2

How can a multirotor estimate wind?

Model answer

By modelling drag as a function of velocity relative to the air and augmenting the EKF with wind states, so that the measured acceleration and the vehicle’s motion make wind observable (airspeed measurements make it more direct).

Question 3

What limits the wind in which a vehicle can hold position?

Model answer

The lean angle needed to balance drag against the tilt and thrust margin available. When the margin is exhausted the vehicle drifts and cannot recover from gusts.

References and further reading

Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.

What’s next

Mark this lesson

Saved in this browser and synced to your account when you are signed in.

Practice this lesson

M5-L5: Simulate wind disturbances

Apply a wind force and measure the recovery.

Next lesson

M5-T17: 3-D path planning on voxel maps

Plan collision-free paths in a 3-D voxel map with 26-connected A*, choose the resolution and obstacle inflation, and shorten the path for the trajectory generator.