Robotics

Pure Pursuit: The Geometry That Lets a Robot Chase a Path

A DARPA Grand Challenge truck barreling across the Mojave at 15 m/s, a warehouse AMR threading a 1.2 m aisle, and a John Deere combine holding a 25 mm line across a half-mile row all run some flavor of the same 40-year-old trick: fix your eyes on a point about a car-length ahead on the path, and steer along the single circular arc that hits it. That's pure pursuit — a geometric path tracker with essentially one tuning knob, the look-ahead distance L. No error integral, no Riccati equation, just an arc.

The whole controller collapses to one line of arithmetic: curvature κ = 2x/L², where x is how far the goal point sits to your left in the vehicle frame. It is embarrassingly simple, provably convergent for a constant look-ahead, and — as every team that has watched a robot cut corners or wobble on a straightaway has learned — deceptively easy to tune wrong.

  • Governing lawκ = 2x/L² (curvature to goal)
  • Steering (bicycle)δ = arctan(2·L_wb·x / L²)
  • One tuning knobLook-ahead L (often L = k·v + L₀)
  • Typical L0.5–6 m (scales with speed)
  • Steady error∝ κ_path·L² near a constant-curvature arc
  • First fieldedCMU Terragator/NavLab, Coulter 1992

Interactive visualization

Press play, or step through manually. The visualization is yours to drive — try it before reading on.

Open visualization fullscreen ↗

Watch the 60-second explainer

A condensed visual walkthrough — narrated, captioned, under a minute.

The one arc that reaches the look-ahead point

Pure pursuit answers a single question every control cycle: of all the circular arcs that start tangent to my current heading, which one passes through a chosen point on the path ahead? Because a car steering at a fixed wheel angle traces a circle, committing to that arc is the same as committing to a steering command.

Set up the geometry in the vehicle body frame with the origin at the rear axle, the +y (or +x, per convention) axis pointing forward, and lateral offset x to the side. Pick a goal point G on the path at straight-line (chord) distance L — the look-ahead distance — with body-frame coordinates such that x is its lateral offset. Simple chord geometry of a circle of radius R (tangent to your heading, passing through G) gives L² = 2R·x, which rearranges cleanly to:

  • Radius: R = L² / (2x)
  • Curvature: κ = 1/R = 2x / L²

That is the entire feedback law. The lateral offset x is the error signal; L² is the gain scaling. If G is dead ahead (x = 0), κ = 0 and you go straight. If G is far to the left, κ is large and you crank the wheel left. The controller never explicitly computes a cross-track error — it just keeps re-aiming at a moving carrot.

From curvature to a steering angle

Curvature is kinematics-agnostic, but a real vehicle needs an actuator command. For a car or Ackermann robot, the kinematic bicycle model lumps the two front wheels into one and relates steer angle δ to path curvature through the wheelbase L_wb:

  • Bicycle steering: δ = arctan(κ · L_wb) = arctan(2 · L_wb · x / L²)

A robot with a 2.6 m wheelbase (a small car), a 6 m look-ahead, and a goal point offset x = 1.0 m gives κ = 2(1.0)/6² = 0.056 m⁻¹ (R ≈ 18 m) and δ = arctan(0.056 × 2.6) ≈ 8.3°. For a differential-drive robot there is no steer angle at all; you convert curvature directly to wheel speeds. With track width b and commanded body speed v, the left/right wheel speeds are v_L = v(1 − κb/2) and v_R = v(1 + κb/2), so κ and v fully specify the motor commands.

The right-turn/left-turn sign of δ follows the sign of x, and the yaw rate the robot will actually achieve is ω = v·κ = v·(2x/L²). That coupling — turn rate rising with speed for a fixed geometry — is exactly why L is almost never held constant on a fast vehicle.

Look-ahead: the one knob, and why it fights itself

Every quirk of pure pursuit traces back to L. It behaves like the proportional gain of a P-controller — but inverted and squared — so it sets both responsiveness and damping at once, and you cannot separate them.

  • Short L (aggressive): small offsets produce large curvature (κ ∝ 1/L²). The robot snaps onto the path but overshoots, then over-corrects the other way — a classic under-damped limit-cycle oscillation that grows worse as speed rises. Below a critical L the loop is unstable.
  • Long L (sluggish): the carrot is so far ahead that the robot ignores nearby deviations and cuts corners, leaving a steady-state offset on curved paths and lazy convergence on straights.

Because the stable region shifts with velocity, production systems make look-ahead speed-scheduled, typically an affine law L = k·v + L₀, with a gain k on the order of 0.3–1.0 s (a fraction of a second of preview) and a floor L₀ of 0.3–1.0 m so the robot still tracks at a standstill. A 2 m/s AMR might run L ≈ 0.9 m; the same code at 15 m/s runs L ≈ 6 m. The controlling trade-off: corner-cutting error grows roughly with κ_path·L², while stability margin and disturbance smoothing grow with L — so you buy ride quality with tracking accuracy on curves.

The physics underneath: it's really lateral acceleration

Pure pursuit is a kinematic law, but a wheeled vehicle following it is a dynamic system, and the binding constraint is tire friction, not geometry. Commanding curvature κ at speed v demands a centripetal (lateral) acceleration a_lat = v²·κ = v²·(2x/L²), supplied entirely by lateral tire force. That force is capped by the friction circle: a_lat,max ≈ µ·g, where µ ≈ 0.8–0.9 on dry asphalt, ~0.3 on wet, ~0.1 on ice.

Concretely, a car at 15 m/s that pure pursuit asks to hold R = 18 m (κ = 0.056 m⁻¹) needs a_lat = 15² × 0.056 ≈ 12.5 m/s² ≈ 1.3 g — beyond any street tire. The vehicle understeers, the real path bulges outside the commanded arc, x grows, and the controller commands even more curvature: a divergence the pure kinematic model never sees. That is why serious implementations add a curvature/lateral-acceleration limiter (clamp κ so v²κ ≤ µ_design·g with a safety factor around 1.5–2) and a speed governor that slows the vehicle before a tight upcoming segment. The kinematic model is valid only when a_lat stays well inside the friction circle and sideslip is negligible — roughly the low-speed, high-µ regime.

Building the loop: the actual algorithm

A working pure-pursuit tracker is a tight loop, usually running at 20–100 Hz alongside a separate longitudinal (speed) controller. The steps:

  • 1. Localize: get the vehicle pose (x, y, θ) in the map frame, typically from an EKF fusing wheel odometry, IMU, and GPS/RTK or lidar-scan matching. RTK-GPS gives ~20 mm; wheel odometry alone drifts.
  • 2. Find the nearest path point: project the rear-axle position onto the polyline path to bound the search.
  • 3. Pick the goal point G: march forward along the path from the nearest point until the straight-line distance to the rear axle first equals L (the current speed-scheduled look-ahead). Interpolate to hit L exactly, not the nearest vertex.
  • 4. Transform G into the vehicle frame: a 2-D rotation/translation gives its lateral offset x.
  • 5. Compute curvature: κ = 2x / L².
  • 6. Convert to actuator command: δ = arctan(κ·L_wb) for Ackermann, or differential wheel speeds; clamp to steering limits and the friction-based curvature limit.
  • 7. Apply and repeat next cycle.

Total cost is a nearest-neighbor search plus a handful of trig calls — microseconds on a microcontroller, which is precisely why it survives on tiny robots and 1996-era compute alike. Compare that to MPC, which solves a constrained optimization every step for a fraction more accuracy at 10³–10⁶× the cost.

Where it runs, and where it breaks

Pure pursuit is everywhere low- to mid-speed autonomy lives: agricultural auto-steer (John Deere, Trimble, and Ag Leader guidance hold sub-25 mm lines across fields — the algorithm's original 1980s niche), warehouse AMRs (MiR, OTTO, Fetch), the CMU NavLab and early DARPA entries, ROS Navigation's regulated_pure_pursuit_controller, and countless F1TENTH and FSAE student cars because it fits on a Teensy.

Its documented failure modes are specific:

  • Corner-cutting on sharp curves when L exceeds the local radius of curvature — the arc slices inside the intended path. Mitigation: shrink L in curvature, or use a regulated variant that scales L (and speed) with path curvature and proximity.
  • Oscillation / instability at high speed with a fixed short L, exactly the under-damped P-controller behavior. Mitigation: speed-schedule L; add rate-limiting on δ.
  • Steady-state offset: with no integral term, a constant lateral disturbance (crosswind, side slope, mis-calibrated odometry) leaves a bias the geometry never zeroes out — the tracker converges to an offset arc, not the path.
  • Reverse driving: naive pure pursuit is unstable in reverse; you must move the reference point to the front axle and re-derive, or switch controllers.
  • Sharp cusps and reversals confuse goal-point selection; the search can jump to the wrong branch of a self-intersecting path.

Best practice: speed-schedule the look-ahead, clamp curvature to the friction circle, add a separate integral trim or a Stanley-style heading term for zero steady-state error, and keep the path smooth (curvature-continuous, e.g. splines or clothoids) so the goal point never snaps.

Pure pursuit versus a Stanley-style front-axle controller — two geometric path trackers with opposite temperaments.
PropertyPure PursuitStanley Controller
Reference pointGoal point L ahead on pathNearest point to front axle
Control lawκ = 2x/L² (steer to arc)δ = ψ_e + arctan(k·e_fa / v)
Feedback quantityLateral offset x of look-aheadCross-track error e + heading error ψ_e
Corner behaviorCuts inside corners (short-cuts)Tracks tightly, little cut-in
Tuning riskToo-small L → oscillation; large L → sluggishHigh-speed jitter without damping term
Best fitSmooth paths, moderate speed, low computeHigh-speed lane keeping, DARPA-style

Frequently asked questions

Why use pure pursuit instead of a PID on cross-track error?

Pure pursuit folds heading and lateral error into one geometric quantity — the arc to a look-ahead point — so it's inherently well-behaved on curved paths where a lateral-error PID would need feedforward for the path curvature. It also has one physically meaningful knob (L) instead of three gains to tune. The trade-off is no integral action, so it leaves a steady-state offset under constant disturbances that a PID's integral term would cancel.

How do I choose the look-ahead distance L?

Start with an affine speed schedule, L = k·v + L₀, with k ≈ 0.3–1.0 s (a fraction of a second of preview) and L₀ ≈ 0.3–1.0 m so tracking works at low speed. Then tune by observation: if the robot oscillates on straights, increase L; if it cuts corners, decrease L (or curvature-schedule it). Always keep L below the tightest path radius you must track.

What's the difference between pure pursuit and the Stanley controller?

Pure pursuit references a goal point L ahead and steers to an arc using the rear axle; Stanley references the nearest path point to the front axle and uses explicit cross-track plus heading error, δ = ψ_e + arctan(k·e/v). Stanley tracks corners tighter and shines at high speed (it won the DARPA Grand Challenge), while pure pursuit is smoother, cheaper, and more forgiving on gentle paths but tends to cut corners.

Why does my robot oscillate down a straight line?

Almost always a look-ahead that is too short for the current speed, which makes the effective proportional gain (∝ 1/L²) too high — a classic under-damped loop. Increase L, speed-schedule it, or add a rate limit on the steering command. The instability worsens with speed, so a value that's fine at 1 m/s can diverge at 5 m/s.

How do I keep pure pursuit inside tire-grip limits?

The commanded curvature implies a lateral acceleration a_lat = v²·κ, which the tires cap at roughly µ·g (≈8 m/s² on dry asphalt, ≈3 on wet). Clamp κ so that v²·κ ≤ µ_design·g with a safety factor of 1.5–2, and add a speed governor that slows the vehicle before tight segments. Without this, a demanded tight arc at speed exceeds grip, the vehicle understeers wide, and the geometric loop can diverge.

Does pure pursuit work in reverse?

Not the standard formulation — with the reference point at the rear axle, reversing makes the loop unstable, and the robot swings away from the path. To drive backward you move the geometric reference to the front axle and re-derive the curvature law, effectively pursuing a point behind the direction of travel, or you hand off to a controller designed for reverse motion at low speed.