Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed ros_lib_kinetic
PID.cpp
00001 /** 00002 * @author Aaron Berk 00003 * 00004 * @section LICENSE 00005 * 00006 * Copyright (c) 2010 ARM Limited 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a copy 00009 * of this software and associated documentation files (the "Software"), to deal 00010 * in the Software without restriction, including without limitation the rights 00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00012 * copies of the Software, and to permit persons to whom the Software is 00013 * furnished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included in 00016 * all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00024 * THE SOFTWARE. 00025 * 00026 * @section DESCRIPTION 00027 * 00028 * A PID controller is a widely used feedback controller commonly found in 00029 * industry. 00030 * 00031 * This library is a port of Brett Beauregard's Arduino PID library: 00032 * 00033 * http://www.arduino.cc/playground/Code/PIDLibrary 00034 * 00035 * The wikipedia article on PID controllers is a good place to start on 00036 * understanding how they work: 00037 * 00038 * http://en.wikipedia.org/wiki/PID_controller 00039 * 00040 * For a clear and elegant explanation of how to implement and tune a 00041 * controller, the controlguru website by Douglas J. Cooper (who also happened 00042 * to be Brett's controls professor) is an excellent reference: 00043 * 00044 * http://www.controlguru.com/ 00045 */ 00046 00047 /** 00048 * Includes 00049 */ 00050 #include "PID.h" 00051 00052 PID::PID(float Kc, float tauI, float tauD, float interval) { 00053 00054 usingFeedForward = false; 00055 inAuto = false; 00056 00057 //Default the limits to the full range of I/O: 3.3V 00058 //Make sure to set these to more appropriate limits for 00059 //your application. 00060 setInputLimits(0.0, 3.3); 00061 setOutputLimits(0.0, 3.3); 00062 00063 tSample_ = interval; 00064 00065 setTunings(Kc, tauI, tauD); 00066 00067 setPoint_ = 0.0; 00068 processVariable_ = 0.0; 00069 prevProcessVariable_ = 0.0; 00070 controllerOutput_ = 0.0; 00071 prevControllerOutput_ = 0.0; 00072 00073 accError_ = 0.0; 00074 bias_ = 0.0; 00075 00076 realOutput_ = 0.0; 00077 00078 } 00079 00080 void PID::setInputLimits(float inMin, float inMax) { 00081 00082 //Make sure we haven't been given impossible values. 00083 if (inMin >= inMax) { 00084 return; 00085 } 00086 00087 //Rescale the working variables to reflect the changes. 00088 prevProcessVariable_ *= (inMax - inMin) / inSpan_; 00089 accError_ *= (inMax - inMin) / inSpan_; 00090 00091 //Make sure the working variables are within the new limits. 00092 if (prevProcessVariable_ > 1) { 00093 prevProcessVariable_ = 1; 00094 } else if (prevProcessVariable_ < 0) { 00095 prevProcessVariable_ = 0; 00096 } 00097 00098 inMin_ = inMin; 00099 inMax_ = inMax; 00100 inSpan_ = inMax - inMin; 00101 00102 setSetPoint(setPoint_); 00103 } 00104 00105 void PID::setOutputLimits(float outMin, float outMax) { 00106 00107 //Make sure we haven't been given impossible values. 00108 if (outMin >= outMax) { 00109 return; 00110 } 00111 00112 //Rescale the working variables to reflect the changes. 00113 prevControllerOutput_ *= (outMax - outMin) / outSpan_; 00114 00115 //Make sure the working variables are within the new limits. 00116 if (prevControllerOutput_ > 1) { 00117 prevControllerOutput_ = 1; 00118 } else if (prevControllerOutput_ < 0) { 00119 prevControllerOutput_ = 0; 00120 } 00121 00122 outMin_ = outMin; 00123 outMax_ = outMax; 00124 outSpan_ = outMax - outMin; 00125 } 00126 00127 /*void PID::setConInputLimits(float cinMin, float cinMax) { 00128 00129 //Make sure we haven't been given impossible values. 00130 if ((cinMin >= cinMax) || (cinMin < inMin_) || (cinMax > inMax_)) { 00131 return; 00132 } 00133 00134 cinSMin_ = (cinMin - inMin_)/inSpan_; 00135 cinSMax_ = (cinMax - inMax_)/inSpan_; 00136 }*/ 00137 00138 void PID::setTunings(float Kc, float tauI, float tauD) { 00139 00140 //Verify that the tunings make sense. 00141 if (Kc == 0.0 || tauI < 0.0 || tauD < 0.0) { 00142 return; 00143 } 00144 00145 //Store raw values to hand back to user on request. 00146 pParam_ = Kc; 00147 iParam_ = tauI; 00148 dParam_ = tauD; 00149 00150 float tempTauR; 00151 00152 if (tauI == 0.0) { 00153 tempTauR = 0.0; 00154 } else { 00155 tempTauR = (1.0 / tauI) * tSample_; 00156 } 00157 00158 //For "bumpless transfer" we need to rescale the accumulated error. 00159 if (inAuto) { 00160 if (tempTauR == 0.0) { 00161 accError_ = 0.0; 00162 } else { 00163 accError_ *= (Kc_ * tauR_) / (Kc * tempTauR); 00164 } 00165 } 00166 00167 Kc_ = Kc; 00168 tauR_ = tempTauR; 00169 tauD_ = tauD / tSample_; 00170 00171 } 00172 00173 void PID::reset(void) { 00174 00175 float scaledBias = 0.0; 00176 00177 if (usingFeedForward) { 00178 scaledBias = (bias_ - outMin_) / outSpan_; 00179 } else { 00180 scaledBias = (realOutput_ - outMin_) / outSpan_; 00181 } 00182 00183 prevControllerOutput_ = scaledBias; 00184 prevProcessVariable_ = (processVariable_ - inMin_) / inSpan_; 00185 00186 //Clear any error in the integral. 00187 accError_ = 0; 00188 00189 } 00190 00191 void PID::setMode(int mode) { 00192 00193 //We were in manual, and we just got set to auto. 00194 //Reset the controller internals. 00195 if (mode != 0 && !inAuto) { 00196 reset(); 00197 } 00198 00199 inAuto = (mode != 0); 00200 00201 } 00202 00203 void PID::setInterval(float interval) { 00204 00205 if (interval > 0) { 00206 //Convert the time-based tunings to reflect this change. 00207 tauR_ *= (interval / tSample_); 00208 accError_ *= (tSample_ / interval); 00209 tauD_ *= (interval / tSample_); 00210 tSample_ = interval; 00211 } 00212 00213 } 00214 00215 void PID::setSetPoint(float sp) { 00216 00217 if (sp > inMax_) { 00218 sp = inMax_; 00219 } else if (sp < inMin_) { 00220 sp = inMin_; 00221 } 00222 setPoint_ = sp; 00223 00224 } 00225 00226 void PID::setProcessValue(float pv) { 00227 00228 processVariable_ = pv; 00229 00230 } 00231 00232 void PID::setBias(float bias){ 00233 00234 bias_ = bias; 00235 usingFeedForward = 1; 00236 00237 } 00238 00239 void PID::setAccLimit(float accLimit) { 00240 00241 accLimit_ = abs(accLimit); 00242 00243 } 00244 00245 00246 float PID::compute() { 00247 00248 //Pull in the input and setpoint, and scale them into percent span. 00249 float scaledPV = (processVariable_ - inMin_) / inSpan_; 00250 00251 /*if (scaledPV > 1.0) { 00252 scaledPV = 1.0; 00253 } else if (scaledPV < 0.0) { 00254 scaledPV = 0.0; 00255 }*/ 00256 00257 float scaledSP = (setPoint_ - inMin_) / inSpan_; 00258 /*if (scaledSP > 1.0) { 00259 scaledSP = 1.0; 00260 } else if (scaledSP < 0.0) { 00261 scaledSP = 0.0; 00262 }*/ 00263 00264 error_ = scaledSP - scaledPV; 00265 00266 //Check and see if the output is pegged at a limit and only 00267 //integrate if it is not. This is to prevent reset-windup. 00268 if (!(prevControllerOutput_ >= 1 && error_ > 0) && !(prevControllerOutput_ <= 0 && error_ < 0)) { 00269 accError_ += error_; 00270 if (accError_ > accLimit_) { 00271 accError_ = accLimit_; 00272 } else if (accError_ < -accLimit_) { 00273 accError_ = -accLimit_; 00274 } 00275 } 00276 00277 //Compute the current slope of the input signal. 00278 float dMeas = (scaledPV - prevProcessVariable_) / tSample_; 00279 00280 float scaledBias = 0.0; 00281 00282 if (usingFeedForward) { 00283 scaledBias = (bias_ - outMin_) / outSpan_; 00284 } 00285 00286 //Perform the PID calculation. 00287 controllerOutput_ = scaledBias + Kc_ * (error_ + (tauR_ * accError_) - (tauD_ * dMeas)); 00288 00289 //Make sure the computed output is within output constraints. 00290 if (controllerOutput_ < 0.0) { 00291 controllerOutput_ = 0.0; 00292 } else if (controllerOutput_ > 1.0) { 00293 controllerOutput_ = 1.0; 00294 } 00295 00296 //Remember this output for the windup check next time. 00297 prevControllerOutput_ = controllerOutput_; 00298 //Remember the input for the derivative calculation next time. 00299 prevProcessVariable_ = scaledPV; 00300 00301 //Scale the output from percent span back out to a real world number. 00302 return ((controllerOutput_ * outSpan_) + outMin_); 00303 00304 } 00305 00306 float PID::getInMin() { 00307 return inMin_; 00308 } 00309 00310 float PID::getInMax() { 00311 return inMax_; 00312 } 00313 00314 float PID::getOutMin() { 00315 return outMin_; 00316 } 00317 00318 float PID::getOutMax() { 00319 return outMax_; 00320 } 00321 00322 float PID::getInterval() { 00323 return tSample_; 00324 } 00325 00326 float PID::getPParam() { 00327 return pParam_; 00328 } 00329 00330 float PID::getIParam() { 00331 return iParam_; 00332 } 00333 00334 float PID::getDParam() { 00335 return dParam_; 00336 } 00337 00338 float PID::getAccLimit() { 00339 return accLimit_; 00340 } 00341 00342 float PID::getAccError() { 00343 return accError_; 00344 } 00345 00346 00347 float PID::getSetPoint() { 00348 return setPoint_; 00349 }
Generated on Tue Jul 12 2022 21:35:43 by
