Skip to content

Commit 3fa06f2

Browse files
committed
Update
- Resolved `Kp` windup as noted in issue br3ttb#6. Algorithm reverts to upstream library, but with fixed point math option and newer controller direction method maintained. - Updated AutoTune examples and documentation.
1 parent 1ff4d46 commit 3fa06f2

File tree

7 files changed

+60
-47
lines changed

7 files changed

+60
-47
lines changed

README.md

+10-29
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,21 @@
11
# QuickPID [![arduino-library-badge](https://www.ardu-badge.com/badge/QuickPID.svg?)](https://www.ardu-badge.com/QuickPID)
22

3-
QuickPID is a fast fixed/floating point implementation of the Arduino PID library with built-in [AutoTune](https://github.com/Dlloydev/QuickPID/wiki/AutoTune) class as a dynamic object to reduce memory if not used, thanks to contributions by [gnalbandian (Gonzalo)](https://github.com/gnalbandian). This controller can automatically determine and set parameters `Kp, Ki, Kd`. Additionally the Ultimate Gain `Ku`, Ultimate Period `Tu`, Dead Time `td` and determine how easy the process is to control. There are 10 tuning rules available to choose from. Also available is a POn setting that controls the mix of Proportional on Error to Proportional on Measurement.
3+
QuickPID is a fast fixed/floating point implementation of the Arduino PID library with built-in [AutoTune](https://github.com/Dlloydev/QuickPID/wiki/AutoTune) class as a dynamic object to reduce memory if not used, thanks to contributions by [gnalbandian (Gonzalo)](https://github.com/gnalbandian). This controller can automatically determine and set parameters `Kp, Ki, Kd`. Additionally the Ultimate Gain `Ku`, Ultimate Period `Tu`, Dead Time `td` and determine how easy the process is to control. There are 10 tuning rules available to choose from. Also available is a POn setting that controls the mix of Proportional on Error to Proportional on Measurement.
44

55
### About
66

7-
This PID controller provides a shortened *read-compute-write* cycle by using a reduced PID algorithm, taking advantage of fixed point math and using a fast analog read function. The `Ki` and `Kd` are scaled by time (µs) and the new `kpi` and `kpd` parameters are calculated in the `SetTunings()` function resulting in only two multiply operations required in `Compute()`.
7+
This PID controller provides a shortened *read-compute-write* cycle by taking advantage of fixed point math and using a fast analog read function.
88

99
### Features
1010

11-
Development began with a fork of the Arduino PID Library. Modifications and new features have been added as described in the change log and below:
12-
13-
- Quicker hybrid fixed/floating point math, efficient PID algorithm and micros() timing resolution.
14-
- Built-in `AutoTunePID` class as a dynamic object. AutoTune automatically determines and applies `Kp`, `Ki` and `Kd` tuning parameters and has 10 tuning rules to choose from.
15-
- Variable `POn` parameter controls the setpoint weighting and mix of Proportional on Error to Proportional on Measurement.
16-
- Includes [analogWrite](https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite) for ESP32 boards.
17-
18-
### Performance (16MHz ATmega328P)
19-
20-
| `Compute()` | Kp | Ki | Kd | Step Time (µS) |
21-
| :---------- | ---- | ---- | ---- | -------------- |
22-
| QuickPID | 2.0 | 5.0 | 1.0 | 72 |
23-
| Arduino PID | 2.0 | 5.0 | 1.0 | 104 |
11+
Development began with a fork of the Arduino PID Library. Modifications and new features have been added as described in the change log.
2412

2513
### [AutoTune RC Filter](https://github.com/Dlloydev/QuickPID/wiki/AutoTune_RC_Filter)
2614

2715
This example allows you to experiment with the AutoTunePID class, various tuning rules and the POn control using ADC and PWM with RC filter. It automatically determines and sets the tuning parameters and works with both DIRECT and REVERSE acting controllers.
2816

2917
#### [QuickPID WiKi ...](https://github.com/Dlloydev/QuickPID/wiki)
3018

31-
### Simplified PID Algorithm
32-
33-
```c++
34-
outputSum += (kpi * error) - (kpd * dInput);
35-
```
36-
37-
The `kpi` and `kpd` parameters are calculated in the `SetTunings()` function. This results in a simple and fast algorithm with only two multiply operations required. The gains for `error` (`kpi`) and measurement `dInput` (`kpd`) are calculated as follows:
38-
39-
```c++
40-
kpi = kp * pOn + ki;
41-
kpd = kp * (1 - pOn) + kd;
42-
```
43-
4419
### Direct and Reverse Controller Action
4520

4621
If a positive error increases the controller's output, the controller is said to be direct acting (i.e. heating process). When a positive error decreases the controller's output, the controller is said to be reverse acting (i.e. cooling process). When the controller is set to `REVERSE` acting, the sign of the `error` and `dInput` (derivative of Input) is internally changed. All operating ranges and limits remain the same. To simulate a `REVERSE` acting process from a process that's `DIRECT` acting, the Input value needs to be "flipped". That is, if your reading from a 10-bit ADC with 0-1023 range, the input value used is (1023 - reading). See the examples `AutoTune_Filter_DIRECT.ino` and `AutoTune_Filter_REVERSE.ino` for details.
@@ -79,7 +54,7 @@ This function contains the PID algorithm and it should be called once every loop
7954

8055
#### [AutoTune](https://github.com/Dlloydev/QuickPID/wiki/AutoTune)
8156

82-
For use of AutoTune, refer to the examples `AutoTune_Filter_DIRECT.ino` and `AutoTune_Filter_REVERSE.ino`
57+
For use of AutoTune, refer to the examples [AutoTune_Filter_DIRECT.ino](https://github.com/Dlloydev/QuickPID/blob/master/examples/AutoTune_Filter_DIRECT/AutoTune_Filter_DIRECT.ino) and [AutoTune_Filter_REVERSE.ino](https://github.com/Dlloydev/QuickPID/blob/master/examples/AutoTune_Filter_REVERSE/AutoTune_Filter_REVERSE.ino)
8358

8459
#### SetTunings
8560

@@ -164,6 +139,12 @@ Use this link for reference. Note that if you're using QuickPID, there's no need
164139
165140
#### Change Log
166141
142+
#### Version 2.3.1
143+
144+
- Resolved `Kp` windup as noted in issue #6. Algorithm reverts to upstream library, but with fixed point math option and newer controller direction method maintained.
145+
- Updated AutoTune examples and documentation.
146+
- Default AutoTune `outputStep` value in examples (and documentation) is now 5.
147+
167148
#### Version 2.3.0
168149
169150
- New AutoTune class added as a dynamic object to reduce memory if not used, thanks to contributions by [gnalbandian (Gonzalo)](https://github.com/gnalbandian).

examples/AutoTune_Filter_DIRECT/AutoTune_Filter_DIRECT.ino

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/******************************************************************************
22
AutoTune Filter DIRECT Example
3-
Reference: https://github.com/Dlloydev/QuickPID/wiki/AutoTune
43
Circuit: https://github.com/Dlloydev/QuickPID/wiki/AutoTune_RC_Filter
54
******************************************************************************/
65

@@ -15,8 +14,7 @@ const int outputMin = 0;
1514
float POn = 1.0; // mix of PonE to PonM (0.0-1.0)
1615

1716
bool printOrPlotter = 0; // on(1) monitor, off(0) plotter
18-
byte tuningRule = 1; // see reference link
19-
byte outputStep = 1;
17+
byte outputStep = 5;
2018
byte hysteresis = 1;
2119
int setpoint = 341; // 1/3 of 10-bit ADC range for symetrical waveform
2220
int output = 85; // 1/3 of 8-bit PWM range for symetrical waveform
@@ -34,7 +32,18 @@ void setup() {
3432
Serial.println(F("AutoTune test exceeds outMax limit. Check output, hysteresis and outputStep values"));
3533
while (1);
3634
}
35+
// Select one, reference: https://github.com/Dlloydev/QuickPID/wiki
36+
//_myPID.AutoTune(tuningMethod::ZIEGLER_NICHOLS_PI);
3737
_myPID.AutoTune(tuningMethod::ZIEGLER_NICHOLS_PID);
38+
//_myPID.AutoTune(tuningMethod::TYREUS_LUYBEN_PI);
39+
//_myPID.AutoTune(tuningMethod::TYREUS_LUYBEN_PID);
40+
//_myPID.AutoTune(tuningMethod::CIANCONE_MARLIN_PI);
41+
//_myPID.AutoTune(tuningMethod::CIANCONE_MARLIN_PID);
42+
//_myPID.AutoTune(tuningMethod::AMIGOF_PID);
43+
//_myPID.AutoTune(tuningMethod::PESSEN_INTEGRAL_PID);
44+
//_myPID.AutoTune(tuningMethod::SOME_OVERSHOOT_PID);
45+
//_myPID.AutoTune(tuningMethod::NO_OVERSHOOT_PID);
46+
3847
_myPID.autoTune->autoTuneConfig(outputStep, hysteresis, setpoint, output, QuickPID::DIRECT, printOrPlotter);
3948
}
4049

examples/AutoTune_Filter_REVERSE/AutoTune_Filter_REVERSE.ino

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/******************************************************************************
22
AutoTune Filter REVERSE Example
3-
Reference: https://github.com/Dlloydev/QuickPID/wiki/AutoTune
43
Circuit: https://github.com/Dlloydev/QuickPID/wiki/AutoTune_RC_Filter
54
******************************************************************************/
65

@@ -16,8 +15,7 @@ const int outputMin = 0;
1615
float POn = 1.0; // mix of PonE to PonM (0.0-1.0)
1716

1817
bool printOrPlotter = 0; // on(1) monitor, off(0) plotter
19-
byte tuningRule = 1; // see reference link
20-
byte outputStep = 1;
18+
byte outputStep = 5;
2119
byte hysteresis = 1;
2220
int setpoint = 341; // 1/3 of 10-bit ADC range for symetrical waveform
2321
int output = 85; // 1/3 of 8-bit PWM range for symetrical waveform
@@ -35,7 +33,18 @@ void setup() {
3533
Serial.println(F("AutoTune test exceeds outMax limit. Check output, hysteresis and outputStep values"));
3634
while (1);
3735
}
36+
// Select one, reference: https://github.com/Dlloydev/QuickPID/wiki
37+
//_myPID.AutoTune(tuningMethod::ZIEGLER_NICHOLS_PI);
3838
_myPID.AutoTune(tuningMethod::ZIEGLER_NICHOLS_PID);
39+
//_myPID.AutoTune(tuningMethod::TYREUS_LUYBEN_PI);
40+
//_myPID.AutoTune(tuningMethod::TYREUS_LUYBEN_PID);
41+
//_myPID.AutoTune(tuningMethod::CIANCONE_MARLIN_PI);
42+
//_myPID.AutoTune(tuningMethod::CIANCONE_MARLIN_PID);
43+
//_myPID.AutoTune(tuningMethod::AMIGOF_PID);
44+
//_myPID.AutoTune(tuningMethod::PESSEN_INTEGRAL_PID);
45+
//_myPID.AutoTune(tuningMethod::SOME_OVERSHOOT_PID);
46+
//_myPID.AutoTune(tuningMethod::NO_OVERSHOOT_PID);
47+
3948
_myPID.autoTune->autoTuneConfig(outputStep, hysteresis, inputMax - setpoint, output, QuickPID::REVERSE, printOrPlotter);
4049
}
4150

library.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"keywords": "PID, controller, signal",
44
"description": "A fast fixed/floating point PID controller with AutoTune and 10 tuning rules to choose from. This controller can automatically determine and set tuning parameters. Compatible with most Arduino and ESP32 boards.",
55
"license": "MIT",
6-
"version": "2.3.0",
6+
"version": "2.3.1",
77
"url": "https://github.com/Dlloydev/QuickPID",
88
"include": "QuickPID",
99
"authors":

library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=QuickPID
2-
version=2.3.0
2+
version=2.3.1
33
author=David Lloyd
44
maintainer=David Lloyd <[email protected]>
55
sentence=A fast fixed/floating point PID controller with AutoTune and 10 tuning rules to choose from.

src/QuickPID.cpp

+22-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**********************************************************************************
2-
QuickPID Library for Arduino - Version 2.3.0
2+
QuickPID Library for Arduino - Version 2.3.1
33
by dlloydev https://github.com/Dlloydev/QuickPID
44
Based on the Arduino PID Library and work on AutoTunePID class
55
by gnalbandian (Gonzalo). Licensed under the MIT License
@@ -53,20 +53,35 @@ bool QuickPID::Compute() {
5353
uint32_t now = micros();
5454
uint32_t timeChange = (now - lastTime);
5555

56-
if (timeChange >= sampleTimeUs) { // Compute the working error variables
56+
if (timeChange >= sampleTimeUs) { // compute the working errors
5757
float input = *myInput;
5858
float dInput = input - lastInput;
5959
error = *mySetpoint - input;
6060
if (controllerDirection == REVERSE) {
6161
error = -error;
6262
dInput = -dInput;
6363
}
64-
if (kpi < 31 && kpd < 31) outputSum += FX_MUL(FL_FX(kpi) , error) - FX_MUL(FL_FX(kpd), (int)dInput); // fixed point
65-
else outputSum += (kpi * error) - (kpd * dInput); // floating-point
64+
// add integral error amount
65+
if (ki < 31) outputSum += FX_MUL(FL_FX(ki), error);
66+
else outputSum += (ki * error);
6667

68+
// proportional on measurement amount
69+
if (kpm < 31) outputSum -= FX_MUL(FL_FX(kpm), dInput);
70+
else outputSum -= (kpm * dInput);
6771
outputSum = CONSTRAIN(outputSum, outMin, outMax);
68-
*myOutput = outputSum;
6972

73+
// proportional on error amount
74+
float output;
75+
if (kpe < 31) output = FX_MUL(FL_FX(kpe), error);
76+
else output = (kpe * error);
77+
78+
// derivative amount
79+
if (kd < 31) output += outputSum - FX_MUL(FL_FX(kd), dInput);
80+
else output += outputSum - kd * dInput;
81+
output = CONSTRAIN(output, outMin, outMax);
82+
*myOutput = output;
83+
84+
// remember some variables for next time
7085
lastInput = input;
7186
lastTime = now;
7287
return true;
@@ -88,8 +103,8 @@ void QuickPID::SetTunings(float Kp, float Ki, float Kd, float POn = 1) {
88103
kp = Kp;
89104
ki = Ki * SampleTimeSec;
90105
kd = Kd / SampleTimeSec;
91-
kpi = (kp * pOn) + ki;
92-
kpd = (kp * (1 - pOn)) + kd;
106+
kpe = kp * pOn;
107+
kpm = kp * (1 - pOn);
93108
}
94109

95110
/* SetTunings(...)*************************************************************
@@ -211,7 +226,6 @@ AutoTunePID::AutoTunePID(float *input, float *output, tuningMethod tuningRule)
211226

212227
void AutoTunePID::reset()
213228
{
214-
215229
_t0 = 0;
216230
_t1 = 0;
217231
_t2 = 0;

src/QuickPID.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ class QuickPID {
133133
float kp; // (P)roportional Tuning Parameter
134134
float ki; // (I)ntegral Tuning Parameter
135135
float kd; // (D)erivative Tuning Parameter
136-
float kpi; // proportional on error amount
137-
float kpd; // proportional on measurement amount
136+
float kpe; // proportional on error amount
137+
float kpm; // proportional on measurement amount
138138

139139
float *myInput; // Pointers to the Input, Output, and Setpoint variables. This creates a
140140
float *myOutput; // hard link between the variables and the PID, freeing the user from having

0 commit comments

Comments
 (0)