{"id":772,"date":"2011-04-15T15:06:22","date_gmt":"2011-04-15T19:06:22","guid":{"rendered":"http:\/\/brettbeauregard.com\/blog\/?p=772"},"modified":"2025-03-22T06:52:41","modified_gmt":"2025-03-22T10:52:41","slug":"improving-the-beginners-pid-initialization","status":"publish","type":"post","link":"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-initialization\/","title":{"rendered":"Improving the Beginner\u2019s PID:  Initialization"},"content":{"rendered":"<p><small>(This is Modification #6 in a <a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-introduction\">larger series<\/a> on writing a solid PID algorithm)<\/small><\/p>\n<h3>The Problem<\/h3>\n<p>In the last section we implemented the ability to turn the PID off and on.  We turned it off, but now let&#8217;s look at what happens when we turn it back on:<br \/>\n<a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/NoInitialization.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/NoInitialization.png\" alt=\"\" title=\"NoInitialization\" width=\"336\" height=\"362\" class=\"aligncenter size-full wp-image-995\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/NoInitialization.png 336w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/NoInitialization-278x300.png 278w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><\/a><\/p>\n<p>Yikes!  The PID jumps back to the last Output value it sent, then starts adjusting from there.  This results in an Input bump that we&#8217;d rather not have.<\/p>\n<h3>The Solution<\/h3>\n<p>This one is pretty easy to fix.  Since we now know when we&#8217;re turning on (going from Manual to Automatic,) we just have to initialize things for a smooth transition.  That means massaging the 2 stored working variables (ITerm &#038; lastInput) to keep the output from jumping.<\/p>\n<h3>The Code<\/h3>\n<pre class=\"brush: css; gutter: true; highlight: [73,74,75,76,77,78,81,82,83,84,85,86,87]; title: ; notranslate\" title=\"\">\n\/*working variables*\/\nunsigned long lastTime;\ndouble Input, Output, Setpoint;\ndouble ITerm, lastInput;\ndouble kp, ki, kd;\nint SampleTime = 1000; \/\/1 sec\ndouble outMin, outMax;\nbool inAuto = false;\n\n#define MANUAL 0\n#define AUTOMATIC 1\n\nvoid Compute()\n{\n   if(!inAuto) return;\n   unsigned long now = millis();\n   int timeChange = (now - lastTime);\n   if(timeChange&gt;=SampleTime)\n   {\n      \/*Compute all the working error variables*\/\n      double error = Setpoint - Input;\n      ITerm+= (ki * error);\n      if(ITerm&gt; outMax) ITerm= outMax;\n      else if(ITerm&lt; outMin) ITerm= outMin;\n      double dInput = (Input - lastInput);\n\n      \/*Compute PID Output*\/\n      Output = kp * error + ITerm- kd * dInput;\n      if(Output&gt; outMax) Output = outMax;\n      else if(Output &lt; outMin) Output = outMin;\n\n      \/*Remember some variables for next time*\/\n      lastInput = Input;\n      lastTime = now;\n   }\n}\n\nvoid SetTunings(double Kp, double Ki, double Kd)\n{\n  double SampleTimeInSec = ((double)SampleTime)\/1000;\n   kp = Kp;\n   ki = Ki * SampleTimeInSec;\n   kd = Kd \/ SampleTimeInSec;\n}\n\nvoid SetSampleTime(int NewSampleTime)\n{\n   if (NewSampleTime &gt; 0)\n   {\n      double ratio  = (double)NewSampleTime\n                      \/ (double)SampleTime;\n      ki *= ratio;\n      kd \/= ratio;\n      SampleTime = (unsigned long)NewSampleTime;\n   }\n}\n\nvoid SetOutputLimits(double Min, double Max)\n{\n   if(Min &gt; Max) return;\n   outMin = Min;\n   outMax = Max;\n   \n   if(Output &gt; outMax) Output = outMax;\n   else if(Output &lt; outMin) Output = outMin;\n\n   if(ITerm&gt; outMax) ITerm= outMax;\n   else if(ITerm&lt; outMin) ITerm= outMin;\n}\n\nvoid SetMode(int Mode)\n{\n\tbool newAuto = (Mode == AUTOMATIC);\n\tif(newAuto &amp;&amp; !inAuto)\n\t{  \/*we just went from manual to auto*\/\n\t\tInitialize();\n\t}\n\tinAuto = newAuto;\n}\n\nvoid Initialize()\n{\n   lastInput = Input;\n   ITerm = Output;\n   if(ITerm&gt; outMax) ITerm= outMax;\n   else if(ITerm&lt; outMin) ITerm= outMin;\n}\n<\/pre>\n<p>We modified SetMode(&#8230;) to detect the transition from manual to automatic, and we added our initialization function.  It sets ITerm=Output to take care of the integral term, and lastInput = Input to keep the derivative from spiking.  The proportional term doesn&#8217;t rely on any information from the past, so it doesn&#8217;t need any initialization.<\/p>\n<h3>The Result<\/h3>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/Initialization.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/Initialization.png\" alt=\"\" title=\"Initialization\" width=\"336\" height=\"362\" class=\"aligncenter size-full wp-image-994\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/Initialization.png 336w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/Initialization-278x300.png 278w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><\/a><\/p>\n<p>We see from the above graph that proper initialization results in a bumpless transfer from manual to automatic: exactly what we were after.<br \/>\n<a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-direction\">Next >><\/a><\/p>\n<h3>Update: Why not ITerm=0?<\/h3>\n<p>I have been getting a lot of questions recently asking why I don&#8217;t set ITerm=0 upon intialization.  As an answer, I&#8217;d ask you to consider the following scenario:  The pid is in manual, and the user has set the output to 50.  After a time, the process steadies out to an input of 75.2.  The user makes the Setpoint 75.2 and turns on the pid.  What should happen?<\/p>\n<p>I contend that after switching to automatic the output value should stay at 50. since the P and D terms will be zero, the only way this will happen is if ITerm is initialized to the value of Output. <\/p>\n<p>If you are in a situation where you need the output to initialize to zero, there is no need alter the code above.  Just set Output=0 in your calling routine before turning the PID from Manual to Automatic.<\/p>\n<p>\n<a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/3.0\/\"><img decoding=\"async\" alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http:\/\/i.creativecommons.org\/l\/by-sa\/3.0\/80x15.png\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>(This is Modification #6 in a larger series on writing a solid PID algorithm) The Problem In the last section we implemented the ability to turn the PID off and on. We turned it off, but now let&#8217;s look at &hellip; <a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-initialization\/\">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":[6,30,41],"class_list":["post-772","post","type-post","status-publish","format-standard","hentry","category-coding","category-pid","tag-arduino","tag-beginners-pid","tag-pid"],"_links":{"self":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/772","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=772"}],"version-history":[{"count":56,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/772\/revisions"}],"predecessor-version":[{"id":7251,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/772\/revisions\/7251"}],"wp:attachment":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/media?parent=772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/categories?post=772"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/tags?post=772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}