From 205772ff88ad24e251cfba0bb5f783d43b6b7a9b Mon Sep 17 00:00:00 2001 From: r-downing <26515643+r-downing@users.noreply.github.com> Date: Sun, 22 Oct 2017 19:53:11 -0400 Subject: [PATCH] added library code files --- AutoPID.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ AutoPID.h | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 AutoPID.cpp create mode 100644 AutoPID.h diff --git a/AutoPID.cpp b/AutoPID.cpp new file mode 100644 index 0000000..2d5069f --- /dev/null +++ b/AutoPID.cpp @@ -0,0 +1,96 @@ +#include "AutoPID.h" + +AutoPID::AutoPID(double *input, double *setpoint, double *output, double outputMin, double outputMax, + double Kp, double Ki, double Kd) { + _input = input; + _setpoint = setpoint; + _output = output; + _outputMin = outputMin; + _outputMax = outputMax; + setGains(Kp, Ki, Kd); + _timeStep = 1000; +}//AutoPID::AutoPID + +void AutoPID::setGains(double Kp, double Ki, double Kd) { + _Kp = Kp; + _Ki = Ki; + _Kd = Kd; +}//AutoPID::setControllerParams + +void AutoPID::setBangBang(double bangOn, double bangOff) { + _bangOn = bangOn; + _bangOff = bangOff; +}//void AutoPID::setBangBang + +void AutoPID::setBangBang(double bangRange) { + setBangBang(bangRange, bangRange); +}//void AutoPID::setBangBang + +void AutoPID::setOutputRange(double outputMin, double outputMax) { + _outputMin = outputMin; + _outputMax = outputMax; +}//void AutoPID::setOutputRange + +void AutoPID::setTimeStep(unsigned long timeStep){ + _timeStep = timeStep; +} + + +bool AutoPID::atSetPoint(double threshold) { + return abs(*_setpoint - *_input) <= threshold; +}//bool AutoPID::atSetPoint + +void AutoPID::run() { + if (_stopped) { + _stopped = false; + reset(); + } + //if bang thresholds are defined and we're outside of them, use bang-bang control + if (_bangOn && ((*_setpoint - *_input) > _bangOn)) { + *_output = _outputMax; + _lastStep = millis(); + } else if (_bangOff && ((*_input - *_setpoint) > _bangOff)) { + *_output = _outputMin; + _lastStep = millis(); + } else { //otherwise use PID control + unsigned long _dT = millis() - _lastStep; //calculate time since last update + if (_dT >= _timeStep) { //if long enough, do PID calculations + _lastStep = millis(); + double _error = *_setpoint - *_input; + _integral += (_error + _previousError) / 2 * _dT / 1000.0; //Riemann sum integral + //_integral = constrain(_integral, _outputMin/_Ki, _outputMax/_Ki); + double _dError = (_error - _previousError) / _dT / 1000.0; //derivative + _previousError = _error; + double PID = (_Kp * _error) + (_Ki * _integral) + (_Kd * _dError); + //*_output = _outputMin + (constrain(PID, 0, 1) * (_outputMax - _outputMin)); + *_output = constrain(PID, _outputMin, _outputMax); + } + } +}//void AutoPID::run + +void AutoPID::stop() { + _stopped = true; + reset(); +} +void AutoPID::reset() { + _lastStep = millis(); + _integral = 0; + _previousError = 0; +} + +bool AutoPID::isStopped(){ + return _stopped; +} + +void AutoPIDRelay::run() { + AutoPID::run(); + while ((millis() - _lastPulseTime) > _pulseWidth) _lastPulseTime += _pulseWidth; + *_relayState = ((millis() - _lastPulseTime) < (_pulseValue * _pulseWidth)); +} + + +double AutoPIDRelay::getPulseValue(){ + return (isStopped()?0:_pulseValue); +} + + diff --git a/AutoPID.h b/AutoPID.h new file mode 100644 index 0000000..d167f33 --- /dev/null +++ b/AutoPID.h @@ -0,0 +1,61 @@ +#ifndef AUTOPID_H +#define AUTOPID_H +#include + +class AutoPID { + + public: + // Constructor - takes pointer inputs for control variales, so they are updated automatically + AutoPID(double *input, double *setpoint, double *output, double outputMin, double outputMax, + double Kp, double Ki, double Kd); + // Allows manual adjustment of gains + void setGains(double Kp, double Ki, double Kd); + // Sets bang-bang control ranges, separate upper and lower offsets, zero for off + void setBangBang(double bangOn, double bangOff); + // Sets bang-bang control range +-single offset + void setBangBang(double bangRange); + // Allows manual readjustment of output range + void setOutputRange(double outputMin, double outputMax); + // Allows manual adjustment of time step (default 1000ms) + void setTimeStep(unsigned long timeStep); + // Returns true when at set point (+-threshold) + bool atSetPoint(double threshold); + // Runs PID calculations when needed. Should be called repeatedly in loop. + // Automatically reads input and sets output via pointers + void run(); + // Stops PID functionality, output sets to + void stop(); + void reset(); + bool isStopped(); + + private: + double _Kp, _Ki, _Kd; + double _integral, _previousError; + double _bangOn, _bangOff; + double *_input, *_setpoint, *_output; + double _outputMin, _outputMax; + unsigned long _timeStep, _lastStep; + bool _stopped; + +};//class AutoPID + +class AutoPIDRelay : public AutoPID { + public: + + AutoPIDRelay(double *input, double *setpoint, bool *relayState, double pulseWidth, double Kp, double Ki, double Kd) + : AutoPID(input, setpoint, &_pulseValue, 0, 1.0, Kp, Ki, Kd) { + _relayState = relayState; + _pulseWidth = pulseWidth; + }; + + void run(); + + double getPulseValue(); + + private: + bool * _relayState; + unsigned long _pulseWidth, _lastPulseTime; + double _pulseValue; +};//class AutoPIDRelay + +#endif