Genetic Programming for Racing Line Optimization- Part 1

Introduction to the problem and attempts thus far

Joe Auckley
Adventures in Autonomous Vehicles

--

The optimal racing line is the path around a track that allows the racer to traverse the course in the minimum time possible. Competitive racing drivers strive to perceive this optimal trajectory and stick to it the best they can. I’ve decided to implement various ways to compute this optimal path as well as the ideal speed at each point for the F1/10 cars, given a bird’s eye view of the track’s boundaries.

The result of 50 generations of a genetic algorithm- the racing line turns close to the apexes of both turns

Problem Overview

The optimal racing line is neither the shortest path around a track nor the path with the highest average velocity. To solve this problem, I am searching over many potential paths and evaluating them by finding the fastest possible velocity profile (velocity at each point on the path) and then computing the time to traverse the path. To search for paths, I computed sampling boxes throughout the track that cover the entirety of the track’s feasible space. (Note- I’m using an adaptation of OpenAi Gym’s random track generator)

Sampling boxes generated for a given track (black lines), shown in pixel space
Close up of sampling boxes around a curve- nearly every spot on the track is in a box

I randomly select a point in each box and fit a cubic spline to the array of points. I then check every point on the spline to see if it is inside the track (valid) or on one of the black track lines (invalid). Invalid tracks are rejected. I experimented with combining boxes on the straightaways to decrease the dimension of the search space, but found that this decreases the chance of randomly generating a valid spline- as bad as 1 in 100. After experimenting with the smoothing factor of the spline (best found was 0.25) I am able to obtain a valid spline once in every 3.62 random samples, despite the substantial overlap between boxes.

Now that I’ve described my sampling method, I’ll explain the approach I’ve tried so far. These sampling boxes may seem a bit elaborate for standard genetic programming, but I made them with several approaches to this problem in mind, so it should be useful later on as well.

A cubic spline (blue) made from randomly sampled input points (orange) with a smoothness factor of 0.25

Genetic Programming

To start, I’ve explored various genetic algorithms for optimization problems. A genetic algorithm is an iterative algorithm inspired by natural selection, where an initial population of solutions is evolved to optimize some criterion. A fitness function must be defined to evaluate the solutions- this is usually the objective function of the optimization problem. Each iteration, the “fittest” members of the population are selected to be the basis of the next generation. The features of the fittest solutions are combined (like genes) through a crossover operation and mutated stochastically to form a new set of solutions. There are many ways to define the fitness function, selection process, and crossover and mutator operations, which is explored in the field of genetic programming. More on these concepts linked in a good read here.

CMA-ES

I decided to start with implementing the Covariance-Matrix Adaptation Evolution Strategy (CMA-ES). A good description of this algorithm (and others) is covered here. In short, the algorithm adaptively adjusts the search space depending on the variance of the “fit” members of the population from the rest of the population. So, when the best solutions in the population are far from the generation’s mean, the variance for the next generation is increased, and vice versa.

My Implementation

The fitness function I am using is just the time to traverse the track. To calculate this, I needed to compute the velocity profile for the given path. For now, I’m using a simple method using the instantaneous radius of curvature at each point of the spline. I calculate this using the equation for a parametric curve described here. I then calculated the fastest possible speed using the radius of curvature, maximum lateral gripping force (downforce multiplied by coefficient of friction), and mass of the car, and capped the speed at a maximum value. The resulting velocity profile is very jagged and not physically possible — it needs to be adjusted for the amount of acceleration and braking that the car can actually provide.
For selection, I am selecting the top 25% of the current generation to be the basis for the next generation, and I implemented mutation and crossover in the standard CMA-ES fashion. Lastly, I’m using a population size of 100, and it stops computing new generations after 50 generations.

Results

As an easy benchmark, I generated 10000 random feasible splines and calculated statistics based off their performance:
Average time: 20.852 seconds
Fastest time: 18.956 seconds
Slowest time: 25.646 seconds
Standard deviation of times: 0.751 seconds

I ran my implementation of CMA-ES 100 times, and calculated statistics based off the last generation of each trial:
Average mean time: 18.632 seconds
Average fastest time: 18.628 seconds
Average slowest time: 18.683 seconds
Average standard deviation: 0.0129 seconds

The fastest spline of the last generation of 100 trials of CMA-ES

The last generation of my CMA-ES is on average entirely faster than the 1 in 10000 spline by nearly 3 tenths of a second (which is a long time in racing). However, there is still room for improvement. The CMA-ES algorithm is pretty good at finding the global optimum, however in this nearly 200 dimensional space, it has not been able to do so. This image shows that it converges to a variety of local optima.

Here are images from a particularly good output from the algorithm, which was evaluated at just 18.482 seconds:

Best (left) and average (right) time of current generation, orange line is fastest time in 10000 spline sampling
Velocity profile (left) and the solution path (right) where yellow is high velocity and purple is low

From these images, you can see that the algorithm converges very quickly. However, the path is still a ways from being globally optimal, as it still does not entirely hug the apexes as expected and make full use of the track’s width on the straights. Also, you can see how the velocity profile is far from physically possible.

Next Steps

  • More realistic dynamics: The velocity profile needs to be corrected using details about the car’s acceleration and braking, and I need to reject spline samples that contain a turning radius less than the car is capable of
  • Tune parameters: Changing parameters like population size, generation number, and population selection cutoff could improve results
  • Get out of local optima: A feature of this algorithm is that the population’s diversity decreases quickly as it converges to a solution. If that solution is not globally optimal, we want to maintain diversity. One way to do that is to cluster solutions into “species” and keep a portion of each species between generations, and I will be exploring this approach
  • Other approaches: I’m not planning on solely using CMA-ES on this problem- I am reading about other genetic algorithms and will implement a few more to see what works best

Stay tuned to the F1/10 blog for updates!

--

--

Joe Auckley
Adventures in Autonomous Vehicles

Robotics Masters student and Autonomous Vehicle researcher at the University of Pennsylvania.