Race Car Problem#

Mathematical Formulation#

Problem Statement#

Find the optimal throttle control \(\theta(t)\) that minimizes the lap time:

\[J = t_f\]

Subject to the dynamic constraints:

\[\frac{d\text{pos}}{dt} = \text{speed}\]
\[\frac{d\text{speed}}{dt} = \theta - \text{speed}\]

And the speed limit constraint:

\[\text{speed}(t) \leq 1 - \frac{1}{2}\sin(2\pi \cdot \text{pos}(t))\]

Boundary Conditions#

  • Initial conditions: \(\text{pos}(0) = 0\), \(\text{speed}(0) = 0\)

  • Final conditions: \(\text{pos}(t_f) = 1.0\), \(\text{speed}(t_f) = \text{free}\)

  • Control bounds: \(0 \leq \theta \leq 1\)

Physical Parameters#

  • Track length: \(L = 1.0\) (normalized)

  • Maximum throttle: \(\theta_{\max} = 1.0\)

State Variables#

  • \(\text{pos}(t)\): Position along track (normalized, 0 to 1)

  • \(\text{speed}(t)\): Vehicle speed

Control Variable#

  • \(\theta(t)\): Throttle input (0 = no throttle, 1 = full throttle)

Notes#

The speed limit varies sinusoidally along the track, representing curves where the car must slow down and straights where higher speeds are allowed.

Running This Example#

cd examples/race_car
python race_car.py

Code Implementation#

examples/race_car/race_car.py#
 1import casadi as ca
 2import numpy as np
 3
 4import maptor as mtor
 5
 6
 7# Problem setup
 8problem = mtor.Problem("Car Race")
 9phase = problem.set_phase(1)
10
11# Variables
12t = phase.time(initial=0.0)
13pos = phase.state("position", initial=0.0, final=1.0)
14speed = phase.state("speed", initial=0.0)
15throttle = phase.control("throttle", boundary=(0.0, 1.0))
16
17# Dynamics
18phase.dynamics({pos: speed, speed: throttle - speed})
19
20# Constraints
21speed_limit = 1 - ca.sin(2 * ca.pi * pos) / 2
22phase.path_constraints(speed <= speed_limit)
23
24# Objective
25problem.minimize(t.final)
26
27# Mesh and guess
28phase.mesh([8, 8, 8], np.array([-1.0, -0.3, 0.3, 1.0]))
29phase.guess(terminal_time=2.0)  # MUCH CLEANER!
30
31# Solve
32solution = mtor.solve_adaptive(
33    problem,
34    min_polynomial_degree=4,
35    max_polynomial_degree=8,
36    nlp_options={"ipopt.print_level": 0},
37)
38
39# Results
40if solution.status["success"]:
41    print(f"Lap time: {solution.status['objective']:.6f}")
42    solution.plot()
43else:
44    print(f"Failed: {solution.status['message']}")