{"id":770,"date":"2011-04-15T15:05:36","date_gmt":"2011-04-15T19:05:36","guid":{"rendered":"http:\/\/brettbeauregard.com\/blog\/?p=770"},"modified":"2025-03-22T06:51:57","modified_gmt":"2025-03-22T10:51:57","slug":"improving-the-beginners-pid-onoff","status":"publish","type":"post","link":"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-onoff\/","title":{"rendered":"Improving the Beginner\u2019s PID: On\/Off"},"content":{"rendered":"<p><small>(This is Modification #5 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>As nice as it is to have a PID controller, sometimes you don&#8217;t care what it has to say.<\/p>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BadForcedOutput.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BadForcedOutput.png\" alt=\"\" title=\"BadForcedOutput\" width=\"336\" height=\"362\" class=\"aligncenter size-full wp-image-988\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BadForcedOutput.png 336w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BadForcedOutput-278x300.png 278w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><\/a><br \/>\nLet&#8217;s say at some point in your program you want to force the output to a certain value (0 for example)  you could certainly do this in the calling routine:<\/p>\n<p>void loop()<br \/>\n{<br \/>\nCompute();<br \/>\nOutput=0;<br \/>\n}<\/p>\n<p>This way, no matter what the PID says, you just overwrite its value.  This is a terrible idea in practice however.  The PID will become very confused: &#8220;I keep moving the output, and nothing&#8217;s happening!  What gives?!  Let me move it some more.&#8221;    As a result, when you stop over-writing the output and switch back to the PID, you will likely get a huge and immediate change in the output value.<\/p>\n<h3>The Solution<\/h3>\n<p>The solution to this problem is to have a means to turn the PID off and on.  The common terms for these states are &#8220;Manual&#8221; (I will adjust the value by hand) and &#8220;Automatic&#8221; (the PID will automatically adjust the output).  Let&#8217;s see how this is done in code:<\/p>\n<h3>The Code<\/h3>\n<pre class=\"brush: css; gutter: true; highlight: [8,10,11,15,71,72,73,74]; title: ; notranslate\" title=\"\">\n\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  inAuto = (Mode == AUTOMATIC);\n}\n\n<\/pre>\n<p>A fairly simple solution.  If you&#8217;re not in automatic mode, immediately leave the Compute function without adjusting the Output or any internal variables.<\/p>\n<h3>The Result<\/h3>\n<p><a href=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BetterForcedOutput.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BetterForcedOutput.png\" alt=\"\" title=\"BetterForcedOutput\" width=\"336\" height=\"362\" class=\"aligncenter size-full wp-image-989\" srcset=\"http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BetterForcedOutput.png 336w, http:\/\/brettbeauregard.com\/blog\/wp-content\/uploads\/2011\/03\/BetterForcedOutput-278x300.png 278w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><\/a><br \/>\nIt&#8217;s true that you could achieve a similar effect by just not calling Compute from the calling routine, but this solution keeps the workings of the PID contained, which is kind of what we need.  By keeping things internal we can keep track of which mode were in, and more importantly it let&#8217;s us know when we change modes. That leads us to the next issue&#8230;<br \/>\n<a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginner\u2019s-pid-initialization\">Next >><\/a><br \/>\n<br \/>\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 #5 in a larger series on writing a solid PID algorithm) The Problem As nice as it is to have a PID controller, sometimes you don&#8217;t care what it has to say. Let&#8217;s say at some point &hellip; <a href=\"http:\/\/brettbeauregard.com\/blog\/2011\/04\/improving-the-beginners-pid-onoff\/\">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-770","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\/770","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=770"}],"version-history":[{"count":40,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/770\/revisions"}],"predecessor-version":[{"id":7249,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/posts\/770\/revisions\/7249"}],"wp:attachment":[{"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/media?parent=770"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/categories?post=770"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/brettbeauregard.com\/blog\/wp-json\/wp\/v2\/tags?post=770"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}