EurekaMoments

This blog is to make a memo about Programming and Autonomous driving technologies which I studied.

Python sample program of Path tracking simulation with Pure pursuit algorithm

Introduction

Path tracking technology is to track a course which is generated with a path planning algorithm. In this entry, I'm introducing a summary and Python sample program of Pure pursuit algorithm which is the most basic and is widely used for Autonomous navigation.

Table of contents

Source code at GitHub

All source codes are located at the following GitHub repository.

Pure pursuit controller module
github.com

Path tracking simulation
github.com

Pure pursuit algorithm

Pure pursuit is the most basic path tracking algorithm. It computes the angular velocity command that moves the vehicle from its current position to reach some look-ahead point in front of the vehicle. If you want to know the algorithm in detail, please refer to the following links.

https://www.ri.cmu.edu/pub_files/pub3/coulter_r_craig_1992_1/coulter_r_craig_1992_1.pdf

www.youtube.com

Look-ahead distance

The look-ahead distance is how far along the course the vehicle should look from the current position to compute the angular velocity command.

This distance can be defined as a parameter and affect the path tracking performance. If the distance was small, it will cause the vehicle to move quickly towards the course. However, the vehicle will overshoot the course and oscillate along it. The distance can be larger to reduce the oscillations, but it will result in larger curvatures near the corners.

Angular velocity computation

Firstly, a target point on the course is decided based on the look-ahead distance. And then, the heading error between the current position and the target point can be computed as follow.

Secondly, the turning radius towards the target point can be computed as follow.

Finally, the angular velocity command to follow the course can be computed based on the turning radius and the forward velocity.

Implementation of Python program

1. Controller module class

A controller module class of Pure pursuit algorithm as follow. This class has the following 5 parameters for computing the angular velocity command.

  • Minimum look-ahead distance[m]
  • Look forward gain
  • Speed proportional gain
  • Wheel base of vehicle[m]
  • Color for drawing target point

Minimum look-ahead distance is used to limit the distance decreasing. Look forward gain is used for changing the distance based on the current velocity. Speed proportional gain is used for computing the forward acceleration command with simple P control algorithm. Wheel base of vehicle is used for computing the angular velocity command as the parameter of the vehicle. Color for drawing target point is used for drawing the decided target point based on the look-ahead distance on the reference course.

"""
pure_pursuit_controller.py

Author: Shisato Yano
"""

from math import sin, tan, atan2


class PurePursuitController:
    """
    Controller class by Pure Pursuit algorithm
    """
    
    def __init__(self, spec, course=None, color='g'):
        """
        Constructor
        spec: Vehicle specification object
        course: Course data and logic object
        color: Color of drawing target point
        """
        
        self.MIN_LOOK_AHEAD_DISTANCE_M = 2.0
        self.LOOK_FORWARD_GAIN = 0.3
        self.SPEED_PROPORTIONAL_GAIN = 1.0
        self.WHEEL_BASE_M = spec.wheel_base_m
        self.DRAW_COLOR = color

        self.course = course
        self.look_ahead_distance_m = self.MIN_LOOK_AHEAD_DISTANCE_M
        self.target_course_index = 0
        self.target_accel_mps2 = 0.0
        self.target_speed_mps = 0.0
        self.target_steer_rad = 0.0
        self.target_yaw_rate_rps = 0.0

2. Computation of Look-ahead distance

A function to compute the look-ahead distance is implemented as follow. The distance can be changed dynamically based on the current forward velocity of the vehicle. This is to make the path tracking more stable.

    def _calculate_look_ahead_distance(self, state):
        """
        Private function to calculate look ahead distance to target point
        state: Vehicle's state object
        """
        
        self.look_ahead_distance_m = self.LOOK_FORWARD_GAIN * state.get_speed_mps() + self.MIN_LOOK_AHEAD_DISTANCE_M

3. Decision of Target point on Course

A function to decide the target point on the reference course is implemented as follow. The target point is located at the nearest distance from the current position of the vehicle and it is more far than the computed look-ahead distance.

    def _calculate_target_course_index(self, state):
        """
        Private function to calculate target point's index on course
        state: Vehicle's state object
        """
        
        nearest_index = self.course.search_nearest_point_index(state)
        while self.look_ahead_distance_m > self.course.calculate_distance_from_point(state, nearest_index):
            if nearest_index + 1 >= self.course.length(): break
            nearest_index += 1
        self.target_course_index = nearest_index

4. Computation of Forward acceleration command

The functions to compute the forward acceleration are implemented as follow. The velocity is controlled with simple P control algorithm. The difference of the velocity between the current velocity and target velocity is computed and the acceleration is computed based on the difference towards the target velocity. The target velocity is given from the reference course data.

    def _decide_target_speed_mps(self):
        """
        Private function to decide target speed[m/s]
        """
        
        self.target_speed_mps = self.course.point_speed_mps(self.target_course_index)

    def _calculate_target_acceleration_mps2(self, state):
        """
        Private function to calculate acceleration input
        state: Vehicle's state object
        """

        diff_speed_mps = self.target_speed_mps - state.get_speed_mps()
        self.target_accel_mps2 = self.SPEED_PROPORTIONAL_GAIN * diff_speed_mps

5. Computation of Angular velocity command

Firstly, a function to compute the steering angle command is implemented. The steering angle command can be computed based on the following equation.

    def _calculate_target_steer_angle_rad(self, state):
        """
        Private function to calculate steering angle input
        state: Vehicle's state object
        """
        
        diff_angle_rad = self.course.calculate_angle_difference_rad(state, self.target_course_index)
        self.target_steer_rad = atan2((2 * self.WHEEL_BASE_M * sin(diff_angle_rad)), self.look_ahead_distance_m)

Finally, a function to compute the angular velocity command is implemented as follow. The angular velocity command can be computed based on the steering angle command following the kinematic model of the vehicle.

    def _calculate_target_yaw_rate_rps(self, state):
        """
        Private function to calculate yaw rate input
        state: Vehicle's state object
        """

        self.target_yaw_rate_rps = state.get_speed_mps() * tan(self.target_steer_rad) / self.WHEEL_BASE_M

6. Sequence of computation

The above implemented functions are executed as follow. The current state of the vehicle is given to the functions. If any reference course data was not given to the controller module, the process of computation is can not be executed.

    def update(self, state, time_s):
        """
        Function to update data for path tracking
        state: Vehicle's state object
        time_s: Simulation interval time[sec]
        """
        
        if not self.course: return

        self._calculate_look_ahead_distance(state)
        
        self._calculate_target_course_index(state)

        self._decide_target_speed_mps()

        self._calculate_target_acceleration_mps2(state)

        self._calculate_target_steer_angle_rad(state)

        self._calculate_target_yaw_rate_rps(state)

Path tracking simulation

The path tracking simulation with the above controller module can be executed as follow. The green point on the course is the decided target point based on the current forward velocity. And then, the angular velocity command towards the target point and the vehicle can track the course based on the command. However, the lateral error of the vehicle towards the course still looks like be large around the corners because Pure pursuit algorithm assume that the vehicle approaches the target point following turning behavior.