← All modules

5.5 Trajectory Navigation

Draft — not verified

Theoretical Background: Trajectory Navigation

Module 5 Theory: Figure-Eight Trajectory and Pure Pursuit Path Following

Learning Objectives

  • Derive the lemniscate parametric trajectory used in the figure-eight simulation
  • Distinguish path-following Pure Pursuit from goal-seeking proportional control
  • Understand arc-length parameterisation and lookahead-distance selection
  • Interpret the navigation performance metrics produced by useFigure­Eight­Navigation
  • Analyse the FigureEightTrajectory library and its integration with the controller

5.5.1 The Lemniscate Trajectory

5.5.1.1 Parametric Definition

The figure-eight path used in the /figure-eight-nav page is a lemniscate of Bernoulli scaled by amplitude . The standard Cartesian parametric form is:

where is the parameter and is the lobe half-amplitude in metres. As advances from to , the robot traces two complete lobes, returning exactly to the origin.

5.5.1.2 FigureEightConfig Parameters:

// useFigureEightNavigation.ts
interface FigureEightConfig {
  amplitude:       number  // lobe half-width (m), default 3.0
  speed:           number  // target cruise speed (m/s), default 0.4
  waypointSpacing: number  // arc-length between waypoints (m), default 0.1
  loops:           number  // number of complete laps before stopping
}

5.5.1.3 Arc-Length Parameterisation

Raw parametric sampling produces uneven waypoint spacing because is not constant along the lemniscate. FigureEightTrajectory.js corrects this by numerically integrating arc length and resampling at uniform intervals :

This ensures the robot receives waypoints at constant geometric spacing regardless of the local curvature of the lemniscate.

5.5.1.4 Trajectory Metrics:

// FigureEightTrajectory.js
getLength()        // total arc length (m) for the configured amplitude
getWaypoints()     // array of {x, y, theta, curvature} objects
getEstimatedTime() // getLength() / config.speed  (seconds)

5.5.2 Pure Pursuit for Curved Path Following

5.5.2.1 Distinction from Goal-Seeking Control

The proportional and PID controllers in useControlAlgorithms drive towards a single static goal point. Pure Pursuit in the figure-eight context drives along a precomputed path by continuously updating the target to a point ahead on the path, producing smooth, anticipatory steering.

PurePursuitConfig Parameters:

// useFigureEightNavigation.ts
interface PurePursuitConfig {
  lookaheadDistance: number  // L — path lookahead (m), default 0.8
  maxAngularVel:     number  // omega_max (rad/s), default 1.5
  goalTolerance:     number  // waypoint switching radius (m), default 0.3
  kp:                number  // proportional gain on heading error, default 1.2
}

5.5.2.2 Lookahead Point Selection

At each control cycle, the algorithm finds the waypoint on the precomputed trajectory that is closest to the lookahead distance ahead of the robot:

where is the -th waypoint. Unlike the single-goal version, always advances forward along the path and never regresses, preventing the robot from doubling back.

5.5.2.3 Steering Law

Given the lookahead target at world position , the heading error is:

The steering curvature and velocity commands are:

Equation (9) applies curvature-based speed reduction: the robot slows proportionally to the local path curvature , with damping coefficient . This prevents corner-cutting on the tight inner turns of the lemniscate.

5.5.2.4 Implementation in useFigureEightNavigation:

// useFigureEightNavigation.ts (simplified)
const updateNavigation = (robotPose: RobotPose) => {
  const waypoints  = pathWaypoints.value
  const cfg        = controllerConfig.value

  // Find lookahead waypoint
  let targetIdx = currentWaypointIndex.value
  while (targetIdx < waypoints.length) {
    const wp  = waypoints[targetIdx]
    const dx  = wp.x - robotPose.x
    const dy  = wp.y - robotPose.y
    const dist = Math.hypot(dx, dy)
    if (dist >= cfg.lookaheadDistance) break
    targetIdx++
  }

  // Wrap index for continuous looping
  if (targetIdx >= waypoints.length) {
    targetIdx = 0
    completionCount.value++
  }

  const target    = waypoints[targetIdx]
  const dx        = target.x - robotPose.x
  const dy        = target.y - robotPose.y
  const theta_t   = Math.atan2(dy, dx)
  let   e_theta   = theta_t - robotPose.theta
  while (e_theta >  Math.PI) e_theta -= 2 * Math.PI
  while (e_theta < -Math.PI) e_theta += 2 * Math.PI

  // Curvature-scaled speed (Eqn 9)
  const kappa   = 2 * Math.sin(e_theta) / cfg.lookaheadDistance
  const v       = cfg.speed * Math.max(0.3, 1 - 0.4 * Math.abs(kappa))
  const omega   = Math.max(-cfg.maxAngularVel,
                  Math.min(cfg.maxAngularVel, cfg.kp * e_theta))

  currentWaypointIndex.value = targetIdx
  return { linear: v, angular: omega }
}

5.5.3 Lookahead Distance Selection

The lookahead distance is the primary tuning parameter:

(m)BehaviourSuitable for
Tight tracking, corner-cuttingLow speed, high precision
(default)Balanced smooth + accurateGeneral figure-eight use
Smooth, cuts sharp turnsHigh speed, large arenas

The default  m was chosen empirically for the 3 m amplitude lemniscate at  m/s. As a rule of thumb: , which gives one second of forward anticipation.

5.5.4 Navigation Performance Metrics

useFigureEightNavigation accumulates a rich performance record throughout the navigation run.

// useFigureEightNavigation.ts
interface NavigationMetrics {
  totalDistance:      number  // odometric path length (m)
  averageSpeed:       number  // mean |v| (m/s)
  maxDeviation:       number  // worst cross-track error (m)
  averageDeviation:   number  // mean cross-track error (m)
  completionTime:     number  // lap time in seconds
  waypointsReached:   number  // total waypoint transitions
  smoothnessScore:    number  // 0-1 acceleration smoothness
  pathEfficiency:     number  // ideal_length / actual_distance
}

5.5.4.1 Cross-Track Error

The deviation from the ideal lemniscate path is computed as the perpendicular distance from the robot’s current position to the nearest path segment:

where is the unit tangent vector at waypoint . A smaller indicates tighter path adherence.

5.5.4.2 Path Efficiency

A value of means the robot travelled exactly the theoretical arc length. Values below indicate overshooting or oscillatory behaviour.

5.5.4.3 Smoothness Score

The smoothness score penalises rapid changes in angular velocity:

A score near 1 indicates consistent, gentle steering; a score near 0 indicates erratic steering caused by an overly aggressive or too-small .

5.5.5 Comparison: Goal-Seeking vs Path-Following Pure Pursuit

PropertyGoal-seeking (5_4)Path-following (5_5)
Target typeSingle static pointMoving lookahead on path
Path requiredNoYes (precomputed waypoints)
Handles curvesPoorly (stop-and-turn)Well (anticipatory steering)
Lap countingN/ANative completion counter
Speed adaptationThreshold-basedCurvature-proportional (Eqn 9)
Cross-track errorNot measuredMeasured per cycle (Eqn 10)
Best suited to/control page/figure-eight-nav page

Summary

Trajectory generation (Equations 1–3): the lemniscate provides a continuously curving path that exercises the full steering envelope of the differential-drive robot. Arc-length parameterisation ensures uniform waypoint spacing irrespective of local curvature.

Pure Pursuit path following (Equations 4–9): lookahead-distance selection anticipates the path shape; curvature-scaled speed reduction prevents corner-cutting; the single tuning parameter provides an interpretable accuracy-vs-smoothness trade-off.

Performance analysis (Equations 10–12): cross-track error, path efficiency, and smoothness score together characterise whether the controller is well-tuned for the given speed and amplitude combination.

Design Choices:

  • Lemniscate over waypoint list: A parametric curve guarantees smoothness with a single amplitude parameter, avoiding the jagged paths that arise from manually placed waypoint lists on a grid.
  • Default  m: Two seconds of lookahead at 0.4 m/s provides enough anticipation to handle the tight inner turns without cutting across them.
  • Curvature-scaled speed: Constant-speed Pure Pursuit cuts corners on high-curvature segments. Scaling by approximates the behaviour of a well-tuned trajectory planner without requiring a full kinodynamic solver.