Skip to content
PID Controller for Self-Driving Car ND
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


PID Controller for Self-Driving Car ND

Udacity - Self-Driving Car NanoDegree

PID Controller

Project Basics

The goal of this project is to implement in C++ a PID controller to control the steering angle for driving a car around a virtual track using the Udacity simulator, as well as tuning each PID gain in order to calculate a steering angle that keeps the car on the track.

The simulator provides cross-track error (CTE) via websocket. The PID (proportional-integral-differential) controller give steering commands to drive the car reliably around the simulator track.

Project Steps

  • Implement a PID Controller for steering the car
  • Optimize each PID gain to run the car smoothly around the track

Discussion / Reflection

Components of a PID controller

Using a PID controller is a great place to start because it is easy to understand, simple to implement, and efficient in a wide area of applications. However, making the controller to perform well in order to steer a car is a tough challenge. Hence, it is very important to understand how a PID works to tune it accordingly.

The PID controller is a feedback controller, which means that it senses/measures the system state and compared it to the desired goal. The difference between the two is the error or, in other words, the delta between where the car is and where we want it to be. In our case, the measured state is the car's position while the desired goal is the middle of the lane. The error is called the cross-track error (CTE). So, the goal of the PID controller is to convert the CTE into a steering command.

To reach its goal, the PID controller uses three components:

  • The "P" for proportional means that the PID produces a command proportional to the CTE. In other words, the car steers in proportion to the CTE. This makes sense because the PID is able to steer the car in the correct direction. If the car is on the right of the middle, then it would steer to the left to get closer to the middle. If the car is far from the middle, the PID would produce a higher steering angle. Higher is the CTE, stronger will be the steering command.

  • The "I" for integral sums up all CTE. It is used to remove constant CTE. No matter how small the constant CTE is, the summation of that contant CTE will be significant enough to adjust the controller output. In our case, it prevents the car from driving on one side of the lane the whole time by steering the car toward the middle.

  • The "D" for derivate is the change in CTE between the current measurement and the previous one. This means that, if the car is moving in the wrong direction (away from the middle) this will cause the steering angle to get larger (the "D" term is added to the "P" term), but if the car is getting closer to the middle the steering angle will get smoothed out (the "D" term is substracted to the "P" term) leading to a better driving experience. Besides, inside a curve, as the derivative is quickly changing it helps the car correct its steering angle faster.

These three components are summed together to produce the PID controller output. On top of that, a different gain parameter is associated with each component which are called Kp, Ki, and Kd.

steering_angle = - (Kp * P_term + Ki * I_term + Kd * D_term).

These gains can be tuned to run the car smoothly around the track.

Finding the right gains

The optimization algorithm called Twiddle has been used to automatically fine tune the PID gains. The car has been run for about 50 iterations using Twiddle, with a constant throttle value (0.3), to finally obtain the corresponding results: Kp: 0.30351, Ki: 0.00001, Kd: 2.66123.

I've also done some tests to control throttle using the steering angle value as follow throttle = (1 - abs(steering_angle)) * 0.5 + 0.3. Gains (Kp, Ki, and Kd) obtained from running Twiddle again with the throttle didn't converge to a satisfying result. Furthermore, adding two more parameters (Ka, and Kb) to Twiddle to tune, such as throttle = (1 - abs(steering_angle)) * Ka + Kb, takes too long to run before having good results.


Starting to work on this project consists of the following steps:

  1. Install uWebSocketIO and all the required dependencies
  2. Clone this repository
  3. Build the main program
    • mkdir build
    • cd build
    • cmake ..
    • make
  4. Launch ./pid [use_twiddle] [Kp] [Ki] [Kd]:
    • use_twiddle could be set to -1 to do not use Twiddle, or to any double value to set the max distance (~2000 for one lap)
    • Kp, Ki, and Kd could take any double values
  5. Launch the Udacity Term 2 simulator
  6. Enjoy!

Installation and Dependencies

This project involves the Udacity Term 2 Simulator which can be downloaded here

Other Important Dependencies

There's an experimental patch for windows in this PR.

Once all the dependencies have been installed clone the project:

git clone

and follow the steps 3 to 6 of the Overview section in order to build and run the main program.

Questions or Feedback

Contact me anytime for anything about my projects or machine learning in general. I'd be happy to help you 😉

You can’t perform that action at this time.