|
1 | | -/************************************************************* |
2 | | - PID Relay Output Example |
3 | | - Same as basic example, except that this time, the output |
4 | | - is going to a digital pin which (we presume) is controlling |
5 | | - a relay. The pid is designed to Output an analog value, |
6 | | - but the relay can only be On/Off. |
| 1 | +/**************************************************************************** |
| 2 | + PID Relay Output Example |
| 3 | + https://github.com/Dlloydev/QuickPID/tree/master/examples/PID_RelayOutput |
7 | 4 |
|
8 | | - To connect them together we use "time proportioning |
9 | | - control", essentially a really slow version of PWM. |
10 | | - First we decide on a window size (5000mS for example). |
11 | | - We then set the pid to adjust its output between 0 and that |
12 | | - window size. Lastly, we add some logic that translates the |
13 | | - PID output into "Relay On Time" with the remainder of the |
14 | | - window being "Relay Off Time". The minWindow setting is a |
15 | | - floor (minimum time) the relay would be on. |
16 | | - *************************************************************/ |
| 5 | + Similar to basic example, except the output is a digital pin controlling |
| 6 | + a mechanical relay, SSR, MOSFET or other device. To interface the PID output |
| 7 | + to a digital pin, we use "time proportioning control" (software PWM). |
| 8 | + First we decide on a window size (5000mS for example). We then set the pid |
| 9 | + to adjust its output between 0 and that window size and finally we set the |
| 10 | + PID sample time to that same window size. |
17 | 11 |
|
18 | | -#include "QuickPID.h" |
| 12 | + The digital output has the following features: |
| 13 | + • The PID compute rate controls the rate of updating the digital output |
| 14 | + • All transitions are debounced (rising and falling) |
| 15 | + • Full control range (0 to windowSize) isn't limited by debounce |
| 16 | + • Only one call to digitalWrite() per transition |
| 17 | + *****************************************************************************/ |
19 | 18 |
|
20 | | -#define PIN_INPUT 0 |
21 | | -#define RELAY_PIN 6 |
| 19 | +#include <QuickPID.h> |
22 | 20 |
|
23 | | -//Define Variables we'll be connecting to |
24 | | -float Setpoint, Input, Output; |
| 21 | +// pins |
| 22 | +const byte inputPin = 0; |
| 23 | +const byte relayPin = 3; |
25 | 24 |
|
26 | | -//Specify the links and initial tuning parameters |
27 | | -float Kp = 2, Ki = 5, Kd = 1; |
| 25 | +// user settings |
| 26 | +const unsigned long windowSize = 5000; |
| 27 | +const byte debounce = 50; |
| 28 | +float Input, Output, Setpoint = 30, Kp = 2, Ki = 5, Kd = 1; |
28 | 29 |
|
29 | | -QuickPID myPID(&Input, &Output, &Setpoint); |
| 30 | +// status |
| 31 | +unsigned long windowStartTime, nextSwitchTime; |
| 32 | +boolean relayStatus = false; |
30 | 33 |
|
31 | | -unsigned int WindowSize = 5000; |
32 | | -unsigned int minWindow = 500; |
33 | | -unsigned long windowStartTime; |
| 34 | +QuickPID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, |
| 35 | + myPID.pMode::pOnError, |
| 36 | + myPID.dMode::dOnMeas, |
| 37 | + myPID.iAwMode::iAwClamp, |
| 38 | + myPID.Action::direct); |
34 | 39 |
|
35 | | -void setup() |
36 | | -{ |
37 | | - pinMode(RELAY_PIN, OUTPUT); |
38 | | - windowStartTime = millis(); |
39 | | - |
40 | | - //initialize the variables we're linked to |
41 | | - Setpoint = 100; |
42 | | - |
43 | | - //tell the PID to range between 0 and the full window size |
44 | | - myPID.SetOutputLimits(0, WindowSize); |
45 | | - |
46 | | - //apply PID gains |
47 | | - myPID.SetTunings(Kp, Ki, Kd); |
48 | | - |
49 | | - //turn the PID on |
| 40 | +void setup() { |
| 41 | + pinMode(relayPin, OUTPUT); |
| 42 | + pinMode(LED_BUILTIN, OUTPUT); |
| 43 | + myPID.SetOutputLimits(0, windowSize); |
| 44 | + myPID.SetSampleTimeUs(windowSize * 1000); |
50 | 45 | myPID.SetMode(myPID.Control::automatic); |
51 | 46 | } |
52 | 47 |
|
53 | | -void loop() |
54 | | -{ |
55 | | - Input = analogRead(PIN_INPUT); |
| 48 | +void loop() { |
| 49 | + unsigned long msNow = millis(); |
| 50 | + Input = analogRead(inputPin); |
| 51 | + if (myPID.Compute()) windowStartTime = msNow; |
56 | 52 |
|
57 | | - /************************************************ |
58 | | - turn the output pin on/off based on pid output |
59 | | - ************************************************/ |
60 | | - if (millis() - windowStartTime >= WindowSize) |
61 | | - { //time to shift the Relay Window |
62 | | - windowStartTime += WindowSize; |
63 | | - myPID.Compute(); |
| 53 | + if (!relayStatus && Output > (msNow - windowStartTime)) { |
| 54 | + if (msNow > nextSwitchTime) { |
| 55 | + nextSwitchTime = msNow + debounce; |
| 56 | + relayStatus = true; |
| 57 | + digitalWrite(relayPin, HIGH); |
| 58 | + digitalWrite(LED_BUILTIN, HIGH); |
| 59 | + } |
| 60 | + } else if (relayStatus && Output < (msNow - windowStartTime)) { |
| 61 | + if (msNow > nextSwitchTime) { |
| 62 | + nextSwitchTime = msNow + debounce; |
| 63 | + relayStatus = false; |
| 64 | + digitalWrite(relayPin, LOW); |
| 65 | + digitalWrite(LED_BUILTIN, LOW); |
| 66 | + } |
64 | 67 | } |
65 | | - if (((unsigned int)Output > minWindow) && ((unsigned int)Output > (millis() - windowStartTime))) digitalWrite(RELAY_PIN, HIGH); |
66 | | - else digitalWrite(RELAY_PIN, LOW); |
67 | 68 | } |
0 commit comments