Self-Driving Car Engineer Nanodegree Program
The goal of this project is to code a PID Controller in C++ to be able to drive a car around a track in Unity's simulator. Essentially I built the PID controller that computes the steering angle of the car, using the cross track error (CTE) and the velocity as inputs, and fine tuned the coefficients for each of three PID gains so that the car is able to autonomously drive around the track.
- Implement PID Controller for Steering
- Properly Initialize the PID
- Convert PID output to steering input
- Fine tune hyper-parameters for each PID coefficient
A video of the car driving autonomously around the track in the simulator (click to see the full video)
A proportional–integral–derivative controller (PID controller or three term controller) is a control loop feedback mechanism widely used in industrial control systems and a variety of other applications requiring continuously modulated control.
source: Aerospace Controls Laboratory @MIT
PID Controller consists of 3 terms, namely proportional (P), integral (I), and derivative (D) control. The output of the controller depends on how we tune the hyperparameters associated with each of these terms. The values of these hyperparameters are specific to each application; in this project they are optimized to allow a car drive smoothly around a test track in a simulator.
- steers the wheel in proportion to the Cross-Track Error (CTE), which measures the distance between the car and the center of the lane. This means that the further we are from the center of the lane, the harder the steering.
- If P coefficient is set too high, the car will oscillate a lot as it will constantly try to overcorrect and overshoot the middle of the lane.
- If P coefficient is too low, the car will steer too slow to curves when it gets off-center.
source: Aerospace Controls Laboratory @MIT
- it takes into account the Cross-Track Error Rate, or how fast the car is moving in perpendicular direction of the desired trajectory when off-centered.
- If we are perfectly following the trajectory, the derivative gain will be zero.
- Increasing P increases the pull that the vehicle feels towards the desired trajectory
- Increasing D increases the resistance of the car to move too quickly towards the line.
- If we set D too high, the car will be gin to chetter (vibrate at a higher frequency than the P gain oscillations).
- Properly choosing D coefficient will allow the car to approach the desired trajectory quickly with an error close to zero.
source: Aerospace Controls Laboratory @MIT
- It sums up all the CTEs to that point and preventing the car to spend too much time in one side of the lane or the other.
- If we set the I coefficient too high, the car will tend to show quicker oscillations.
- If we choose the I coefficient too low, the car will tend to drift to one side of the lane or the other for longer periods of time.
- Properly choosing I will allow the vehicle to quickly correct the misalignment and return to its nominal performance.
source: Aerospace Controls Laboratory @MIT
-
I manually tested different values for Kp, Kd and Ki coefficients over a few iterations and eventually choosing a combination of values that provided good results. My approach was to first start with all gains initialized to zero--the car drives and it crashes in the first curve. Then I gradually increased the value of P and the car started oscillating and crashing in the second curve. Once I reached Kp ~0.1, I start tweaking the value of D. I kept trying different values of P and D until the car showed a response to a disturbance (i.e: curvature) with steady oscillation that quickly goes away (critically damped). At this point, the car was able to drive autonomously one full track. I then applied a tiny value for I gain, which allowed a more quickly correction to the nominal performance of the car without much oscillation. The final values chosen are:
Kp = -0.1
Ki = -0.005
Kd = -1.6
-
I also tried implementing Twiddle algorithm, which automates the process of finding the optimal parameters. I ended up no using it as the resulting parameters tended to vary every time I ran it, and didn't appreciate an improvement in driving behavior compared to using the parameter values manually chosen in the previous phase.
-
(TODO) Apply PID for throttle
- cmake >= 3.5
- All OSes: click here for installation instructions
- make >= 4.1
- Linux: make is installed by default on most Linux distros
- Mac: install Xcode command line tools to get make
- Windows: Click here for installation instructions
- gcc/g++ >= 5.4
- Linux: gcc / g++ is installed by default on most Linux distros
- Mac: same deal as make - [install Xcode command line tools]((https://developer.apple.com/xcode/features/)
- Windows: recommend using MinGW
- uWebSockets == 0.13, but the master branch will probably work just fine
- Follow the instructions in the uWebSockets README to get setup for your platform. You can download the zip of the appropriate version from the releases page. Here's a link to the v0.13 zip.
- If you run OSX and have homebrew installed you can just run the ./install-mac.sh script to install this
- Simulator. You can download these from the project intro page in the classroom.
- Clone this repo.
- Make a build directory:
mkdir build && cd build
- Compile:
cmake .. && make
- Run it:
./pid
(using the pre-selected parameter values) or./pid kp ki kd
(where kd, ki and kd are the desired values for the parameters)