{"id":17180944,"url":"https://github.com/awav/pid-controller","last_synced_at":"2025-07-04T03:36:18.501Z","repository":{"id":91468932,"uuid":"96467115","full_name":"awav/pid-controller","owner":"awav","description":"Implementation of Proportional–Integral–Derivative (PID) controller for Self-Driving-Car steering angle","archived":false,"fork":false,"pushed_at":"2017-07-08T20:08:47.000Z","size":77779,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-30T03:15:32.969Z","etag":null,"topics":["pid","sdc","self-driving-car","steering-angles"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/awav.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-06T19:57:04.000Z","updated_at":"2020-09-12T13:33:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"06b75f09-d0aa-4d35-81a6-3ea82fa4ceed","html_url":"https://github.com/awav/pid-controller","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awav%2Fpid-controller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awav%2Fpid-controller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awav%2Fpid-controller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awav%2Fpid-controller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/awav","download_url":"https://codeload.github.com/awav/pid-controller/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245377961,"owners_count":20605375,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pid","sdc","self-driving-car","steering-angles"],"created_at":"2024-10-15T00:32:22.974Z","updated_at":"2025-03-25T00:42:04.703Z","avatar_url":"https://github.com/awav.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"PID Controller\n===\n\n![Alt Text](data/sdc-car.gif)\n\n### Introduction\n\nPID controller or Proportional–Integral–Derivative controller is a control loop mechanism. It calculates an cross-track error or controller error `e(t)` of a target state value `u(t)` and measured state value `m(t)` as `e(t) = u(t) - m(t)`. The result of PID controller is output . Sometimes PID controller is named as PSD or proportional-summation-difference, because algorithm calculates integral as summation of errors over `t` and derivative as difference between previous error and current one.\n\n### Terms\n\n![Alt Text](data/pid-equation.png)\n\n* **Proportion term**. The proportion term defines direction and how fast the algorithm should compensate the error. It is easy to overshoot using only this gain and as a result the control output oscillates around target value. The proportion parameter `Kp` is non-negative number.\n* **Integral term**. Integral gain addresses how long and how far measured value has been from the goal. The integral term sums error `e(t)`. If even a small error persists, the total sum will grow and influence the control output. The integral parameter `Ki` is non-negative number.\n* **Derivative term**. The derivative term, in fact, irons the oscillation made by proportion term. More precisely, it represents how fast the error is changin at current moment. Employing error changing rate, the derivative term alleviates overshooting caused by proportion term. The derivative `Kd` parameter is non-negative number.\n\n### Tuning\n\nNowadays plenty number of algorithms are available for tuning PID controller coefficients. Moreover, some approaches provide auto-tuning properties, thereafter the PID controller can be adjusted in real time depending on magnitude of the cross-track error. You can find auto-tuning PID implementations [here](http://uk.mathworks.com/matlabcentral/fileexchange/4652-autotunerpid-toolkit?requestedDomain=www.mathworks.com) or [here](http://playground.arduino.cc/Code/PIDLibrary).\n\nI started with Twiddle algorithm which was advertised in Udacity course as simple and stable. I was not satisfied with final results, because it was even very bad as a starting point for parameters in further hand-crafting.\n\nI set eyes on [Ziegler–Nichols method](https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method) discovered back in 1949. It has even more simple and precise rules to achieve efficient and semi-optimal values of coefficients. Here they are:\n\n1. Turn off **I** and **D** terms. In other words set `Ki = 0` and `Kd = 0`.\n2. Set `Kp = 0` and increase it slowly until the control output exhibits sustained oscillations. At this step we get our critical proportion gain. In my case, I increased value manually from _0_ to _0.5_ with interval _0.1_ and stopped at _0.3_.\n3. **ZN** method also requires to cast period of time. I set up it to _100ms_.\n4. Turn on **I** and **D** components by using values from **ZN** table: `Kp = 0.6 * critical_gain = 0.18`, `Ki = 0.5 * time_period = 50` and `Kd = 0.13 * time_period = 13`.\n\nI used this values as starting point for further hand-craft tuning. I noticed that PID controller doesn't react at all if integral component is set to zero, so I concluded that steering angle is free from bias and assigned small value _0.00001_ to it. The final coefficients I have got: `Kp = 0.1`, `Ki = 0.00001` and `Kd = 1.45`. But through it all, the car had sudden and quick movements, especially on turns. When added [exponential smoothing](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) to PID control output, the bizarre discrete car turns almost disappeared.\n\n[Video](https://drive.google.com/open?id=0B90SlGxx-BAeZjlTZEd5a0dHczQ) how car finishes track successfully.\n\n### Experiments\n\nYou can see below some experiments with changing P, I, and D parameters. Initial optimized values were `P = 0.1`, `I = 0.00001`, `D = 1.45`:\n\n* Effect of P component. Changed from _0.1_ to _1_. Oscillation increases overtime leading to loosing control and to the crash in the end.\n\n![Alt Text](data/sdc-p.gif)\n\n* Effect of I component. Changed from _0.00001_ to _0.5_. It had kind of comic consequence. The car pulled off the road and made its way next to it.\n\n![Alt Text](data/sdc-i.gif)\n\n* Effect of D component. Changed from _1.45_ to _20_. Whatever value I tried car always could finish the racetrack. Output control oscillation is around irrespective our senses. No matter how smoothly car is moving, output wiggles near to setpoint (target value). High D component hardly tries to balance \"micro\" error, but instead we observe car shaking on the road.\n\n![Alt Text](data/sdc-d.gif)\n\n### Build and run project:\n\n```\n$ ./build.sh\n$ ./run.sh\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawav%2Fpid-controller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fawav%2Fpid-controller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawav%2Fpid-controller/lists"}