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']}")