BlockWerk Guides

Inverted Pendulum on a Cart

A pendulum hanging from a pivot is boring: push it and it swings back. Stand the same pendulum upright on a cart that can only move sideways, and it becomes the sharpest teaching problem in control engineering. The system cannot hold still on its own. Left alone it falls, and it falls faster the further it has already fallen. The only way to keep it up is to move the thing it is standing on — to catch it by driving the cart underneath it.

That is what makes it worth a full case study. Almost every idea in classical control shows up here with nowhere to hide: an unstable plant, a controller that has to act before the error grows, the difference between reacting to an error and anticipating it, and the trade-off between a fast response and a violent one.

The physical setup

A cart of mass MM rolls on a horizontal track, with viscous friction bb opposing its motion. A rod of mass mm is pinned to the cart and free to rotate in the vertical plane. The force uu is applied horizontally to the cart — it is the only thing we control. The angle θ\theta is measured from the upward vertical, so θ=0\theta = 0 is balanced and positive θ\theta means the rod has tipped one way.

SymbolMeaningValue
MMcart mass0.5 kg0.5\ \text{kg}
mmpendulum mass0.2 kg0.2\ \text{kg}
bbcart friction coefficient0.1 N⋅s/m0.1\ \text{N}\cdot\text{s/m}
llpivot to centre of mass0.3 m0.3\ \text{m}
IIrod inertia about its centroid13ml2=0.006 kg⋅m2\tfrac{1}{3}ml^2 = 0.006\ \text{kg}\cdot\text{m}^2
gggravitational acceleration9.81 m/s29.81\ \text{m/s}^2

Equations of motion

Take the cart and the rod separately and let the pin joint pass forces between them. Call the horizontal force in the joint NN and the vertical force PP.

Newton's second law along the track, for the cart alone:

Mx¨+bx˙+N=uM\ddot{x} + b\dot{x} + N = u

The rod's centre of mass sits at x−lsin⁡θx - l\sin\theta horizontally (positive θ\theta leans the rod back, towards −x-x), so differentiating twice gives the horizontal force the rod needs:

N=mx¨−mlθ¨cos⁡θ+mlθ˙2sin⁡θN = m\ddot{x} - ml\ddot{\theta}\cos\theta + ml\dot{\theta}^2\sin\theta

Substituting removes NN and leaves the first equation of motion:

(M+m)x¨+bx˙−mlθ¨cos⁡θ+mlθ˙2sin⁡θ=u(M + m)\ddot{x} + b\dot{x} - ml\ddot{\theta}\cos\theta + ml\dot{\theta}^2\sin\theta = u

For the second, take moments about the rod's centre of mass. Gravity acts there so it contributes nothing; only the two joint forces do:

(I+ml2)θ¨−mglsin⁡θ=mlx¨cos⁡θ(I + ml^2)\ddot{\theta} - mgl\sin\theta = ml\ddot{x}\cos\theta

Two coupled nonlinear equations. Note the sign of the gravity term: moved to the right-hand side it is +mglsin⁡θ+mgl\sin\theta when θ\theta is measured from upward, so it pushes θ¨\ddot\theta the way θ\theta already points — exactly what makes this system fall over rather than swing back.

Linearising about the upright position

Balancing means staying near θ=0\theta = 0. For small angles, sin⁡θ≈θ\sin\theta \approx \theta, cos⁡θ≈1\cos\theta \approx 1, and θ˙2\dot{\theta}^2 is second-order small and drops out entirely:

(I+ml2)θ¨−mglθ=mlx¨(I + ml^2)\ddot{\theta} - mgl\theta = ml\ddot{x}

(M+m)x¨+bx˙−mlθ¨=u(M + m)\ddot{x} + b\dot{x} - ml\ddot{\theta} = u

Taking Laplace transforms with zero initial conditions and eliminating X(s)X(s) between the two gives the transfer function from the applied force to the pendulum angle:

Θ(s)U(s)=mlq ss3+b(I+ml2)qs2−(M+m)mglqs−bmglq\frac{\Theta(s)}{U(s)} = \frac{\dfrac{ml}{q}\,s}{s^3 + \dfrac{b(I + ml^2)}{q}s^2 - \dfrac{(M+m)mgl}{q}s - \dfrac{bmgl}{q}}

where

q=(M+m)(I+ml2)−(ml)2q = (M + m)(I + ml^2) - (ml)^2

With the values above, q=0.0132q = 0.0132 and the transfer function becomes

Θ(s)U(s)=4.54545 ss3+0.18182 s2−31.21364 s−4.45909\frac{\Theta(s)}{U(s)} = \frac{4.54545\,s}{s^3 + 0.18182\,s^2 - 31.21364\,s - 4.45909}

Why it falls over

Those two minus signs in the denominator are the whole story. Factor it and the poles are

s=+5.568,s=−5.607,s=−0.143s = +5.568,\qquad s = -5.607,\qquad s = -0.143

One of them is in the right half-plane. Any disturbance, however small, excites a response that grows like e5.568te^{5.568t} — the angle doubles roughly every 0.120.12 seconds. This is not a modelling artefact. It is the rod falling over, written in algebra.

Run the diagram with the controller disconnected and you will see exactly this: a nudge, then a curve that leaves the top of the plot and never comes back.

The whole plant as one state-space model

The transfer function above describes the angle, and only the angle. Put the cart back in and the linearised system has four states — cart position and velocity, rod angle and angular rate — and one input:

x˙=Ax+Bu,x=[xx˙θθ˙]T\dot{\mathbf{x}} = A\mathbf{x} + Bu,\qquad \mathbf{x} = \begin{bmatrix} x & \dot{x} & \theta & \dot{\theta} \end{bmatrix}^\mathsf{T}

A=[01000−(I+ml2)bqm2gl2q000010−mlbqmgl(M+m)q0],B=[0I+ml2q0mlq]A = \begin{bmatrix} 0 & 1 & 0 & 0 \\ 0 & -\dfrac{(I+ml^2)b}{q} & \dfrac{m^2gl^2}{q} & 0 \\ 0 & 0 & 0 & 1 \\ 0 & -\dfrac{mlb}{q} & \dfrac{mgl(M+m)}{q} & 0 \end{bmatrix},\qquad B = \begin{bmatrix} 0 \\ \dfrac{I+ml^2}{q} \\ 0 \\ \dfrac{ml}{q} \end{bmatrix}

Its poles are the three above plus one more at s=0s = 0: the cart, which has no preferred position at all. Written out, the angle's transfer function from this model is

Θ(s)U(s)=4.545 s2s (s3+0.182 s2−31.21 s−4.459)\frac{\Theta(s)}{U(s)} = \frac{4.545\,s^2}{s\,(s^3 + 0.182\,s^2 - 31.21\,s - 4.459)}

and one ss cancels. That cancellation is why the third-order transfer function was correct, and it is also the whole reason an angle-only controller cannot bring the cart back: seen from θ\theta, the cart pole is invisible.

The cart position has zeros of its own, at s=±mgl/(I+ml2)=±4.95s = \pm\sqrt{mgl/(I+ml^2)} = \pm 4.95. The one in the right half-plane matters later.

Building it in BlockWerk

The plant is a single StateSpace block. Its matrices are not decimals: every entry is written as an expression over the diagram's variables — mgl(M+m)/q, (I+ml^2)/q — and evaluated when the model runs. Move the MM slider and AA and BB follow; the engine rebuilds the block's matrices in place without restarting. CC is the identity, so the block has four outputs, y_0 to y_3, one per state.

Everything else hangs off those outputs. The angle goes through a Saturation at ±90°\pm 90° — the floor, which the linear model knows nothing about — to the scope and to the angle-only controller. All four states go to the state-feedback gains.

Disturbing the system

Here is a trap worth stepping around deliberately.

The obvious test is a step on the setpoint. For the angle it does nothing. The setpoint is zero — upright — and the model starts upright, so the error is zero, the controller outputs nothing, and the plot is a flat line forever. Nothing has gone wrong; there is simply nothing to correct.

A balancing problem is not a tracking problem. What you want to ask is _"if something knocks it, does the controller catch it?"_ So the input is a disturbance, applied to the force: a short shove, then nothing. This model uses a rectangular pulse of 10 N10\ \text{N} lasting 0.1 s0.1\ \text{s} at t=0.2 st = 0.2\ \text{s} — an impulse of 1 N⋅s1\ \text{N}\cdot\text{s} — built from two Step blocks that cancel. Without a controller the rod reaches the floor half a second later.

A controller that only sees the angle

The first loop is a PID on −θ-\theta. Five gain sets, each measured over a 5 s5\ \text{s} run with a sample time of 0.001 s0.001\ \text{s}:

KpK_pKiK_iKdK_dpeak θ\thetain degreesback within 0.0050.005 rad
1001200.04110.04112.35°2.35°0.750.75 s
1000200.04110.04112.35°2.35°0.750.75 s
3205.50.13960.13968.00°8.00°1.051.05 s
501100.08190.08194.69°4.69°0.940.94 s
2001400.02050.02051.17°1.17°0.590.59 s

Proportional action alone is a spring. With Kp=100K_p = 100 and nothing else the closed-loop poles sit at −0.10±20.6j-0.10 \pm 20.6j: the rod swings through upright at 3.3 Hz3.3\ \text{Hz} with a damping ratio of 0.0050.005, and keeps swinging. A third pole at +0.011+0.011 is still unstable — slowly.

Derivative action removes the energy. It responds to θ˙\dot\theta, to how fast the rod is falling, and so starts pushing while the rod is still nearly upright. With Kd=20K_d = 20 the swing dies out within a second.

The integral term moves the last slow pole. Without it the constant term of the closed-loop characteristic polynomial, −bmgl/q+Ki ml/q-bmgl/q + K_i\,ml/q, is negative, and a pole stays at +0.011+0.011. Ki=1K_i = 1 (the CTMS choice) makes it −0.0002-0.0002: stable on paper, with a time constant of about 80 minutes.

And through all of it the cart drifts. After the push it rolls off at a steady pace — half a metre in five seconds, two metres in twenty — because no choice of KpK_p, KiK_i and KdK_d can move the pole at s=0s = 0.

State feedback: the cart comes back

Measure all four states and feed each one back:

u=−K [x−xrefx˙θθ˙]Tu = -K\,\begin{bmatrix} x - x_\text{ref} & \dot{x} & \theta & \dot{\theta} \end{bmatrix}^\mathsf{T}

The model uses the CTMS LQR design, minimising ∫(xTQ x+u2) dt\int (\mathbf{x}^\mathsf{T} Q\,\mathbf{x} + u^2)\,dt with Q=diag⁡(5000,0,100,0)Q = \operatorname{diag}(5000, 0, 100, 0):

K=[−70.7−37.8105.620.9]K = \begin{bmatrix} -70.7 & -37.8 & 105.6 & 20.9 \end{bmatrix}

which puts the closed-loop poles at −8.49±7.93j-8.49 \pm 7.93j and −4.76±0.83j-4.76 \pm 0.83j. After the push the rod peaks at 5.4°5.4° and the cart returns to the middle. A setpoint step of 0.2 m0.2\ \text{m} at t=1.5 st = 1.5\ \text{s} takes about a second, a peak lean of 9°9° and 14 N14\ \text{N} — and starts with the cart rolling 58 mm58\ \text{mm} the wrong way. That is the zero at +4.95+4.95: to lean the rod towards the target the cart must first move out from under it, and state feedback moves every pole but no zero.

Transport delay

A real loop has latency — filtering, sampling, a bus, the drive. Break the loop at the cart's input and the loop gain L(s)=K(sI−A)−1BL(s) = K(sI - A)^{-1}B crosses 0 dB0\ \text{dB} at 26.1 rad/s26.1\ \text{rad/s} with 61.3°61.3° of phase margin. A delay τd\tau_d leaves the magnitude alone and subtracts ωτd\omega\tau_d from the phase, so the delay margin is

τmax=61.3°⋅π/18026.1 rad/s≈41 ms\tau_\text{max} = \frac{61.3° \cdot \pi/180}{26.1\ \text{rad/s}} \approx 41\ \text{ms}

Measured: 30 ms30\ \text{ms} raises the peak lean from 9°9° to 13°13° and leaves 16°16° of margin; 40 ms40\ \text{ms} rings at the edge; 50 ms50\ \text{ms} loses the rod.

Things to try

  • The speed slider scales all four LQR poles by one factor, and the gains are designed again for whatever plant the other sliders describe. At 0.50.5 a setpoint move costs 0.9 N0.9\ \text{N}; at 1.51.5 it costs 72 N72\ \text{N} and a 21°21° lean.
  • Combine speed 1.51.5 with 30 ms30\ \text{ms} of delay. The faster controller crosses over at a higher frequency and has only about 28 ms28\ \text{ms} of delay margin: the rod falls.
  • Set the wind to 5 N5\ \text{N}. The rod stays upright, but the cart settles about 7 cm7\ \text{cm} off its setpoint: at rest the controller must push back with −5 N-5\ \text{N}, and the position gain only does that with an error, F/kxF/k_x. Integral action on xx would remove it.
  • Drag ll up. A longer rod falls more slowly — the unstable pole moves toward the origin — which is why circus performers balance long poles, not short ones.

What this model leaves out

The model is linear, which means it is only honest near upright: sin⁡θ≈θ\sin\theta \approx \theta holds to within 1%1\% up to about 14°14°. The linear model will dutifully catch a rod from angles a real one could not come back from. Swinging the rod up from hanging down needs a nonlinear controller first — Åström–Furuta energy control drives E=12(I+ml2)θ˙2+mgl(cos⁡θ−1)E = \tfrac12 (I+ml^2)\dot\theta^2 + mgl(\cos\theta - 1) to zero, reinforcement learning is another route — with a linear controller like this one taking over near the top.

The cart runs on an endless track here, and the motor delivers any force asked of it.

Sources

The parameter set used here (MM, mm, bb, ll) and the choice of this system as a worked example come from the Control Tutorials for MATLAB & Simulink (CTMS), by Prof. Dawn Tilbury (University of Michigan) and Prof. Bill Messner (Carnegie Mellon University), later extended by Prof. Rick Hill (Detroit Mercy), JD Taylor (CMU) and Prof. Shuvra Das (Detroit Mercy), with funding from the NSF (grant DUE 9554819) and MathWorks. CTMS is licensed CC BY-SA 4.0.

The derivation, the text, the block diagram and every measured number on this page are our own work, produced on BlockWerk's own engine. We use g=9.81 m/s2g = 9.81\ \text{m/s}^2.

The equations of motion for a cart-mounted inverted pendulum are standard and appear in substantially this form in most control textbooks, among them Ogata's Modern Control Engineering, Nise's Control Systems Engineering and Franklin, Powell & Emami-Naeini's Feedback Control of Dynamic Systems.

See Also

  • StateSpace: the whole plant, four states, matrices written as formulas.
  • Gain: the four state-feedback gains.
  • PIDController: the angle-only controller.
  • Delay: the transport delay between controller and cart.
  • Saturation: the floor at ±90°.
  • XYPlot: the phase plane, θ against θ̇.
  • uPlotDisplay: angle, cart position and control force.

Simulate in BlockWerk

Interactive sandbox directly in your browser — zero installation, WASM-powered.

Simulate in BlockWerk →