|
| 1 | +#include "AutoPID.h" |
| 2 | + |
| 3 | +AutoPID::AutoPID(double *input, double *setpoint, double *output, double outputMin, double outputMax, |
| 4 | + double Kp, double Ki, double Kd) { |
| 5 | + _input = input; |
| 6 | + _setpoint = setpoint; |
| 7 | + _output = output; |
| 8 | + _outputMin = outputMin; |
| 9 | + _outputMax = outputMax; |
| 10 | + setGains(Kp, Ki, Kd); |
| 11 | + _timeStep = 1000; |
| 12 | +}//AutoPID::AutoPID |
| 13 | + |
| 14 | +void AutoPID::setGains(double Kp, double Ki, double Kd) { |
| 15 | + _Kp = Kp; |
| 16 | + _Ki = Ki; |
| 17 | + _Kd = Kd; |
| 18 | +}//AutoPID::setControllerParams |
| 19 | + |
| 20 | +void AutoPID::setBangBang(double bangOn, double bangOff) { |
| 21 | + _bangOn = bangOn; |
| 22 | + _bangOff = bangOff; |
| 23 | +}//void AutoPID::setBangBang |
| 24 | + |
| 25 | +void AutoPID::setBangBang(double bangRange) { |
| 26 | + setBangBang(bangRange, bangRange); |
| 27 | +}//void AutoPID::setBangBang |
| 28 | + |
| 29 | +void AutoPID::setOutputRange(double outputMin, double outputMax) { |
| 30 | + _outputMin = outputMin; |
| 31 | + _outputMax = outputMax; |
| 32 | +}//void AutoPID::setOutputRange |
| 33 | + |
| 34 | +void AutoPID::setTimeStep(unsigned long timeStep){ |
| 35 | + _timeStep = timeStep; |
| 36 | +} |
| 37 | + |
| 38 | + |
| 39 | +bool AutoPID::atSetPoint(double threshold) { |
| 40 | + return abs(*_setpoint - *_input) <= threshold; |
| 41 | +}//bool AutoPID::atSetPoint |
| 42 | + |
| 43 | +void AutoPID::run() { |
| 44 | + if (_stopped) { |
| 45 | + _stopped = false; |
| 46 | + reset(); |
| 47 | + } |
| 48 | + //if bang thresholds are defined and we're outside of them, use bang-bang control |
| 49 | + if (_bangOn && ((*_setpoint - *_input) > _bangOn)) { |
| 50 | + *_output = _outputMax; |
| 51 | + _lastStep = millis(); |
| 52 | + } else if (_bangOff && ((*_input - *_setpoint) > _bangOff)) { |
| 53 | + *_output = _outputMin; |
| 54 | + _lastStep = millis(); |
| 55 | + } else { //otherwise use PID control |
| 56 | + unsigned long _dT = millis() - _lastStep; //calculate time since last update |
| 57 | + if (_dT >= _timeStep) { //if long enough, do PID calculations |
| 58 | + _lastStep = millis(); |
| 59 | + double _error = *_setpoint - *_input; |
| 60 | + _integral += (_error + _previousError) / 2 * _dT / 1000.0; //Riemann sum integral |
| 61 | + //_integral = constrain(_integral, _outputMin/_Ki, _outputMax/_Ki); |
| 62 | + double _dError = (_error - _previousError) / _dT / 1000.0; //derivative |
| 63 | + _previousError = _error; |
| 64 | + double PID = (_Kp * _error) + (_Ki * _integral) + (_Kd * _dError); |
| 65 | + //*_output = _outputMin + (constrain(PID, 0, 1) * (_outputMax - _outputMin)); |
| 66 | + *_output = constrain(PID, _outputMin, _outputMax); |
| 67 | + } |
| 68 | + } |
| 69 | +}//void AutoPID::run |
| 70 | + |
| 71 | +void AutoPID::stop() { |
| 72 | + _stopped = true; |
| 73 | + reset(); |
| 74 | +} |
| 75 | +void AutoPID::reset() { |
| 76 | + _lastStep = millis(); |
| 77 | + _integral = 0; |
| 78 | + _previousError = 0; |
| 79 | +} |
| 80 | + |
| 81 | +bool AutoPID::isStopped(){ |
| 82 | + return _stopped; |
| 83 | +} |
| 84 | + |
| 85 | +void AutoPIDRelay::run() { |
| 86 | + AutoPID::run(); |
| 87 | + while ((millis() - _lastPulseTime) > _pulseWidth) _lastPulseTime += _pulseWidth; |
| 88 | + *_relayState = ((millis() - _lastPulseTime) < (_pulseValue * _pulseWidth)); |
| 89 | +} |
| 90 | + |
| 91 | + |
| 92 | +double AutoPIDRelay::getPulseValue(){ |
| 93 | + return (isStopped()?0:_pulseValue); |
| 94 | +} |
| 95 | + |
| 96 | + |
0 commit comments