-
Notifications
You must be signed in to change notification settings - Fork 7
/
PIDController.cpp
147 lines (119 loc) · 3.76 KB
/
PIDController.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//
// Lucky Resistor's Fan Controller
// ---------------------------------------------------------------------------
// (c)2016 by Lucky Resistor. See LICENSE for details.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#include "PIDController.h"
namespace lr {
PIDController::PIDController()
:
_kp(0.0f),
_ki(0.0f),
_kd(0.0f),
_reverseDirection(false),
_outputDrift(0.0f),
_output(0.0f),
_outputMinimum(0.0f),
_outputMaximum(255.0f),
_errorSumAndKi(0.0f),
_target(0.0f),
_lastInput(0.0f),
_sampleTime(-2.0f),
_lastCalculation(0)
{
}
void PIDController::begin(float kp, float ki, float kd)
{
_kp = kp;
_ki = ki;
_kd = kd;
}
void PIDController::setOutputLimits(float minimum, float maximum)
{
_outputMinimum = minimum;
_outputMaximum = maximum;
}
void PIDController::setOutputReverse(bool isReverse)
{
if (_reverseDirection != isReverse) {
_kp = -_kp;
_ki = -_ki;
_kd = -_kd;
_reverseDirection = isReverse;
}
}
void PIDController::setOutputDrift(float outputDrift)
{
_outputDrift = outputDrift;
}
void PIDController::setOutputValue(float value)
{
_output = value;
}
float PIDController::getOutputValue() const
{
return _output;
}
void PIDController::setTargetValue(float value)
{
_target = value;
}
float PIDController::calculateOutput(float input)
{
// Check if we already have a sample time measurement.
if (_sampleTime < -1.0f) {
// No, just store the time point, input value and keep the current output value.
_lastCalculation = millis();
_lastInput = input;
_errorSumAndKi = _output;
_sampleTime = -1.0f;
return _output;
}
// Update the sample time.
const float newSampleTime = static_cast<float>(millis() - _lastCalculation)/1000.0f;
if (_sampleTime < 0.0f) {
_sampleTime = (_sampleTime + newSampleTime)/2.0f;
} else {
_sampleTime = newSampleTime;
}
// Calculate the new output value.
const float kp = _kp;
const float ki = _ki * _sampleTime; // Make sure our tuning values change on timing.
const float kd = _kd / _sampleTime;
const float error = _target - input; // Get the current error
_errorSumAndKi += (ki * error); // Add to the error sum and integrate the Ki value into it.
_errorSumAndKi += _outputDrift; // Add the output drift to the error sum and ki value.
// Limit the error sum (*Ki) to values in the given limits of the output.
if (_errorSumAndKi > _outputMaximum) {
_errorSumAndKi = _outputMaximum;
} else if (_errorSumAndKi < _outputMinimum) {
_errorSumAndKi = _outputMinimum;
}
const float inputDelta = input - _lastInput; // Get the delat of the input.
const float newOutput = (kp*error) + _errorSumAndKi - (kd*inputDelta);
if (newOutput > _outputMaximum) {
_output = _outputMaximum;
} else if (newOutput < _outputMinimum) {
_output = _outputMinimum;
} else {
_output = newOutput;
}
_lastCalculation = millis();
_lastInput = input;
return _output;
}
}