{"id":19138039,"url":"https://github.com/lemonpi/pid","last_synced_at":"2025-05-06T20:44:57.145Z","repository":{"id":27259742,"uuid":"30732220","full_name":"LemonPi/PID","owner":"LemonPi","description":"general PID control for volatile input (interrupt driven)","archived":false,"fork":false,"pushed_at":"2015-02-14T04:41:41.000Z","size":108,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-19T14:57:56.639Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LemonPi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-13T00:12:57.000Z","updated_at":"2021-04-17T09:01:28.000Z","dependencies_parsed_at":"2022-09-01T19:40:49.124Z","dependency_job_id":null,"html_url":"https://github.com/LemonPi/PID","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/LemonPi%2FPID","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LemonPi%2FPID/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LemonPi%2FPID/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LemonPi%2FPID/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LemonPi","download_url":"https://codeload.github.com/LemonPi/PID/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252769127,"owners_count":21801373,"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":[],"created_at":"2024-11-09T06:41:31.706Z","updated_at":"2025-05-06T20:44:57.120Z","avatar_url":"https://github.com/LemonPi.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PID\nGeneral PID control for volatile input (interrupt driven).\n\nBased on Brett Beauregard's [PID_V1 library](https://github.com/br3ttb/Arduino-PID-Library/),\nbut with a more efficient compute (mainly by getting rid of his liberal use of doubles).\n\n# Purpose\nWhen you have an input (PWM to an H-bridge) that affects an output (speed of wheel) that is subject to additional factors (different motor, different terrain, non-linearity of driving current to speed, different wheel size), some feedback from the actual output is required to modulate the input so the output meets target. One closed loop technique that's commonly used in industry because of its simplicity and effectiveness is a PID controller - modulation on instant proportional error, integral of error over time, and the rate change of error/derivative.\n\nAn example of a output response curve with the target velocity as a white line, actual velocity of left wheel as purple and right wheel as red, and with each PID cycle (set at 50ms) being 2 pixels wide:\n![example](http://imgur.com/GK4ILUi.png)\n# Instructions\nFor arduino users, place directory inside My Documents/Arduino/libraries\n```C++\n#include \u003cpid.h\u003e\n\n// volatile input (interrupt driven) that you want to listen to\nvolatile int tick_l = 0;\n// can use non-volatile, but need to remove all mention of volatile in the source\n\n// interrupt ISR\nvoid tick_left() {++tick_l;}\n\n\n// target of 100 ticks per PID cycle (100ms by default), for example from your rotary encoder\nint target_l = 100;\n\n// PWM output to adjust input level\nint motor_level = 0;\n\n// templated on input, setpoint, and output type\nPID\u003cint\u003e motor_control_left(tick_l, target_l, motor_level);\n\n// can be more specific and assign tuning parameters and output/input relations\nPID\u003cint\u003e motor_control_alt(tick_l, target_l, motor_level, 2.0, 0, 0.5, NEGATIVE);\n// negative relation means as output increases input should be expected to decrease\n\n\nvoid setup() {\n  // listen on pin 2 (interrupt 0, Arduino logic...) for a falling clockedge\n  attachInterrupt(0, tick_left, FALLING);\n\n  // start monitoring input and give output feedback\n  motor_control_left.start();\n  \n  // set cycle time to be 50ms = 20Hz (by default 100ms)\n  motor_control_left.set_cycle(50);\n  \n  // tune with different parameters\n  motor_control_left.tune(2.0, 0, 0.5);\n}\n\nvoid loop() {\n  \n  // simultaneously run PID and check if clock cycle occured\n  if (motor_control_left.compute()) {\n    // I don't recommend serially printing a volatile variable, use a temporary instead and clear right away\n    Serial.println(tick_l);\n    tick_l = 0;\n  }\n}\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonpi%2Fpid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemonpi%2Fpid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonpi%2Fpid/lists"}