Introduction to Robot Learning · Lecture 12 of 25 · CMU 16-831

Model-Based Control Basics

You know the physics — gravity, mass, the equations of motion. So how do you compute the control that holds a system exactly where you want it? The answer is a feedback loop, and the optimal one turns out to be a single matrix multiplied by the state.

Prerequisites: basic vectors & matrices + the idea of a dynamics model from Lecture 1 + a little Python. No control theory assumed.
10
Chapters
5
Simulations
3
Code Labs

Chapter 0: You Know the Physics. Now What?

The last few lectures were about robots that don't know their world — they learn from trial and error, paying in samples and crashes. This lecture takes the opposite starting point, the one classical engineering has lived in for a century: you already have a good model of the dynamics. You know the mass, you know gravity, you can write down how the state evolves.

That is not a fantasy. The instructor lists where it happens: games with known rules, anything you can derive from first-principles rigid-body physics, robot simulators, and systems where you fit the unknown parameters of a known model (system identification). When you know the model, things get dramatically easier. Apollo flew people to the Moon on it. Boston Dynamics' Atlas does backflips on it. No neural network in sight.

So here is the question this entire lecture answers. A quadrotor is hovering. A gust shoves it sideways. What thrust command do you send, right now, as a function of where the drone is, to bring it back? You are not asking "what's the best move in some abstract game." You are asking for a control law — a rule u = π(x) that maps the current state x into the action u to apply this instant.

The one shift in mindset. Reinforcement learning maximizes a reward by sampling an unknown world. Model-based control instead uses the known dynamics to design a feedback policy by hand — or, for the optimal version, by solving a small matrix equation. The recipe is two steps: (1) get the dynamics model, (2) figure out how to choose actions. Today is all of step 2, given step 1.

And the punchline, the thing that should feel surprising by the end of this lesson: for a linear system with a quadratic cost, the optimal controller — the very best possible policy — is not a deep network. It is a single gain matrix K, and the action is just u = −Kx. Multiply the state by a matrix, negate it, send it. That's the Linear-Quadratic Regulator, and we'll build up to why the optimum is that simple.

Let's start by watching a controller hold a point. Below, a cart is being pushed back toward a target by a feedback law. Crank the disturbance and watch it fight back — or turn the controller off and watch it drift away forever.

A feedback controller holding a target — and what happens without it

The cart should sit on the dashed target. A feedback law pushes it back whenever it drifts. Slide the disturbance to keep shoving it. Uncheck feedback on to remove the controller — now nothing pulls it home.

Disturbance 0.40
Ready.

With feedback on, the cart settles near the target no matter how hard you push — it measures its error and corrects. With feedback off, the same push sends it wandering, because nothing watches the result. That difference is the entire subject of this lecture: how to design the rule that does the correcting, and how to prove it actually brings the system home.

In this lecture's setting, what distinguishes model-based control from the model-free reinforcement learning of earlier lectures?

Chapter 1: The State-Space Model — How the World Evolves

Before we can control a system we need a precise way to say how it moves. Control theory writes every system in one of two near-identical forms, and the whole lecture lives in them.

The state x is a vector that captures everything you need to know about the system right now — for a cart, its position and velocity; for a drone, position, velocity, angle, and angular rate. The control input u is what you get to choose — a thrust, a torque, a wheel speed. The dynamics f says how the state changes given the current state and your input.

continuous time:   ẋ = f(x, u)      discrete time:   xt+1 = f(xt, ut)

The dot in ẋ means rate of change — how fast the state is moving this instant. The continuous form says "the velocity of the state is some function of state and input." The discrete form says "next step's state is some function of this step's state and input." They describe the same idea; the discrete one is what a computer actually iterates, and the continuous one (the instructor's choice for today) makes stability easiest to define because the physical world is continuous.

The data flow, made concrete. Picture the loop running 50 times a second. In: the current state x (say a 4-vector for a 2-D drone). Through: your policy u = π(x) turns that 4-vector into a 2-vector of commands (thrust, torque). Through: the dynamics f integrate those commands forward by one tiny time step. Out: a new state x, which feeds straight back in. Control is this ring spinning, with f fixed by physics and π the thing you design.

The simplest possible dynamics — the integrators

Two toy systems carry most of the intuition, so meet them now.

The single integrator is ẋ = u: whatever you command is the velocity of the state. Push right, it slides right; release, it stops instantly. Think of a frictionless puck where your input is its speed.

The double integrator is ẍ = u (two dots = acceleration): your input is the acceleration, not the velocity. This is Newton's law for a unit mass — force equals acceleration. It is the honest model of a cart, a drone axis, a robot joint. The subtlety, which Chapter 4 will make vivid, is that commanding acceleration is much harder to stabilize than commanding velocity: you can't stop on a dime, because momentum carries you past the target.

Linear systems — the form we can actually solve

When f is linear, the model collapses to two matrices:

ẋ = A x + B u

Here A is the n×n matrix describing how the state evolves on its own (the open-loop, uncontrolled physics), and B is the n×m matrix describing how your input pushes the state. The double integrator written this way uses x = [position; velocity]: position's rate is velocity, velocity's rate is the input. So A moves position from velocity, and B injects u into velocity. Almost no real robot is exactly linear — but Chapter 9 shows you can linearize a nonlinear system around an operating point and get an A and B that are accurate nearby. Linear systems are where the clean theory lives, so we earn the right to use it.

Single vs. double integrator — command velocity, or command acceleration?

A pulse of input u is applied for a moment. Watch how the state x responds. The single integrator (input = velocity) jumps and holds. The double integrator (input = acceleration) keeps drifting after the input ends — momentum. Toggle which one you're driving.

Single integrator: input sets velocity directly.
In the linear model ẋ = A x + B u, what do A and B represent?

Chapter 2: Feedback — Closing the Loop

We have the dynamics. Now the goal. The instructor lists what a feedback policy might be asked to do: stabilize the system to a reference point, track a moving trajectory, minimize a cost (this is where RL was born), be adaptive to uncertainty, and be robust to disturbance. Today's spine is the first one — hold a target — because everything else is built on it.

A feedback policy is a rule u = π(x): you look at the current state and decide the input from it. Plug it into the dynamics and you get the closed-loop system, the system with the controller wired in:

ẋ = f(x, π(x)) = fcl(x)

The notation fcl emphasizes the point: once the policy is fixed, there is no input left to choose — the state evolves all on its own according to a new, controller-shaped law. Designing a controller is choosing π so that this closed-loop law behaves the way you want.

The proportional controller — push harder the farther you are

The simplest useful policy is the proportional (P) controller: the input is proportional to the error, pushing back toward the reference. For the single integrator ẋ = u, with target 0, take u = −kx:

ẋ = −k x

Read this. If x is positive (we're to the right of the target), the input is negative (push left); the bigger the error, the harder the push. The constant k > 0 is the gain — a single dial for how aggressively the controller reacts. The solution of this equation is a decaying exponential, x(t) = e−kt x(0): the error melts away to zero, faster for larger k. We just turned a system that did nothing (u = 0 leaves it frozen wherever it started) into one that homes in on the target.

Why feedback, not a precomputed plan? An open-loop plan computes the whole input sequence once and executes it blindly. Feedback re-reads the state every instant and reacts. If the world is perfectly known and never disturbed, the two are identical. Add one gust of wind — one mismatch between your model and reality — and only feedback recovers, because only feedback looks at the consequence of its own action. The gain k is the strength of that looking.

Open-loop trajectory optimization vs. closed-loop policy

The instructor draws this distinction explicitly. Open-loop trajectory optimization (planning) solves for a whole sequence of states and inputs ahead of time — great for "what path should I take," useless on its own against surprises. Closed-loop policy optimization finds the rule u = π(x) that reacts. Real systems use both: plan a trajectory, then wrap a feedback controller around it to hug that trajectory despite disturbances. We'll see exactly that in Chapter 6.

The proportional gain k — how hard should the controller push?

Single integrator with a P controller u = −kx, starting away from the target. Slide the gain. Small k crawls home; large k snaps home. Watch the error curve x(t) = e−ktx(0) get steeper as k grows.

Gain k0.80
Larger k = faster decay toward the target.
For the single integrator ẋ = u with target 0, the proportional law u = −kx gives closed-loop dynamics ẋ = −kx. Why does this drive the error to zero?

Chapter 3: PID — Proportional, Derivative, Integral

The P controller is enough for the single integrator, but it falls apart on the double integrator — the honest model of a real cart or drone axis. Here is why, and here is the fix, term by term. By the end you'll understand the most widely deployed controller on Earth: PID.

P alone isn't enough — the double integrator

Take ẍ = u, target 0, and apply pure proportional, u = −x. The closed-loop law is ẍ = −x, whose solution is x(t) = x(0) cos(t) + ẋ(0) sin(t) — a sine wave that never decays. The controller keeps pushing back toward the target, the mass keeps overshooting through it (momentum!), and you get an undying oscillation. Stable, technically, but useless: it never settles.

The missing ingredient is damping. A pure spring (which is what u = −x makes) oscillates forever because nothing removes energy. Real systems settle because friction bleeds energy away. To make the controller settle, we add a term that opposes velocity — an artificial friction. That term is the derivative.

Add D — the derivative term (damping)

The derivative controller adds a term proportional to how fast the error is changing. For the double integrator: u = −x − 2ẋ. The closed-loop law becomes ẍ = −x − 2ẋ, which now decays — the solution is x(t) = (x(0) + (x(0)+ẋ(0))t)e−t, sliding smoothly to zero. The −2ẋ term is a brake: when the cart is racing toward the target, D pushes against the motion, dissipating the energy that would have caused overshoot. P + D together is the PD controller, the workhorse of robot joint control.

u = −Kp x − Kd ẋ     (PD: P stiffness + D damping)

Read the two gains as physical dials. Kp is stiffness — how hard the controller pulls toward the target (a stronger spring). Kd is damping — how hard it resists motion (a stronger shock absorber). Too little Kd and you overshoot and ring; too much and you crawl home sluggishly. There is a sweet spot, and you'll find it in the widget below.

Add I — the integral term (kill the steady offset)

One problem remains. Suppose a constant disturbance d shoves the system — a steady wind, a payload, gravity on a tilted arm. A P or PD controller leaves a steady-state offset: it settles, but slightly off-target, because at the offset the spring force exactly balances the disturbance and the error stops shrinking. The fix is the integral controller: accumulate the error over time and feed it back.

u = −Kp x − Kd ẋ − Ki ∫ x dt

The integral term has a beautiful logic: as long as any error persists, the integral keeps growing, so the input keeps ramping — until the error is driven to exactly zero. The instructor shows the disturbed single integrator with u = −2x − ∫x: differentiate both sides and you get ẍ = −2ẋ − x, which is exponentially stable and drives the error to zero despite the constant disturbance. Integral control, he notes, is the simplest form of adaptive control — it silently learns the constant push and cancels it.

PID in one breath. P reacts to the error you have now (stiffness). D reacts to how fast the error is changing (damping — kills overshoot). I reacts to the error you've accumulated (kills steady offset from constant disturbances). Three terms, three gains, and you can tune almost any single-axis system. This is why PID runs your thermostat, your car's cruise control, and most industrial robots.

A PID step by hand

Let's compute one control step with real numbers so the formula stops being abstract. Discrete double integrator, target 0, gains Kp = 1.0, Kd = 2.0, Ki = 0.1, time step Δt = 0.1. Suppose right now the position is x = 0.5, the velocity is ẋ = −0.3 (already moving back toward target), and the accumulated error integral so far is I = 0.8.

The control output is the weighted sum:

u = −(1.0)(0.5) − (2.0)(−0.3) − (0.1)(0.8)
u = −0.5 + 0.6 − 0.08 = +0.02

Notice what each term said. P wanted to push left (−0.5) because we're to the right of target. D pushed right (+0.6) because we're already moving left fast — D is saying "ease off the brake, you'll overshoot." I added a small left nudge (−0.08) from the leftover accumulated error. The three negotiate, and the net command is a gentle +0.02. Then the integral updates: I ← I + x·Δt = 0.8 + 0.5·0.1 = 0.85, ready for the next step. That single line, run 50 times a second, is a PID controller.

Tune a PID cart — watch overshoot, oscillation, and settling

A double-integrator cart starts left of the dashed target and a constant wind blows it right. Tune the three gains and press Run. Kp = stiffness, Kd = damping (raise it to kill ringing), Ki = integral (raise it to erase the steady offset from the wind). The trace shows position over time.

Kp (stiffness)2.0
Kd (damping)0.5
Ki (integral)0.00
Try K_d = 0 first (rings), then raise it.

Three experiments worth running: (1) set Kd = 0 and watch it oscillate — no damping. (2) Raise Kd and the ringing dies. (3) With Ki = 0 and wind on, notice it settles below the target — the steady offset. Now raise Ki and watch the trace creep back up to exactly the target. You just saw all three terms earn their letters.

Let's build it in code — the full PID loop — and prove that adding the integral term is what finally erases the offset.

A PD controller settles a cart slightly below a target when a constant wind pushes it. Which term fixes this, and why?

Chapter 4: Stability — Does It Actually Come Home?

We've been tuning controllers by eye. But "looks like it settles" is not engineering. Control theory's job, the instructor says, is to rigorously define and analyze what we mean by a good controller. The most basic property of all is stability: if you perturb the system, does it come back?

There are three flavors, and they form a ladder of increasing strength.

TypePlain meaningPicture
StableStart near the equilibrium, stay near it. Small nudge → bounded response, never blows up. But it need not converge.A frictionless pendulum nudged slightly: swings forever within a small arc.
Asymptotically stableStable and it converges back to the equilibrium eventually.The same pendulum with a little friction: swings die out, returns to rest.
Exponentially stableAsymptotically stable and the convergence is exponentially fast — bounded by α·|error|·e−λt.Heavily damped: snaps back fast, error shrinks like e−λt.

The formal definitions are about ε and δ: a solution is stable if for every error tolerance ε you pick, there's a starting-distance δ small enough that staying within δ at the start keeps you within ε forever. Asymptotically stable adds that the gap eventually goes to zero. Exponentially stable adds that it goes to zero at least as fast as a decaying exponential. The instructor notes a clean fact: for linear systems, asymptotic and exponential stability are the same thing. So for the linear systems we care about, "converges" already means "converges fast."

The three integrator examples, side by side. Single integrator ẋ = u: u = 0 gives ẋ = 0, merely stable (frozen wherever it started); u = −kx gives ẋ = −kx, exponentially stable. Double integrator ẍ = u: u = 0 is unstable (a tiny velocity sends it off to infinity, x(t) = εt); u = −x is only stable (the undamped oscillation); u = −x − 2ẋ (the PD law) is exponentially stable. The derivative term is precisely what climbs from "stable" to "exponentially stable."

Lyapunov's idea — stability without solving the ODE

For a high-dimensional system you can't just solve the differential equation and stare at it. Lyapunov gave a way to prove stability without solving anything. The trick: find an energy-like function V(x) that is positive everywhere except zero at the equilibrium, and show that it always decreases along the system's motion. If the energy can only go down and is bounded below by zero, the system must drain to the bottom — the equilibrium.

V̇ ≤ 0 ⇒ stable   ·   V̇ < 0 ⇒ asymptotically stable   ·   V̇ ≤ −αV ⇒ exponentially stable

The instructor's example makes it concrete. Take the single integrator ẋ = −Kx with the energy V(x) = ½ xTx (squared distance from the target). Its rate of change along the motion is V̇ = xTẋ = −xTKx. If K is positive definite, this is strictly negative whenever x ≠ 0 — in fact V̇ ≤ −2λmin(K)·V, which is the exponential-stability condition. So the system is exponentially stable whenever the gain K is positive definite, proven without ever solving the ODE. That is the power of the energy argument: it scales to any dimension.

The three flavors of stability — perturb and watch

Each curve is a perturbed system released from the same nudge. Unstable runs away. Stable (only) oscillates within a band but never settles. Asymptotically stable drifts home. Exponentially stable snaps home. Slide the damping to morph between them.

Damping0.60
Positive damping = exponentially stable; zero = oscillates; negative = blows up.
A perturbed system oscillates forever within a small band but never converges back to the equilibrium. Which stability property does it have?

Chapter 5: Eigenvalues — Reading Stability Off the Matrix

For linear systems, stability is not something you have to simulate or guess. It is written, exactly, in the eigenvalues of the closed-loop matrix. This is the single most useful test in linear control, and it's a one-line check.

Wire a linear feedback law u = −Kx into the linear system ẋ = Ax + Bu. The closed loop becomes:

ẋ = (A − BK) x = Acl x

where K is the gain matrix (an m×n matrix) and Acl = A − BK is the closed-loop matrix. The solution of ẋ = Aclx is governed by the eigenvalues of Acl — each mode of the system decays or grows like eλt where λ is an eigenvalue. So:

The eigenvalue stability test (continuous time). The closed-loop system ẋ = Aclx is exponentially stable if and only if every eigenvalue of Acl has a strictly negative real part — they all sit in the left half of the complex plane. Such a matrix is called Hurwitz. If any eigenvalue has positive real part, that mode blows up — unstable. If the worst eigenvalue sits exactly on the imaginary axis (real part 0), you get marginal stability — the undamped oscillation. Designing K is choosing where to place these eigenvalues.

Why the real part? Write an eigenvalue as λ = σ + iω. Then eλt = eσt(cosωt + i sinωt). The real part σ sets the envelope: σ < 0 means a shrinking exponential (decay), σ > 0 means a growing one (blow-up), σ = 0 means constant amplitude (eternal oscillation). The imaginary part ω just sets how fast it oscillates inside that envelope. So the sign of the real part is stability. The more negative, the faster it decays — that's the exponential rate λ from Chapter 4.

A stability check by hand

Take the double integrator with a PD controller and verify it's stable through eigenvalues alone. State x = [position p; velocity v]. The open-loop matrices are A = [[0, 1], [0, 0]] (position's rate is velocity; velocity's rate is zero on its own) and B = [[0], [1]] (input is acceleration). The PD law u = −Kpp − Kdv means K = [Kp, Kd]. The closed-loop matrix:

Acl = A − BK = [[0, 1], [−Kp, −Kd]]

Its eigenvalues solve the characteristic equation det(Acl − λI) = 0, which works out to λ2 + Kdλ + Kp = 0. Plug in Kp = 1, Kd = 2 (the instructor's PD example): λ2 + 2λ + 1 = 0, so (λ + 1)2 = 0, giving a repeated eigenvalue at λ = −1. Both eigenvalues have real part −1 < 0 — Hurwitz — so the closed loop is exponentially stable, decaying like e−t. That matches exactly the ODE solution from Chapter 3. Now set Kd = 0: λ2 + 1 = 0 gives λ = ±i, real part 0 — the eternal oscillation. The eigenvalues told us everything without solving a single trajectory.

Eigenvalue placement — drag the gains, watch the poles move

The complex plane. The shaded left half is the stable region (negative real part). The two dots are the eigenvalues of the closed-loop double integrator A−BK for the current PD gains. Slide Kp, Kd: push the poles deep-left for fast stable response; drop Kd to 0 and watch them slide onto the imaginary axis (marginal); the status line reports stable / marginal / unstable.

Kp1.0
Kd2.0
Both poles in the left half-plane: exponentially stable.

Note the discrete-time twist, since real controllers run in discrete time: for xt+1 = Aclxt, the stable region is not the left half-plane but the unit circle — every eigenvalue must have magnitude (spectral radius) strictly less than 1, so each mode λt shrinks. Same idea, different boundary. We'll use exactly this test in the eigenvalue code lab.

Let's verify the closed-loop stability test directly from the matrices.

For a continuous-time closed loop ẋ = Aclx, what condition on the eigenvalues of Acl guarantees exponential stability?

Chapter 6: Disturbance, Robustness, and Tracking

Real systems don't match your model exactly. There's a gust, a payload, an unmodeled friction. The instructor frames the uncertainty hierarchy crisply: robust control handles a disturbance that is "wrong and not learnable" (you just need to survive it), and adaptive control handles one that is "wrong but learnable" (you can estimate and cancel it). Let's see why a good controller is naturally robust, and how to track a moving target.

Why exponential stability buys you robustness

Add a disturbance d to the model: ẋ = f(x, u) + d. The goal of robust control is input-to-state stability (ISS) — not necessarily converging to exactly zero, but staying within an error ball whose size is proportional to the disturbance. The instructor's example nails it: the disturbed single integrator ẋ = −kx + d settles to a steady error of d/k. Bigger gain k → smaller residual error. The system doesn't blow up; it just sits a little off, by an amount you can shrink.

The deep reason exponential stability matters. It implies robustness. A merely-stable system can be knocked arbitrarily far by a persistent disturbance; an exponentially stable one always pulls back hard enough that the disturbance only buys a bounded, proportional offset (ISS). This is why we don't settle for "stable" — we want the exponential decay, because it's what guarantees graceful behavior when (not if) the model is wrong.

And to eliminate a constant disturbance entirely, you already know the trick from Chapter 3: integral control. The instructor calls it the simplest adaptive controller — it silently estimates the constant push and cancels it. More sophisticated adaptive control (MRAC, L1 adaptive, the Neural-Fly work) estimates richer, time-varying disturbances, but the integral term is the seed of the whole idea.

Tracking a trajectory — add a feedforward term

So far the target was a fixed point. Often we want to track a moving reference xd(t) — follow a path, not just hold still. The instructor's tracking controller for the double integrator ẍ = u is:

u = −Kp(x − xd) − Kd(ẋ − ẋd) + ẍd

The first two terms are PD on the tracking error e = x − xd. The last term, ẍd, is the feedforward: the acceleration the desired trajectory itself demands. Why include it? Define the error e = x − xd and substitute — the feedforward exactly cancels the ẍd that appears, leaving clean error dynamics:

ë + Kdė + Kpe = 0

This is just the stable PD equation from Chapter 5, now governing the error rather than the position. The feedforward does the "predictable" work of following the trajectory; the feedback only has to mop up the deviations. Without it, the feedback would always lag, constantly chasing a target it can't anticipate. For a fixed setpoint, ẋd and ẍd are zero and it collapses back to plain PD. Feedforward + feedback is the standard pattern: plan the path (open-loop), wrap feedback around it (closed-loop), exactly the split from Chapter 2.

Robustness vs. tracking — a controller chasing a moving target under wind

The desired trajectory is a moving sine. The cart tracks it with PD + feedforward, while a wind disturbance pushes it. Slide the wind up: the cart stays close (robust). Toggle feedforward off and watch the cart lag behind the moving target.

Wind0.40
Tracking a moving target.
In the tracking controller u = −Kp(x−xd) − Kd(ẋ−ẋd) + ẍd, what is the role of the feedforward term ẍd?

Chapter 7: LQR — The Optimal Linear Controller

PID gains we tuned by hand and by eye. But "which gains are best?" is itself a question with a clean answer. The instructor's bullet from Lecture 1 returns: minimize a cost — this is where RL started. Set up the right cost over a linear system and the optimal controller drops out in closed form. This is the Linear-Quadratic Regulator (LQR), and it is the centerpiece of the whole lecture.

The cost — state error versus control effort

LQR asks: drive the state to zero while not spending too much control. It writes that trade-off as a quadratic cost integrated over time:

J = ∫0 ( xTQ x + uTR u ) dt

Two terms, two penalties. xTQ x penalizes the state for being away from zero — the bigger the error, the bigger the cost; Q (positive semidefinite) weights which states you care about. uTR u penalizes the control effort — how much "gas" you burn; R (positive definite) weights how expensive your actuators are. The entire art of LQR is the ratio Q/R.

The Q-vs-R trade-off, in plain words. Crank Q up (relative to R): the controller treats state error as expensive, so it slams the actuators to snap home fast — aggressive, large control, fast response. Crank R up: control is expensive, so the controller is gentle and patient — small, smooth inputs, slow response. There is no free lunch: you cannot have a fast response and tiny control effort. Q/R is the dial between them, and LQR computes the provably optimal gain for whatever ratio you pick.

The answer is a single gain matrix

Here is the surprise that the whole lecture has been building toward. For the linear system ẋ = Ax + Bu with this quadratic cost, the optimal policy is linear state feedback — u = −Kx — the very form we've been using all along. The best possible controller, out of all possible controllers, is just a matrix times the state:

u = −K* x      K* = R−1BTP

where P is a positive-definite matrix that solves the Algebraic Riccati Equation (ARE):

ATP + P A + Q = P B R−1 BT P

You do not solve this by hand — you call an LQR routine in Python or MATLAB, the instructor stresses. But understand what it gives you. The matrix P is, in a precise sense, the optimal cost-to-go: xTPx is the minimum remaining cost from state x — the value function from your RL lectures, now for a continuous linear system. The gain K* reads that value off and turns it into the cheapest action. And here is the kicker:

LQR is optimal AND stable. Under mild assumptions on A, B, Q, R, one can prove the closed-loop matrix A − BK* is Hurwitz — all eigenvalues in the left half-plane (Chapter 5). So the LQR controller doesn't just minimize the cost; it is guaranteed exponentially stable for free. You get optimality and stability in one matrix. That is why LQR, derived in the 1960s for Apollo, is still the default linear controller everywhere.

Where does this closed form come from? The instructor names two classical routes: dynamic programming (the Hamilton-Jacobi-Bellman equation — the continuous-time cousin of the value iteration you saw in Lecture 7) and calculus of variations (Pontryagin's maximum principle). Both land on the same Riccati equation. Next lecture derives the discrete-time version step by step; today we just need to see the structure and feel the trade-off. The lab below makes that trade-off something you can play with.

The LQR Q-vs-R trade-off — reshape the response with one slider

A double-integrator cart, perturbed off target, controlled by the LQR-optimal gain for the current Q/R ratio. Slide toward cheap control (large R): slow, gentle, small input. Slide toward expensive error (large Q): fast, aggressive, large input. The position and control effort traces both respond.

Q/R ratio2.0
Balanced: moderate speed, moderate effort.
In LQR with cost ∫(xTQx + uTRu)dt, what happens to the optimal controller as you increase R relative to Q?

Chapter 8: Discrete LQR by Hand — The Riccati Recursion

The continuous Riccati equation is solved by a library call. But the finite-horizon discrete version — the one the next lecture derives and the one you'd actually code for model-based RL — is solved by a beautiful backward recursion, and it is small enough to run by hand. Doing so reveals exactly where the gain comes from: it's dynamic programming, run backward in time, exactly like value iteration.

The setup: discrete linear system xt+1 = A xt + B ut, and a cost summed over a finite horizon of N steps, with a terminal penalty:

J = xNTQfxN + ∑t=0N−1 ( xtTQ xt + utTR ut )

The cost-to-go from any state turns out to be quadratic, Vt(x) = xTPtx, and the matrices Pt are computed backward from the end. Start at the terminal cost, PN = Qf, then sweep backward. At each step the optimal gain and the next P are:

Kt = (R + BTPt+1B)−1 BTPt+1A
Pt = Q + ATPt+1A − ATPt+1B (R + BTPt+1B)−1 BTPt+1A

This is the backward Riccati recursion. Read it as one step of dynamic programming: given the cost-to-go from the next state (Pt+1), find the action that minimizes "cost now + cost-to-go from where that action lands you." The minimization is over a quadratic, so it has a closed form — that's where the matrix inverse comes from. The result is both the optimal gain Kt for this step and the updated cost-to-go Pt. Sweep all the way back to t = 0 and you have a gain for every step.

One Riccati step with real numbers

Let's do the cleanest possible scalar example so every operation is a number, not a matrix. Take a scalar system A = 1, B = 1 (so xt+1 = xt + ut), with cost weights Q = 1, R = 1, and a terminal penalty Qf = 1. Start the backward sweep at PN = Qf = 1.

One step back, compute KN−1 first:

K = (R + B·P·B)−1 B·P·A = (1 + 1·1·1)−1·1·1·1 = 1/2 = 0.5

So at this step the optimal action is u = −0.5·x — move halfway toward the target. Why not all the way (u = −x, landing exactly on 0)? Because control is costly (R = 1): the cost of slamming there outweighs the benefit. Halfway is the optimal compromise. Now the cost-to-go update:

P = Q + A·P·A − A·P·B·(R + B·P·B)−1·B·P·A
P = 1 + 1 − 1·(1/2)·1 = 2 − 0.5 = 1.5

So P grew from 1 to 1.5: states farther in the past cost more, because more steps of error and effort lie ahead. Take another step back with P = 1.5: K = 1.5/(1+1.5) = 0.6, and P = 1 + 1.5 − 1.5·0.6 = 1.6. The gains and P-values march toward a steady value as the horizon grows — and that fixed point is exactly the solution of the algebraic Riccati equation from Chapter 7. The infinite-horizon LQR gain is the limit of this backward recursion. Beautiful: finite-horizon DP, run long enough, is the steady-state optimal controller.

Now build the full backward recursion and prove the gain it produces actually stabilizes the system.

Why does the finite-horizon discrete LQR solve the Riccati recursion backward in time?

Chapter 9: Connections — Linearization, and Where This Goes

You now have the control-theory foundation that all of model-based RL stands on. Before the cheat sheet, one loose end: real robots are nonlinear. How do we use this beautiful linear theory on a nonlinear drone?

Linearization — the bridge from nonlinear to linear

The instructor's answer is linearization. Around an equilibrium point (xe, ue) where the system is at rest, approximate the nonlinear f by its first derivatives — the Jacobians:

A = ∂f/∂x |(xe, ue)     B = ∂f/∂u |(xe, ue)     ẋ ≈ A(x − xe) + B(u − ue)

The 2-D drone makes it vivid: at hover (level, motionless, thrust balancing gravity), the nasty trig term with sinθ and cosθ flattens to a simple linear matrix — the dynamics become "horizontal acceleration is proportional to tilt angle, vertical acceleration is proportional to extra thrust." Near hover, the drone is a linear system, so you design an LQR controller for the linearized A and B and it works beautifully — as long as you don't tilt too far. There's also feedback linearization, which algebraically cancels the nonlinearity (the instructor mentions it but skips the theory). And when linearization isn't enough — aggressive maneuvers, big tilts — you re-linearize at every step along a trajectory, which is exactly the iLQR/DDP and SQP machinery of the next lectures.

Cheat sheet — the control vocabulary you now own.
  • State-space model: ẋ = f(x,u) (continuous) or xt+1 = f(xt,ut) (discrete); linear form ẋ = Ax + Bu.
  • Feedback policy: u = π(x). Closed-loop system: ẋ = f(x, π(x)). Feedback recovers from disturbances; open-loop plans can't.
  • PID: P = error (stiffness), D = error rate (damping, kills overshoot), I = accumulated error (kills steady offset). u = −Kpx − Kdẋ − Ki∫x.
  • Stability: stable (stays near) < asymptotically stable (converges) < exponentially stable (converges fast); equivalent for linear systems. Lyapunov: find energy V with V̇ < 0.
  • Eigenvalue test: ẋ = Aclx stable iff all eigenvalues have negative real part (Hurwitz, left half-plane). Discrete: all magnitudes < 1 (inside unit circle).
  • Robustness: exponential stability implies ISS — a bounded disturbance buys only a bounded, proportional offset. Integral control kills constant disturbances.
  • LQR: minimize ∫(xTQx + uTRu)dt over ẋ = Ax + Bu. Optimal policy is linear: u = −K*x, K* = R−1BTP, P solves the Riccati equation. Q/R = error-vs-effort dial. Optimal AND stable.
  • Linearization: Jacobians A, B at an equilibrium turn a nonlinear system into a local linear one you can apply all the above to.

The honest caveats

Where to go next on this site

The test of this lesson. Open the Lecture 12 slides. You should now be able to, from memory: write a linear state-space model and a P/PD/PID control law; explain why D kills overshoot and I kills steady offset; state the three stability flavors and the eigenvalue (Hurwitz / unit-circle) test; build A−BK and read off stability; explain the LQR cost and its Q-vs-R trade-off; say why the optimal linear controller is just a gain u = −Kx; and run one step of the backward Riccati recursion by hand. If you can, you're ready for MPC and optimal control.

"The optimal controller for a linear system with a quadratic cost is a single matrix on the state. Everything harder — constraints, nonlinearity, unknown dynamics — is the rest of the course earning its keep."