Reference example · Project 1 · Basic Skills for Experimentalists, TIGP 2026

Pendulum on a cart

A cart on a rail with a pole hinged on it. Push the cart and the pole swings; switch balance on and a controller keeps it upright. It exists to show the shape of a finished Project 1 — and, more than that, to show a simulation being checked against a number worked out on paper before any code existed.

Open the app Code The five-line spec The log

The check is the whole point

The specification named one number that could be predicted by hand, before a line of code was written: the small-swing period of a simple pendulum.

T = 2π√(L/g) = 2π√(1.00 m / 9.81 m s−²) = 2.006 s

The app measures its own period by timing successive crossings of the hanging position and prints it next to the prediction. Let the pole swing and the two numbers sit side by side on screen.

The app with the pole swinging below the cart. The
      readout in the toolbar shows expected T = 2.006 s and measured T = 1.987 s.
Predicted 2.006 s, measured 1.987 s. They do not agree exactly, and that disagreement is the interesting part.

Why it is not exactly 2.006 s

Two real effects, both visible on screen, both predictable without touching the code.

The cart recoils. 2π√(L/g) assumes the pivot is nailed down. This one is not: the cart is free to slide, so the pivot moves the other way as the pole swings, which stiffens the oscillation and shortens the period by √(M/(M+m)). With M = 5.0 kg and m = 0.2 kg that is a factor 0.9806.

The amplitude is not small. Released with the bob moving at 1.2 rad s−¹ the swing reaches 22°, and a real pendulum slows as it swings wider — lengthening the period by about 1 + θ₀²/16, a factor 1.0093.

Ideal small-swing period 2π√(L/g)2.0061 s
× cart recoil √(M/(M+m))× 0.9806
× finite amplitude 1 + θ₀²/16, θ₀ = 22.1°× 1.0093
Predicted1.9854 s
Measured by the app1.987 s
Agreement0.1 %

This is what a check is for. The first comparison was 1 % out. The useful response was not to shrug, and not to adjust the code until the numbers matched — it was to ask which physics the hand calculation had left out, put it back, and find agreement to 0.1 %. Both corrections were predicted on paper and then confirmed.

Separating the two corrections

You can switch one of them off. Make the cart heavy and it stops recoiling, leaving the amplitude correction alone — so the period does not converge on 2.006 s, it lands about 1 % above it. Edit const M in app/index.html:

cart mass Mmeasured Tpredictedwhat is left
5 kg1.9875 s1.9854 s both corrections; they nearly cancel
50 kg2.0208 s2.0207 s recoil almost gone
500 kg2.0250 s2.0243 s amplitude only

The 500 kg row is the cleanest result on this page: with the pivot effectively fixed, 2π√(L/g) × (1 + θ₀²/16) = 2.0243 s against 2.0250 s measured. Two lines of algebra, four significant figures, no fitting.

Balancing it

Switch balance on and a PD controller takes over the same single input a player has — a horizontal force on the cart:

F = (120 θ + 25 θ̇) + (2.0 x + 3.0 ẋ)

The first bracket rights the pole; the second walks the cart back toward the middle. Push the cart with the arrow keys and watch it catch the pole.

Animation: the pole stands upright on the cart, is
      shoved sideways, and the cart darts underneath it to bring it back up, twice.
Two shoves, caught. From rest it comes back upright from a lean of more than 60°.

The sign of that first bracket is the whole trick, and it looks backwards. To catch a pole falling to the right you must drive the cart to the right, under it — not away from it. The controller shipped with the opposite sign from 2026-09-06 until 2026-09-12, which drove the pole over from any starting lean and parked the cart against the rail every time. Measured twelve seconds after release from the same three leans, with only that sign changed:

released frombefore — |θ|, cart after — |θ|, cart
3°1.810 rad, −3.00 m0.001 rad, 0.02 m
9°1.811 rad, −3.00 m0.003 rad, 0.05 m
17°1.809 rad, −3.00 m0.007 rad, 0.10 m

1.81 rad is the pole lying flat with the cart jammed against the end of the rail. 0.00 rad is upright. The period check never caught this because it runs with balance off.

How it is built

The shape to copy

Not the pendulum — the method, and the repository layout the course asks for:

  1. A five-line SPEC.md written first, naming one number you can predict on paper.
  2. The app in app/, published at …/app/.
  3. A project website at the repository root — this page — saying what it is, how it works, and what was checked.
  4. A PROGRESS.md: done, verified, next, gotchas. One entry per session.
  5. A card on the class project wall when it works.

If your own session stalls in class, fork this repository and carry on from it — but do the timing yourself. The measured number in your SPEC.md has to be one you took.