{"id":1893,"date":"2012-01-28T14:41:56","date_gmt":"2012-01-28T18:41:56","guid":{"rendered":"http:\/\/brettbeauregard.com\/blog\/?p=1893"},"modified":"2024-06-03T15:50:45","modified_gmt":"2024-06-03T19:50:45","slug":"arduino-pid-autotune-library","status":"publish","type":"post","link":"http:\/\/brettbeauregard.com\/blog\/2012\/01\/arduino-pid-autotune-library\/","title":{"rendered":"Arduino PID Autotune Library"},"content":{"rendered":"<p>At long last, I&#8217;ve released an <a href=\"http:\/\/arduino.cc\/playground\/Code\/PIDAutotuneLibrary\">Autotune Library<\/a> to compliment the <a href=\"http:\/\/arduino.cc\/playground\/Code\/PIDLibrary\">Arduino PID Library<\/a>. When I released the current version of the PID Library, I did an insanely extensive <a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-introduction\/\">series of posts<\/a> to get people comfortable with what was going on inside. <\/p>\n<p>While not nearly as in-depth, that&#8217;s the goal of this post.  I&#8217;ll explain what the Autotune Library is trying to accomplish, and how it goes about its business.<br \/>\n<!--more--><\/p>\n<h3> Attribution <\/h3>\n<p>For A couple years I&#8217;ve wanted to have an Autotune Library, but due to an agreement with my employer, I wasn&#8217;t able to write one.  BUT! when I found the <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/4652-autotunerpid-toolkit\">AutotunerPID Toolkit<\/a> by William Spinelli I was good to go; My company had no problem with me porting and augmenting and existing open source project. <\/p>\n<p>I converted the code from matlab, made some tweaks to the peak identification code, and switched it from the Standard form (Kc, Ti, Td) to the Ideal form (Kp, Ki, Kd.)  Other than that, all credit goes to Mr. Spinelli.<\/p>\n<h3>The Theory<\/h3>\n<p>The best tuning parameters (Kp, Ki, Kd,) for a PID controller are going to depend on what that controller is driving.  The best tunings for a toaster oven are going to be different than the best tunings for a sous-vide cooker.<\/p>\n<p>Autotuners attempt to figure out the nature of what the controller is driving, then back-calculate tuning parameters from that.  There are various methods of doing this, but most involve changing the PID Output in some way then observing how the Input responds.  <\/p>\n<p>The method used in the library is known as the relay method. here&#8217;s how it works:<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/00-ideal.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/00-ideal.png\" alt=\"\" title=\"00-ideal\" width=\"451\" height=\"453\" class=\"alignnone size-full wp-image-1964\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/00-ideal.png 451w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/00-ideal-150x150.png 150w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/00-ideal-298x300.png 298w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/p>\n<p>Starting at steady state (both Input and Output are steady,) the Output is stepped in one direction by some distance D. When the Input crosses a trigger line, the output changes to the other direction by distance D.  <\/p>\n<p>By analyzing how far apart the peaks are, and how big they are in relation to the output changes, the Autotuner can tell the difference between one type of process and another.  As a result, different systems will get custom tuning parameters:<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/01-Correlations.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/01-Correlations.png\" alt=\"\" title=\"01-Correlations\" width=\"399\" height=\"81\" class=\"aligncenter size-full wp-image-1966\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/01-Correlations.png 399w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/01-Correlations-300x60.png 300w\" sizes=\"auto, (max-width: 399px) 100vw, 399px\" \/><\/a><\/p>\n<h2>The Implementation<\/h2>\n<p>  This works well in theory, but real-world data isn&#8217;t very cooperative.  The input signal is usually noisy, which causes two main problems.<\/p>\n<h3>Problem #1: When to step?<\/h3>\n<p> Since a noisy signal is choppy, it&#8217;s likely that the trigger line will be crossed several times as the Input moves past it.  This can cause mild chatter in the output, or if severe, can completely destroy things:<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/02-noise.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/02-noise.png\" alt=\"\" title=\"02-noise\" width=\"450\" height=\"453\" class=\"aligncenter size-full wp-image-1970\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/02-noise.png 450w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/02-noise-150x150.png 150w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/02-noise-298x300.png 298w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/a><br \/>\nThe way I chose to side-step this issue was to have the user specify a noise band.  In effect, this creates two trigger lines.  Since the distance between them is equal to the noise (if properly set) it&#8217;s less likely that multiple crossings will occur due to signal chatter.<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/03-noise-fixed.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/03-noise-fixed.png\" alt=\"\" title=\"03-noise fixed\" width=\"451\" height=\"453\" class=\"aligncenter size-full wp-image-1971\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/03-noise-fixed.png 451w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/03-noise-fixed-150x150.png 150w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/03-noise-fixed-298x300.png 298w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/p>\n<h3> Problem #2: Peak Identification<\/h3>\n<p>In a simulated world, identifying the peaks is easy: when the Input signal changes direction, that&#8217;s a minimum or a maximum (depending an which change occured.)  In a noisy world however,  this method fails:<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/04-peakID.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/04-peakID.png\" alt=\"\" title=\"04-peakID\" width=\"451\" height=\"289\" class=\"aligncenter size-full wp-image-1978\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/04-peakID.png 451w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/04-peakID-300x192.png 300w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/p>\n<p>Every noise blip is a direction change.  To deal with this issue I added a &#8220;look-back time&#8221; parameter.  It&#8217;s an awful name.  If you can think of something better let me know.<\/p>\n<p>At any rate, the user defines some window, say 10 seconds.  The Library then compares the current point to the last ten seconds of data.  If it is a min or a max, it gets flagged as a possible peak.<\/p>\n<p>When the flagged point switches from being a max to a min, or vice versa, the previously flagged point is confirmed as a peak.<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/05-peakIDfixed.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/05-peakIDfixed.png\" alt=\"\" title=\"05-peakIDfixed\" width=\"451\" height=\"289\" class=\"aligncenter size-full wp-image-1979\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/05-peakIDfixed.png 451w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2012\/01\/05-peakIDfixed-300x192.png 300w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/p>\n<p>Another way of explaining the look-back time is that a point will be identified as a peak if it is the largest (or smallest) value within one look-back into the future or past. Like I said: awful name.<\/p>\n<h2> You should also know&#8230; <\/h2>\n<ul>\n<li>The number of cycles performed will vary between 3 and 10.  The algorithm waits until the last 3 maxima have been within 5% of each other.  This is trying to ensure that we&#8217;ve reached a stable oscillation and there&#8217;s no external strangeness happening.  This leads me to&#8230;\n<\/li>\n<li>I&#8217;m not the biggest fan of Autotune.  I&#8217;ve often said, and still believe, that a moderately trained person will beat an Autotuner every day of the week.  There&#8217;s just so much that can go wrong without the algorithm knowing about it.  That being said, Autotune is a valuable tool to help the novice get into the ballpark.\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>At long last, I&#8217;ve released an Autotune Library to compliment the Arduino PID Library. When I released the current version of the PID Library, I did an insanely extensive series of posts to get people comfortable with what was going &hellip; <a href=\"http:\/\/brettbeauregard.com\/blog\/2012\/01\/arduino-pid-autotune-library\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31,7],"tags":[38,36,41],"class_list":["post-1893","post","type-post","status-publish","format-standard","hentry","category-coding","category-pid","tag-autotune","tag-ospid","tag-pid"],"_links":{"self":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/1893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/comments?post=1893"}],"version-history":[{"count":40,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/1893\/revisions"}],"predecessor-version":[{"id":7198,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/1893\/revisions\/7198"}],"wp:attachment":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/media?parent=1893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/categories?post=1893"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/tags?post=1893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}