LQR
LQR (Linear-Quadratic Regulator) is the principled answer to the question PID never solves: how do I pick my controller gains? Instead of hand-tuning knobs by trial and error, you write down a cost function that trades off how far the system is from its goal against how much control effort you spend — and LQR computes the optimal feedback gains that minimize that cost. It matters because it turns gain tuning into a design decision (what do I care about?) rather than guesswork.
Prerequisites
The setup
LQR starts from a linear system in state-space form:
ẋ = A·x + B·uHere x is the state vector (everything you need to describe the system — e.g. position and velocity), u is the control input (what your actuators do), A describes how the state evolves on its own, and B describes how inputs push it. The controller is a full-state feedback law:
┌─────────────┐ r=0 │ │ u = -K·x ┌──────────────┐ ──────►│ -K (gain) │ ─────────────────►│ plant │ │ │ │ ẋ = Ax + Bu │ └─────▲───────┘ └──────┬───────┘ │ │ │ x (full state) │ └──────────────────────────────────┘In words: push every input proportional to how far the whole state is from zero. K is the gain matrix — for multi-input/multi-output (MIMO) systems it couples every input to every state.
The cost function
LQR finds K by minimizing a quadratic cost accumulated over time:
J = ∫ ( xᵀ·Q·x + uᵀ·R·u ) dt- Q — the state-error penalty: how much you care about being off-target. Big Q → tight, aggressive control that drives error to zero fast.
- R — the control-effort penalty: how much you care about aggressive, energy-hungry, or hardware-stressing actuation. Big R → gentle, lazy control that conserves effort.
The Q/R ratio is the design knob. You don’t tune gains; you tune what you value, and the gains follow.
How K is found
LQR reduces to solving the Algebraic Riccati Equation (ARE) for a matrix P. You don’t derive it by hand — it’s a standard solver call. Once P is known:
K = R⁻¹·Bᵀ·PRunnable example
A classic double integrator — a frictionless cart where the input is acceleration, state = [position, velocity].
import numpy as npfrom scipy.linalg import solve_continuous_are
# Double integrator: state = [position, velocity], input = accelerationA = np.array([[0.0, 1.0], [0.0, 0.0]])B = np.array([[0.0], [1.0]])
# Q penalizes state error; R penalizes control effort.# Increase Q (or shrink R) for tighter, more aggressive control.Q = np.diag([1.0, 1.0])R = np.array([[1.0]])
# Solve the Algebraic Riccati Equation for P, then form the LQR gain.P = solve_continuous_are(A, B, Q, R)K = np.linalg.inv(R) @ B.T @ P
print("LQR gain K =", K) # [[1.0, 1.732]]print("closed-loop eigenvalues =", np.linalg.eigvals(A - B @ K)) # both have negative real part → stableRunning this prints K = [[1.0, 1.732]], and the closed-loop poles eig(A - BK) land at -0.866 ± 0.5j — negative real parts, so the cart is driven smoothly back to the origin.
LQR vs PID
PID is hand-tuned and single-input/single-output (SISO): you twist three knobs per loop and accept the coupling between loops as a nuisance. LQR is optimal and natively MIMO — it handles coupled multi-axis systems in one shot. The trade-offs:
- LQR requires a model (
A,B). If you don’t have one, identify it first — see System Identification and State-Space Representation. - LQR assumes full state knowledge. When you can’t measure the whole state, pair it with a Kalman filter to estimate
x; the combination is called LQG (Linear-Quadratic-Gaussian).
Related Terms
Sources
- Kalman, R. E. “Contributions to the Theory of Optimal Control.” Boletín de la Sociedad Matemática Mexicana, 1960. (Original formulation of the optimal regulator.)
- Anderson, B. D. O., and Moore, J. B. Optimal Control: Linear Quadratic Methods. Dover, 2007.
- SciPy documentation,
scipy.linalg.solve_continuous_are. Accessed 2026-06-01. https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.solve_continuous_are.html - Underactuated Robotics (R. Tedrake), Ch. “Linear Quadratic Regulators.” Accessed 2026-06-01. https://underactuated.mit.edu/lqr.html