Skip to content

Commit

Permalink
Vehicle Steering Control using PID. Adding files for project submission
Browse files Browse the repository at this point in the history
  • Loading branch information
AhmedDesoky91 committed Sep 5, 2018
1 parent 27eea76 commit 4a4e164
Show file tree
Hide file tree
Showing 12 changed files with 13,515 additions and 2 deletions.
49 changes: 49 additions & 0 deletions .cproject
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="0.1570756881">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.1570756881" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration buildProperties="" description="" id="0.1570756881" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.1570756881." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1160039664" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.1160039664.1518819301" name=""/>
<builder id="org.eclipse.cdt.build.core.settings.default.builder.1499869261" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.677009479" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.1640990166" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1951982531" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.663409044" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1873477790" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1012831861" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1627184704" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="Vehicle-Steering-Control-using-PID-Controller.null.983217834" name="Vehicle-Steering-Control-using-PID-Controller"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="0.1570756881">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>
27 changes: 27 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Vehicle-Steering-Control-using-PID-Controller</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>
26 changes: 26 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
project(PID)

cmake_minimum_required (VERSION 3.5)

add_definitions(-std=c++11)

set(CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "${CXX_FLAGS}")

set(sources src/PID.cpp src/main.cpp)

include_directories(/usr/local/include)
link_directories(/usr/local/lib)

if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

include_directories(/usr/local/opt/openssl/include)
link_directories(/usr/local/opt/openssl/lib)
link_directories(/usr/local/Cellar/libuv/1*/lib)

endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")


add_executable(pid ${sources})

target_link_libraries(pid z ssl uv uWS)
109 changes: 107 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,107 @@
# Vehicle-Steering-Control-using-PID-Controller
In this project, I have worked on a PID controller to control the vehicle's steering angle
# **Vehicle Control Using PID Controller**
---

**In this project, I have worked on a PID controller to control the vehicle's steering angle .**

## Project Introduction:
---
In this project, we are controlling the vehicle's steering angle to be within the road using one of the most common and fundamental controllers which is the PID (Proportional, Integral, Differtial) controller. For doing this, we use the Cross Track Error (CTE) which the lateral distance between the vehicle and the reference trajectory provided from the simulator to control the steering angle and have the vehicle in the road.


## Environment:
---
* Ubuntu 16.04 LTS
* Udacity Self-Driving Car Nano-Degree Term2 Simulator
* cmake >= 3.5
* make >= 4.1
* gcc/g++ >= 5.4

## Parameters Discussion
---
### Proportional Term (Kp)
The proportional term is simply multiplying a factor (constant) by the error value (CTE in our case) to compensate the drift happened in the steering angle due to this error (CTE).

The following equation summerizes the proportional term:
` steering_angle = - Kp * CTE`

Applying the proportional term (P-Controller) to the vehicle, it will act like this:
![p-controller](https://i.imgur.com/UcCq2Dm.png)
It will be overshooting overtime .. sometimes this overshooting will be slightly small and it may be OK, but even if it is small, it will never really converge, It will be what is called "marginally stable" or "stable"

We can consider this overshooting as oscillation for our control process. When Kp is large, the oscillation is faster, and vise versa.

### Differential Term (Kd)
The previous discussion turns to the P-term is usually is not enough due to the overshooting probelm and oscillation. The differential term allow to gracefully approach our target trajectory by having the steering angle not only proportional to the error itself, but also to the difference of the error using another factor (Kd).

**How we compute the derivative `d/dt CTE` ?**

`d/dt CTE = ( current_CTE - previosu_CTE ) / delta_t`

When `delta_t = 1` :
`d/dt CTE = current_CTE - previosu_CTE`


The following equation summerizes the PD-Controller:
`steering_agnle = - Kp * CTE - Kd * (CTE - previous_CTE)`

The following figure from my Udacilty lesson illustrates the impact of the D-term for having more smooth controller rather than P-controller only.
![PD-controller](https://i.imgur.com/LxTHRHm.png)

### Integral Term (Ki)
The integral term tackles problems what is called in robotics **Systematic Bias**. To explain this problem with an example related to our case, assume that you receive your car with wheels 100% aligned straight. But in reality due to some mechanical offsets and errors, they are not alighned. When running our controller, this error will accumulate over time turning to a big error in CTE

The following image illustraces the systematic bias:
![sys-bias](https://i.imgur.com/ycL1Sb2.png)
Even the controller is stable at the end (in blue), it far away from the set point we need to achieve (yellow)

The I-term solves for this problem by having the sum of all cross track errors you have ever observed. It will evetually correct the vehicle's motion

The following summerizes how we calculate the integral term:
`integral_CTE += CTE`

So, the final equation for having a PID controller:
`steering_angle = - Kp * CTE - Kd * (CTE - previous_CTE) - Ki * integral_CTE`


## Parameters Tuning (Kp, Ki, Kd)
---
I followed a manual approach for tuning the PID parameters.

I have followed the following strategy:
- Firstly and initially, for the integral term, the Systematic bias does not appear in simulation, so I set `Ki = 0.0`
- I started with setting the prortional term `Kp` with low values. I got the feeling that car is not that responsive (oscillation is very slow).
- Then I have increased the `Kp` with trial after another. Here I got to the car keeps oscillating
- Then I started introducing the `Kd` term to have a more smooth and graceful driving
- With many trial, I found the following:
- `Kp` values less than 0.9 get to very poor response to the car specially in curves
- `kp` is very acceptable in 0.1
- `kd` values less than 0.35 allow the propostional term to have dominant impact so the car still osciallting
- `kd` with high values (2.5, 3.0, .. ) are Ok in sometimes but it gave me the feeling of continuous smooting for steeting so I felt that it is not safe driving

**Parameters Tuning Conclusion:**

- I found `Kp = 0.11` and `kd = 0.47` achieves one of the best safe driving for parameters tuning.
- Yes, it may be two times the car touches the ledges, but on the other hand the car was moving very smoothly and gracefully all over the track with very acceptable performace.
- The following video is a demo for my project, [here](https://youtu.be/hOGo_fkgdsE)

## Running the Code
---
This project involves the Term 2 Simulator which can be downloaded [here](https://github.com/udacity/self-driving-car-sim/releases)


This repository includes two files that can be used to set up and install uWebSocketIO for either Linux or Mac systems. For windows you can use either Docker, VMware, or even Windows 10 Bash on Ubuntu to install uWebSocketIO.

Once the install for uWebSocketIO is complete, the main program can be built and ran by doing the following from the project top directory.

1. mkdir build
2. cd build
3. cmake ..
4. make
5. ./pid

## Conclusion
---
* The PID controller is on the common and fundametal controllers that can be used in for controlling the vehicle steering and brakes.
* PID parameters tuning needs a lot of intution and understanding of them impact.
* There are some methods to tune these parameters automatically rather than manually, for example the twiddle (or coordinate ascent) algorithm. It may be a furhter improvement for my project to use on of these algorithms for parameters tuning.

21 changes: 21 additions & 0 deletions cmakepatch.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--- CMakeLists.txt 2017-03-23 20:58:47.000000000 +0900
+++ CMakeListsnew.txt 2017-03-23 20:57:33.000000000 +0900
@@ -32,10 +32,16 @@
target_link_libraries (uWS LINK_PUBLIC ${OPENSSL_CRYPTO_LIBRARY})
target_link_libraries (uWS LINK_PUBLIC ${ZLIB_LIBRARY})

-if (UNIX)
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_link_libraries (uWS LINK_PUBLIC pthread)
install (TARGETS uWS DESTINATION /usr/lib64)
install (FILES src/Extensions.h src/WebSocketProtocol.h src/Networking.h src/WebSocket.h src/Hub.h src/Group.h src/Node.h src/Socket.h src/HTTPSocket.h src/uWS.h src/uUV.h DESTINATION /usr/include/uWS)
-endif (UNIX)
+endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+target_link_libraries (uWS LINK_PUBLIC pthread)
+install (TARGETS uWS DESTINATION /usr/local/lib)
+install (FILES src/Extensions.h src/WebSocketProtocol.h src/Networking.h src/WebSocket.h src/Hub.h src/Group.h src/Node.h src/Socket.h src/HTTPSocket.h src/uWS.h src/uUV.h DESTINATION /usr/local/include/uWS)
+endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

add_subdirectory(examples)
15 changes: 15 additions & 0 deletions install-mac.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
brew install openssl libuv cmake
git clone https://github.com/uWebSockets/uWebSockets
cd uWebSockets
git checkout e94b6e1
patch CMakeLists.txt < ../cmakepatch.txt
mkdir build
export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
cd build
OPENSSL_VERSION=`openssl version -v | cut -d' ' -f2`
cmake -DOPENSSL_ROOT_DIR=$(brew --cellar openssl)/$OPENSSL_VERSION -DOPENSSL_LIBRARIES=$(brew --cellar openssl)/$OPENSSL_VERSION/lib ..
make
sudo make install
cd ..
cd ..
sudo rm -r uWebSockets
15 changes: 15 additions & 0 deletions install-ubuntu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#! /bin/bash
sudo apt-get update
sudo apt-get install git libuv1-dev libssl-dev gcc g++ cmake make
git clone https://github.com/uWebSockets/uWebSockets
cd uWebSockets
git checkout e94b6e1
mkdir build
cd build
cmake ..
make
sudo make install
cd ..
cd ..
sudo ln -s /usr/lib64/libuWS.so /usr/lib/libuWS.so
sudo rm -r uWebSockets
31 changes: 31 additions & 0 deletions set_git.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

# Make sure you have the latest version of the repo
echo
git pull
echo

# Ask the user for login details
read -p 'Git repository url: ' upstreamVar
read -p 'Git Username: ' userVar
read -p 'Git email: ' emailVar

echo
echo Thank you $userVar!, we now have your credentials
echo for upstream $upstreamVar. You must supply your password for each push.
echo

echo setting up git

git config --global user.name $userVar
git config --global user.email $emailVar
git remote set-url origin $upstreamVar
echo

echo Please verify remote:
git remote -v
echo

echo Please verify your credentials:
echo username: `git config user.name`
echo email: `git config user.email`
42 changes: 42 additions & 0 deletions src/PID.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "PID.h"
#include <iostream>
#include <numeric>
#include <math.h>



using namespace std;

/*
* TODO: Complete the PID class.
*/

PID::PID() {}

PID::~PID() {}

void PID::Init(double Kp, double Ki, double Kd) {
PID::Kp = Kp;
PID::Ki = Ki;
PID::Kd = Kd;

p_error = 0.0;
i_error = 0.0;
d_error = 0.0;
}

void PID::UpdateError(double cte) {
static double previous_cte = cte;

p_error = cte;
d_error = cte - previous_cte;
i_error += cte;

previous_cte = cte;

}

double PID::TotalError() {
return 0.0;
}

48 changes: 48 additions & 0 deletions src/PID.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef PID_H
#define PID_H
#include <vector>

class PID {
public:
/*
* Errors
*/
double p_error;
double i_error;
double d_error;

/*
* Coefficients
*/
double Kp;
double Ki;
double Kd;


/*
* Constructor
*/
PID();

/*
* Destructor.
*/
virtual ~PID();

/*
* Initialize PID.
*/
void Init(double Kp, double Ki, double Kd);

/*
* Update the PID error variables given cross track error.
*/
void UpdateError(double cte);

/*
* Calculate the total PID error.
*/
double TotalError();
};

#endif /* PID_H */
Loading

0 comments on commit 4a4e164

Please sign in to comment.