Code: github.com/oalahurikar/CarND-MPC-Project

The Problem

Drive a simulated car around a track at 60 mph. Sounds simple — until the simulator adds a cruel twist: every steering command you send is delayed by 100 ms before the car actually responds. By the time your control lands, the world has moved on.

A reactive controller — “I see error, I correct error” — fails. It chases ghosts. The car wobbles, oversteers, and eventually leaves the road.

The Idea

Stop reacting. Start predicting.

Instead of asking “what should I do right now?”, the car asks “what should I do over the next 750 ms?” — solves for the entire steering and throttle plan, executes only the first step, then re-plans on the next tick.

This is Model Predictive Control. The car carries a tiny physics model of itself in its head and runs an optimizer 20 times a second to find the smoothest path forward.

Why It Works Under Latency

The horizon is 750 ms. The latency is 100 ms. The plan is already looking 7× past the delay window — by the time the command lands, the car is still doing exactly what it intended.

The trick that holds it all together: a single weight in the cost function. Penalize change in steering 600× harder than anything else. The optimizer stops jerking the wheel and starts drawing smooth arcs. Smooth plans survive delay; jerky ones don’t.

The Stack

C++ with Ipopt (solver), CppAD (auto-diff), Eigen (linear algebra), uWebSockets (simulator bridge). 118-variable nonlinear program, solved every 50 ms.

The Result

Full track. Curves and straights. 60 mph. 100 ms latency. No off-road excursions.

What I Took Away

The real lesson wasn’t the math — it was that smoothness is a control strategy. One weight, tuned an order of magnitude higher than the rest, did more for stability than any clever state estimation would have. Sometimes the best way to handle a hard problem is to make the answer boring.