Now you can download a copy of these docs so you can use them offline! Download now
PIDController.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "PIDController.h" 00008 #include "Notifier.h" 00009 #include "PIDSource.h" 00010 #include "PIDOutput.h" 00011 #include <math.h> 00012 #include "Synchronized.h" 00023 PIDController::PIDController(float Kp, float Ki, float Kd, 00024 PIDSource *source, PIDOutput *output, 00025 float period) : 00026 m_semaphore (0) 00027 { 00028 m_semaphore = semBCreate(SEM_Q_PRIORITY, SEM_FULL); 00029 00030 m_controlLoop = new Notifier(PIDController::CallCalculate, this); 00031 00032 00033 m_P = Kp; 00034 m_I = Ki; 00035 m_D = Kd; 00036 m_maximumOutput = 1.0; 00037 m_minimumOutput = -1.0; 00038 00039 m_maximumInput = 0; 00040 m_minimumInput = 0; 00041 00042 m_continuous = false; 00043 m_enabled = false; 00044 m_setpoint = 0; 00045 00046 m_prevError = 0; 00047 m_totalError = 0; 00048 m_tolerance = .05; 00049 00050 m_result = 0; 00051 00052 m_pidInput = source; 00053 m_pidOutput = output; 00054 m_period = period; 00055 00056 m_controlLoop->StartPeriodic(m_period); 00057 } 00058 00062 PIDController::~PIDController() 00063 { 00064 semFlush(m_semaphore); 00065 delete m_controlLoop; 00066 } 00067 00075 void PIDController::CallCalculate(void *controller) 00076 { 00077 PIDController *control = (PIDController*) controller; 00078 control->Calculate(); 00079 } 00080 00086 void PIDController::Calculate() 00087 { 00088 bool enabled; 00089 PIDSource *pidInput; 00090 00091 CRITICAL_REGION(m_semaphore) 00092 { 00093 if (m_pidInput == 0) return; 00094 if (m_pidOutput == 0) return; 00095 enabled = m_enabled; 00096 pidInput = m_pidInput; 00097 } 00098 END_REGION; 00099 00100 if (enabled) 00101 { 00102 float input = pidInput->PIDGet(); 00103 float result; 00104 PIDOutput *pidOutput; 00105 00106 { 00107 Synchronized sync(m_semaphore); 00108 m_error = m_setpoint - input; 00109 if (m_continuous) 00110 { 00111 if (fabs(m_error) > (m_maximumInput - m_minimumInput) / 2) 00112 { 00113 if (m_error > 0) 00114 { 00115 m_error = m_error - m_maximumInput + m_minimumInput; 00116 } 00117 else 00118 { 00119 m_error = m_error + m_maximumInput - m_minimumInput; 00120 } 00121 } 00122 } 00123 00124 double potentialIGain = (m_totalError + m_error) * m_I; 00125 if (potentialIGain < m_maximumOutput) 00126 { 00127 if (potentialIGain > m_minimumOutput) 00128 m_totalError += m_error; 00129 else 00130 m_totalError = m_minimumOutput / m_I; 00131 } 00132 else 00133 { 00134 m_totalError = m_maximumOutput / m_I; 00135 } 00136 00137 m_result = m_P * m_error + m_I * m_totalError + m_D * (m_error - m_prevError); 00138 m_prevError = m_error; 00139 00140 if (m_result > m_maximumOutput) m_result = m_maximumOutput; 00141 else if (m_result < m_minimumOutput) m_result = m_minimumOutput; 00142 00143 pidOutput = m_pidOutput; 00144 result = m_result; 00145 } 00146 00147 pidOutput->PIDWrite(result); 00148 } 00149 } 00150 00158 void PIDController::SetPID(float p, float i, float d) 00159 { 00160 CRITICAL_REGION(m_semaphore) 00161 { 00162 m_P = p; 00163 m_I = i; 00164 m_D = d; 00165 } 00166 END_REGION; 00167 } 00168 00173 float PIDController::GetP() 00174 { 00175 CRITICAL_REGION(m_semaphore) 00176 { 00177 return m_P; 00178 } 00179 END_REGION; 00180 } 00181 00186 float PIDController::GetI() 00187 { 00188 CRITICAL_REGION(m_semaphore) 00189 { 00190 return m_I; 00191 } 00192 END_REGION; 00193 } 00194 00199 float PIDController::GetD() 00200 { 00201 CRITICAL_REGION(m_semaphore) 00202 { 00203 return m_D; 00204 } 00205 END_REGION; 00206 } 00207 00213 float PIDController::Get() 00214 { 00215 float result; 00216 CRITICAL_REGION(m_semaphore) 00217 { 00218 result = m_result; 00219 } 00220 END_REGION; 00221 return result; 00222 } 00223 00231 void PIDController::SetContinuous(bool continuous) 00232 { 00233 CRITICAL_REGION(m_semaphore) 00234 { 00235 m_continuous = continuous; 00236 } 00237 END_REGION; 00238 00239 } 00240 00247 void PIDController::SetInputRange(float minimumInput, float maximumInput) 00248 { 00249 CRITICAL_REGION(m_semaphore) 00250 { 00251 m_minimumInput = minimumInput; 00252 m_maximumInput = maximumInput; 00253 } 00254 END_REGION; 00255 00256 SetSetpoint(m_setpoint); 00257 } 00258 00265 void PIDController::SetOutputRange(float minimumOutput, float maximumOutput) 00266 { 00267 CRITICAL_REGION(m_semaphore) 00268 { 00269 m_minimumOutput = minimumOutput; 00270 m_maximumOutput = maximumOutput; 00271 } 00272 END_REGION; 00273 } 00274 00279 void PIDController::SetSetpoint(float setpoint) 00280 { 00281 CRITICAL_REGION(m_semaphore) 00282 { 00283 if (m_maximumInput > m_minimumInput) 00284 { 00285 if (setpoint > m_maximumInput) 00286 m_setpoint = m_maximumInput; 00287 else if (setpoint < m_minimumInput) 00288 m_setpoint = m_minimumInput; 00289 else 00290 m_setpoint = setpoint; 00291 } 00292 else 00293 { 00294 m_setpoint = setpoint; 00295 } 00296 } 00297 END_REGION; 00298 } 00299 00304 float PIDController::GetSetpoint() 00305 { 00306 float setpoint; 00307 CRITICAL_REGION(m_semaphore) 00308 { 00309 setpoint = m_setpoint; 00310 } 00311 END_REGION; 00312 return setpoint; 00313 } 00314 00319 float PIDController::GetError() 00320 { 00321 float error; 00322 CRITICAL_REGION(m_semaphore) 00323 { 00324 error = m_error; 00325 } 00326 END_REGION; 00327 return error; 00328 } 00329 00330 /* 00331 * Set the percentage error which is considered tolerable for use with 00332 * OnTarget. 00333 * @param percentage error which is tolerable 00334 */ 00335 void PIDController::SetTolerance(float percent) 00336 { 00337 CRITICAL_REGION(m_semaphore) 00338 { 00339 m_tolerance = percent; 00340 } 00341 END_REGION; 00342 } 00343 00344 /* 00345 * Return true if the error is within the percentage of the total input range, 00346 * determined by SetTolerance. This asssumes that the maximum and minimum input 00347 * were set using SetInput. 00348 */ 00349 bool PIDController::OnTarget() 00350 { 00351 bool temp; 00352 CRITICAL_REGION(m_semaphore) 00353 { 00354 temp = fabs(m_error) < (m_tolerance / 100 * 00355 (m_maximumInput - m_minimumInput)); 00356 } 00357 END_REGION; 00358 return temp; 00359 } 00360 00364 void PIDController::Enable() 00365 { 00366 CRITICAL_REGION(m_semaphore) 00367 { 00368 m_enabled = true; 00369 } 00370 END_REGION; 00371 } 00375 void PIDController::Disable() 00376 { 00377 CRITICAL_REGION(m_semaphore) 00378 { 00379 m_pidOutput->PIDWrite(0); 00380 m_enabled = false; 00381 } 00382 END_REGION; 00383 } 00384 00388 bool PIDController::IsEnabled() 00389 { 00390 bool enabled; 00391 CRITICAL_REGION(m_semaphore) 00392 { 00393 enabled = m_enabled; 00394 } 00395 END_REGION; 00396 return enabled; 00397 } 00398 00402 void PIDController::Reset() 00403 { 00404 Disable(); 00405 00406 CRITICAL_REGION(m_semaphore) 00407 { 00408 m_prevError = 0; 00409 m_totalError = 0; 00410 m_result = 0; 00411 } 00412 END_REGION; 00413 }
Generated on Thu Jan 12 2012 22:35:23 for WPILibC++ by
1.7.1