I have implemented PID control to keep a photoresistor at a desired setpoint of "light level" detected by using an LED to come on if the light level drops below the setpoint and the LED will turn off if the light level detected is above the set point. This code is working as stand alone code as it should.
I was wondering if it was possible to write in code so that I could utilise a push button to override these set conditions i.e. when the light level detected is above the set point and the LED is off, would it be possible to "force" this LED on through the use of a push button? If so, what would the code for this look like?
Any help is greatly appreciated, thanks in advance.
#include <PID_v1.h>
const int photores = A0; // Photo resistor input
const int pot = A1; // Potentiometer input
const int led = 9; // LED output
double lightLevel; //variable that stores the incoming light level
const int sw1pin = A2; // input pin: DIL switch 1 on pin A2
int sw1_state = 0; // DIL switch 1 state (HIGH/LOW)
// Tuning parameters
float Kp=0; //Initial Proportional Gain
float Ki=10; //Initial Integral Gain
float Kd=0; //Initial Differential Gain
double Setpoint, Input, Output; //These are just variables for storing values
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); // This sets up our PDID Loop
//Input is our PV
//Output is our u(t)
//Setpoint is our SP
const int sampleRate = 1; // Variable that determines how fast our PID loop runs
// Communication setup
const long serialPing = 500; //This determines how often we ping our loop
// Serial pingback interval in milliseconds
unsigned long now = 0; //This variable is used to keep track of time
// placehodler for current timestamp
unsigned long lastMessage = 0; //This keeps track of when our loop last spoke to serial
// last message timestamp.
void setup(){
lightLevel = analogRead(photores); //Read in light level
Input = map(lightLevel, 0, 1024, 0, 255); //Change read scale to analog out scale
Setpoint = map(analogRead(pot), 0, 1024, 0, 255); //get our setpoint from our pot
Serial.begin(9600); //Start a serial session
myPID.SetMode(AUTOMATIC); //Turn on the PID loop
myPID.SetSampleTime(sampleRate); //Sets the sample rate
Serial.println("Begin"); // Hello World!
lastMessage = millis(); // timestamp
}
void loop(){
Setpoint = map(analogRead(pot), 0, 1024, 0, 255); //Read our setpoint
lightLevel = analogRead(photores); //Get the light level
Input = map(lightLevel, 0, 900, 0, 255); digitalRead(A2); // Map it to the right scale, Read SW1
myPID.Compute(); //Run the PID loop
analogWrite(led, Output); //Write out the output from the PID loop to our LED pin
now = millis(); //Keep track of time
if(now - lastMessage > serialPing) { //If its been long enough give us some info on serial
// this should execute less frequently
// send a message back to the mother ship
Serial.print("Setpoint = ");
Serial.print(Setpoint);
Serial.print(" Input = ");
Serial.print(Input);
Serial.print(" Output = ");
Serial.print(Output);
Serial.print("\n");
lastMessage = now;
//update the time stamp.
}
}
This is my written code, I have declared the push button along with its initial state. How would I initialise the button in the setup() function before entering the command in the loop() function?
Hi brattray23,
that would be my way of doing it; the example is for 2 buttons, and I don't know on which parameter you want to play, but it's a start, if it can inspire you!
(I have changed your name 'sw1pin' in ''button1Plus', I have not seen you already have named it...
.
.
#include <PID_v1.h>
const int photores = A0; // Photo resistor input
const int pot = A1; // Potentiometer input
const int led = 9; // LED output
double lightLevel; //variable that stores the incoming light level
//----------------------------
//const int sw1pin = A2; // input pin: DIL switch 1 on pin A2
//int sw1_state = 0; // DIL switch 1 state (HIGH/LOW)
// Tuning parameters
float Kp=0; //Initial Proportional Gain
float Ki=10; //Initial Integral Gain
float Kd=0; //Initial Differential Gain
double Setpoint, Input, Output; //These are just variables for storing values
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); // This sets up our PDID Loop
//Input is our PV
//Output is our u(t)
//Setpoint is our SP
const int sampleRate = 1; // Variable that determines how fast our PID loop runs
// Communication setup
const long serialPing = 500; //This determines how often we ping our loop
// Serial pingback interval in milliseconds
unsigned long now = 0; //This variable is used to keep track of time
// placehodler for current timestamp
unsigned long lastMessage = 0; //This keeps track of when our loop last spoke to serial
// last message timestamp.
//------------------------------------------------------
#define pinButton1 A2 // PIN + button (fix your pin number here)
#define pinButton2 8 // PIN - button (fix your pin number here)
unsigned long prevmillisButtons; // BUTTON debounce period
#define button1Plus 1 // BUTTON convention: PlusButton value= 1
#define button2Minus 2 // BUTTON convention: MinusButton value= 2
byte buttonStat; // BUTTON state buttons
byte buttonDown; // BUTTON pressed buttons
byte buttonUp; // BUTTON released buttons
byte buttonMemo; // BUTTON memorised state buttons
void setup(){
lightLevel = analogRead(photores); //Read in light level
Input = map(lightLevel, 0, 1024, 0, 255); //Change read scale to analog out scale
Setpoint = map(analogRead(pot), 0, 1024, 0, 255); //get our setpoint from our pot
Serial.begin(9600); //Start a serial session
myPID.SetMode(AUTOMATIC); //Turn on the PID loop
myPID.SetSampleTime(sampleRate); //Sets the sample rate
Serial.println("Begin"); // Hello World!
lastMessage = millis(); // timestamp
//------------------------------------------------------
pinMode (pinButton1, INPUT_PULLUP); //
pinMode (pinButton2, INPUT_PULLUP); //
}
void loop(){
Setpoint = map(analogRead(pot), 0, 1024, 0, 255); //Read our setpoint
lightLevel = analogRead(photores); //Get the light level
Input = map(lightLevel, 0, 900, 0, 255); digitalRead(A2); // Map it to the right scale, Read SW1
myPID.Compute(); //Run the PID loop
analogWrite(led, Output); //Write out the output from the PID loop to our LED pin
now = millis(); //Keep track of time
if(now - lastMessage > serialPing) { //If its been long enough give us some info on serial
// this should execute less frequently
// send a message back to the mother ship
Serial.print("Setpoint = ");
Serial.print(Setpoint);
Serial.print(" Input = ");
Serial.print(Input);
Serial.print(" Output = ");
Serial.print(Output);
Serial.print("\n");
lastMessage = now;
//update the time stamp.
}
//------------------------------------------------------
if (pollButtons()) { // buttons pressed ?
if (button1Plus & buttonDown) {}; // your action here
if (button2Minus & buttonDown) {}; // your action here
}
}
// -----------------------------------------------------
bool pollButtons() { // BUTTONS : DEBOUNCE, FRONT DETECTION
if (millis() - prevmillisButtons > 20) { // 20 ms buttons debounce period
prevmillisButtons = millis(); //
//
byte iii = 0; // (iii and jjj are "local" variables)
if (!digitalRead(pinButton1)) iii = button1Plus; //
if (!digitalRead(pinButton2)) iii |= button2Minus;//
byte jjj = buttonStat; //
buttonStat = iii & buttonMemo; // buttons status
buttonDown = (jjj ^ buttonStat) & buttonStat; // buttons is (are) just pressed
buttonUp = (iii ^ jjj) & jjj; // buttons is (are) just released
buttonMemo = iii; // buttons configuration for next use
//
if (buttonStat | buttonDown | buttonUp) return 1; //
} //
return 0; //
} //
Maybe you only want one switch status information (on or off), in which case a simple read as done in the line 'Input = map(lightLevel...,' is enough (but the A2 pin reading is missing something)
My example is rather intended for the management of several buttons, such as for +, - and enter for example...
Hey people,
Thank you for your replies.
I was looking to keep the code as simple as possible, keeping the same PID loop and just introducing 1 push button which drives the LED output to the maximum mapped value of 255.
The thought behind doing this was to compare this to a manual switch if the PID were to fail in its application to if the LED output was to be stuck at 0 for any given reason.
i seriously doubt there's a need for PID (where is there any lag).
why not simply turn the LED on if the level is below some threshold and off when above some threshold (add a little hysterisis) and simply test for a button press to enable manual control, turning on the LED and disabling manual control when in manual mode
Bingo!
Thank you very much for your patience and assistance.
The PID is working as it's own entity and the push button overrides the output and sets it to max just as desired.
Now for the next task, I plan to add in an "off" override push button before adding in a 7-seg display to show a "1" when the LED is on and a "0" when the LED is off.
Still very much new to this so I appreciate all the help I can get