I'm trying to turn a light "On" and "Off" with Arduino using a Relay, Photo-resistor and Serial Communication. The problem come in to play when I try to turn the light Off when the Photo-resistor is receiving a low value and has received an instruction via Serial Communication to prevent the "IF" statement from activating, it simply doesn't not work as the light is kept on.
I'm using 4 "IF" statement to control the light: auto light using Photo-resistor and serial value resumed in "ON/OFF", turn light on using serial value "h", turn light off using serial value "l" and another serial value to control the auto light statement using "a" to control the first statement.
How can I use a value to control light based on a sensor and serial output at the same time. In other words, how can I stop light from turning on automatically?? What I'm doing wrong or what I left?
Here is my simple code:
char val;
boolean setAuto=true; // Automatic Light Status Value
int ldr;
int relayPin=4;
void setup() {
pinMode(relayPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
ldr = analogRead(A0); // Read value from Photoresistor
if ( Serial.available()) {
val = Serial.read(); // Get serial value
}
if ( setAuto == true && ldr < 50 ) { // Here is the main problem
digitalWrite(relayPin, HIGH);
}
else if ( val == 'h' ) {
digitalWrite(relayPin, HIGH); // Work
}
else if ( val == 'l') {
digitalWrite(relayPin, LOW); // Work
}
else if (val == 'a') { // Here is the other part of the problem
setAuto = !setAuto; // Changing value for automatic light
}
}
The first if statement:
if ( setAuto == true && ldr < 50 ) { // Here is the main problem
digitalWrite(relayPin, HIGH);
} else {
takes precedence over the next two if statements. Since setAuto is ALWAYS true and so when ldr < 50 the light thru relayPin is ON.
Think about how you might want to setAuto to false.
Hint. You might want to evaluate val just after it is read:
if ( Serial.available()) {
val = Serial.read(); // Get serial value
if (val == ..... logic to affect the course of events.....
}
Related
Need to update potentiometer values all time not only once, try different ways but nothing works :(
I think that main problem is that this function while(digitalRead(gotoPositionAPin)); blocks
Now it's read value and save speed
workflow of code
press button right save position a
press button left save position b
update pot speed (set speed)
update pot acceleration (set accel)
press button go to position A (its going with previous set of speed and acceleration)
press button go to position B (its going with previous set of speed and acceleration)
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(1, 12, 11);
#define stepsPerRev 1600
#define stepPin 12
#define dirPin 11
#define ledPin 13
#define rotateLeftPin 7
#define rotateRightPin 6
#define savePositionAPin 5
#define savePositionBPin 4
#define gotoPositionAPin 3
#define gotoPositionBPin 2
#define maxSpeedPin 0
#define accelPin 1
// Set this to zero if you don't want debug messages printed
#define printDebug 0
// These are the constants that define the speed associated with the MaxSpeed pot
#define MAX_STEPS_PER_SECOND 1000 // At 200 s/r and 1/8th microstepping, this will be 333 rev/minute
#define MIN_STEPS_PER_SECOND 27 // At 200 steps/rev and 1/8th microstepping, this will be 1 rev/minute
// Change this value to scale the acceleration pot's scaling factor
#define ACCEL_RATIO 1
int buttonState = 0;
int stepNumber = 0;
int curSpeed = 100;
int dir = 0;
int maxSpeed = 0;
int accel = 0;
long savedPosA = 0;
long savedPosB = 0;
int loopCtr = 0;
float fMaxSpeed = 0.0;
float fStepsPerSecond = 0.0;
void setup()
{
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(rotateLeftPin, INPUT);
pinMode(rotateRightPin, INPUT);
pinMode(savePositionAPin, INPUT);
pinMode(savePositionBPin, INPUT);
pinMode(gotoPositionAPin, INPUT);
pinMode(gotoPositionBPin, INPUT);
if (printDebug)
{
// Initialize the Serial port
Serial.begin(9600);
}
// blink the LED:
blink(2);
stepper1.setMaxSpeed(800.0);
stepper1.setAcceleration(600.0);
// Grab both speed and accel before we start
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
accel = analogRead(accelPin)/ACCEL_RATIO;
}
void loop()
{
// First, we need to see if either rotate button is down. They always take precidence.
if(digitalRead(rotateLeftPin))
{
stepper1.setSpeed(-fStepsPerSecond);
while(digitalRead(rotateLeftPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(-fStepsPerSecond);
}
}
else if (digitalRead(rotateRightPin))
{
stepper1.setSpeed(fStepsPerSecond);
while(digitalRead(rotateRightPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(fStepsPerSecond);
}
}
// Go see if we need to update our analog conversions
CheckPots();
// Check to see if user is trying to save position A or B
if(digitalRead(savePositionAPin))
{
savedPosA = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved A at :");
Serial.println(savedPosA);
}
while(digitalRead(savePositionAPin));
}
if(digitalRead(savePositionBPin))
{
savedPosB = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved B at :");
Serial.println(savedPosB);
}
while(digitalRead(savePositionBPin));
}
// Check to see if the user wants to go to position A or B
if (digitalRead(gotoPositionAPin))
{
if (printDebug)
{
// Yup, let's go to position A
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to A = ");
Serial.println(savedPosA);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosA);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionAPin));
}
else if (digitalRead(gotoPositionBPin))
{
// Yup, let's go to position B
if (printDebug)
{
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to B = ");
Serial.println(savedPosB);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosB);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionBPin));
}
}
// Blink the reset LED:
void blink(int howManyTimes)
{
int i;
for (i=0; i < howManyTimes; i++)
{
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
}
void CheckPots(void)
{
loopCtr++;
// Only read these once in a while because they take a LONG time
if (loopCtr == 100)
{
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
}
// Read in the acceleration analog value
// This needs to be scaled too, but to what?
if (loopCtr >= 200)
{
accel = analogRead(accelPin)/ACCEL_RATIO;
loopCtr = 0;
}
}
If you're looking into "continuous operation" but don't want to introduce interrupts into your code (which will have special requirements in and of itself) there are a couple of things you need to get rid of:
Endless loops like: while(digitalRead(savePositionAPin));
System waits like: delay(200); as in your blink()
and instead use state variables. State variables are more or less what the name says: variables that hold the state of something, so you know what value the button, or timer, or counter had last time.
So, instead of a while-loop waiting for a button to be released, just set a global or static boolean that knows what state you were in the last time loop() ran, so you don't trigger the button action again. You need one boolean flag for each button.
And instead of delays, either create a state variable that holds "passed time" which you can get from millis() for example. So don't wait but instead you should just check if a certain amount of time has passed so you can toggle the state of the LED.
Adding a blinking LED to loop() - (untested example):
#define LEDWAIT 300
unsigned long myTime = 0;
bool onoff = false;
loop()
{
if (myTime == 0)
myTime = millis();
if ((millis() - myTime) > LEDWAIT) {
digitalWrite(ledPin, onoff ? HIGH : LOW);
onoff = !onoff;
myTime = millis();
}
// do other things
}
It is not entirely clear to me what your program is supposed to do and what the error is, so please correct me if I am wrong: You want to update a value based on which button is pressed? What is your opinion on using interrupts for triggering the updates?
You may want to edit the formating of your question.
I have 2 buttons connected to 5 volts on 1 end and to D4 and D2 in stm32F401RE board. I want to drive 2 digital outputs ,D7 and D0, on some LEDs that are on series with a resistance respectively ending to ground. An extra feature was to light a board LED for a specific time which is why I have written the while scantimes part.
I have written the code but I get an error to put ; after 10 in the if statement,even after I put it, it wont fix/compile.
#include "mbed.h"
#define BLINKING_RATE 500ms
int main()
{
int scantimes = 0;
DigitalIn button1(D4);
DigitalIn button2(D2);
DigitalOut ledred(D7);
DigitalOut ledgreen(D0);
if(button1 || button2 == 1){
scantimes = 10
if(button1 == 1){
ledred == 1
}
if(button2 == 1){
ledgreen == 1
}
};
#ifdef LED2
DigitalOut led(LED2);
#else
bool led;
#endif
while (scantimes>=0) {
led = !led;
ThisThread::sleep_for(BLINKING_RATE);
}
}
Don't have "mbed.h" so can't compile, however:
in your code:
if(button1 || button2 == 1){
scantimes = 10
if(button1 == 1){
ledred == 1
}
if(button2 == 1){
ledgreen == 1
}
};
the conditional "==" operator is used in both the condition of the if statement as well as within the body of the statement.
if the goal is to "set" ledgreen or ledred to 1, use "=" instead of "==". otherwise the program is just checking whether the led's are equal to one, rather than setting their value.
Also, semicolons will be needed at the end of each statement.
To give a short summary of my project, it’s a smart parking system where I let a parking user know whether a parking lot is vacant or not. I’m implementing an XBee network containing 1 coordinator and 2 routers. I have two sensors, 1 sensor at the exit and 1 at the entrance. Those two sensors are the routers and whatever data they gather is being transmitted to the coordinator (output). The two routers have the same code which is:
INPUT CODE (TRANSMITTING):
#include<SoftwareSerial.h>
#define Sensor 8
void setup() {
pinMode(Sensor,INPUT);
Serial.begin(9600);
}
void loop()
{
bool Detection = digitalRead(Sensor);
int carexit=1;
if(Detection == HIGH)
{
Serial.println("Car Exit");
Serial.write(carexit);
}
if(Detection == LOW)
{
Serial.println("Clear");
}
}
It’s a very simple code where it detects a car coming in or out. Since the two routers are the same we’ll use the sensor for the cars exiting. When I open the serial monitor, the word “Clear” will keep on being outputted continuously nonstop until detection is found which will show an output of “Car Exit” for about 3 seconds and then return to “Clear” continuously. This data is being transmitted to the coordinator. What I’m trying to do is take that continuous data and have the serial monitor at the coordinator input a single integer value. For example, at the entrance, the sensor will sense the car and transmit the data to the coordinator where it'll increment. The result will show something like this if there’s only 1 vacant slot available:
Vacant slots: 1
and when the car exits the router at the exit, it will transmit a code to the coordinator decrementing it:
Vacant slots: 0
So, the input(router) would be transmitting continuous data while the output(transmitter) will detect it and just register it for a single-digit value. The output code(receiving) by the way is shown below:
OUTPUT CODE(RECEIVING):
#include "SoftwareSerial.h"
// RX: Arduino pin 2, XBee pin DOUT. TX: Arduino pin 3, XBee pin DIN
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 0)
{
Serial.write(Serial.read());
}
}
The output code is pretty simple as well. Let me know if there’s any possible way to implement what I’m trying to do and if there are any other details I left out, let me know as well.
Thank you!
This is a very common problem, best solved at the source, in your sensor transmit code.
//...
bool PreviousDetection = false;
void loop()
{
bool Detection = digitalRead(Sensor);
// do not do anything when state hasn't changed.
if (Detection != PreviousDetection)
{
if (Detection)
Serial.println("Car Exit");
else
Serial.println("Clear");
}
PreviousDetection = Detection;
}
You may want to add some debouncing to reduce the risk of false readings.
//...
// Debounce thresholds the number depends on the frequency of readings,
// speeed of cars, sensitivity and placement of your sensor...
// Dirt, sun exposure, etc... may influence readings in the long term.
const int LowDebounceThreshold = 3;
const int HighDebounceThreshold = 3;
bool PreviousDetection = false;
int DebounceCounter = 0;
bool DebouncedPreviousDetection = false;
void loop()
{
bool Detection = digitalRead(Sensor);
//
if (Detection == PreviousDetection)
++DebounceCounter; // this will rollover, but will not affect
// DebouncedDetection in any meaningfull way.
else
DebounceCounter = 0;
PreviousDetection = Detection;
bool DebouncedDetection = PreviousDebouncedDetection;
if (Detection && DebounceCounter >= HighDebounceThreshold)
DebouncedDetection = true;
else if (!Detection && DebounceCounter >= LowDebounceThreshold)
DebouncedDetection = false;
if (DebouncedDetection != PreviousDebouncedDetection)
{
PreviousDebouncedDetection = DebouncedDetection;
if (DebouncedDetection)
Serial.println("Car Exit");
else
Serial.println("Clear");
}
}
I need my code to stop in the loop, i have tried to put in a break but the method sendToGCM() continues. I only want the method to be executed once, the stop while the condition
void loop()
{
// Other code here giving temp a value
if (temp > 22)
{
status = false;
value["status"] = status;
while (temp > 22)
{
sendToGCM(); // Sends push notification
break;
}
}
else
{
status = true;
value["status"] = status;
}
}
So if I understood you correctly, if the temperature goes 22 degrees you want to send a message, but only the first time. If you break the loop, you still enter it if you the loop() function is executed again.
In order to achieve what you want to do, you code will need to look something like this
boolean message_sent;
void loop() {
...
if(temperature > 22 && !message_sent) {
sendToGCM();
message_sent = true;
}
}
If you want to send a message every time the temperature rises over 22 degrees you would need something like this
boolean message_sent;
boolean was_under_22;
void setup() {
...
was_under_22 = function_that_checks_if_temp_is_under_22();
...
}
void loop() {
...
if(temperature > 22 && was_under_22) {
if(!message_sent) {
sendToGCM();
message_sent = true;
was_under_22 = false;
}
} else {
was_under_22 = true;
message_sent = false;
}
}
EDIT: slightly adapted the code in response to Patrick Trentin's comment. The code assumes you only want to capture if the temperature rises above 22 degrees and that if the Arduino starts with over 22 degrees then no message is sent.
Your problem is that you are setting temp, then entering the loop that checks that value. A simple solution would be to update the temp value inside the while loop, to give the application a chance to break out of the while loop.
Example:
void loop()
{
// Other code here giving temp a value
if (temp > 22)
{
status = false;
value["status"] = status;
while (temp > 22)
{
sendToGCM(); // Sends push notification
//Additional code to set the value of temp, allowing the value to
//be greater than 22.
}
}
else
{
status = true;
value["status"] = status;
}
}
Please note that the above example is intended to continuously send the push notification while the temp value is over 22. If that's not the intention, just remove the sendToGCM() from the while loop. You will still only send it if the temp is greater than 22, since you have the if check.
Currently I am using an Arduino in combination with Python. I am writing the Python code now and for an unknown reason it breaks halfway an if-loop. I think the reason might be the serial communication... I'll try to explain it with my code.
For easy reading: the parts of the code that are of interest are between rows of '====='. I put the rest of the code in for context.
Arduino Code
const int mPin = 2; // Pin attached to the Mark button
const int cPin = 3; // Pin attached to the Capture button
const int qPin = 4; // Pin attached to the Quit button
const int solAPin = 6; // Solenoid logic pin A - RELEASE PIN
const int solBPin = 7; // Solenoid logic pin B - CLOSE PIN
const int ledPin = 13; // Onboard LED
boolean lastmButton = 0;
boolean currmButton = 0;
boolean lastcButton = 0;
boolean currcButton = 0;
boolean lastqButton = 0;
boolean currqButton = 0;
void setup() {
// Initial code, run at startup
pinMode(mPin, INPUT); // Reads button press
pinMode(cPin, INPUT); // Reads button press
pinMode(qPin, INPUT); // Reads button press
pinMode(solAPin, OUTPUT);
pinMode(solBPin, OUTPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(solAPin, LOW);
digitalWrite(solBPin, LOW);
digitalWrite(ledPin, LOW);
Serial.begin(9600); // Open Python communication line
}
boolean debounce(boolean last, int Pin) {
boolean current = digitalRead(Pin);
if (last != current)
{
delay(5);
current = digitalRead(Pin);
}
return current;
}
void loop() {
// Main code, continious loop
currmButton = debounce(lastmButton, mPin);
currcButton = debounce(lastcButton, cPin);
currqButton = debounce(lastqButton, qPin);
// ===========================================================
if (currmButton == HIGH && lastmButton == LOW) {
mark();
}
if (currcButton == HIGH && lastcButton == LOW) {
Serial.print("C");
}
if (currqButton == HIGH && lastqButton == LOW) {
Serial.print("Q");
}
lastmButton = currmButton;
lastcButton = currcButton;
lastqButton = currqButton;
}
//==============================================================
void mark() {
digitalWrite(solBPin, HIGH); // Close Pin, pencil moves down
delay(300);
digitalWrite(solBPin, LOW);
digitalWrite(solAPin, HIGH); // Release Pin
delay(100);
digitalWrite(solAPin, LOW); // Neutral
Serial.print("M");
}
The debounce-code is not optimal, but it works for now. As you can see; the Arduino writes M/C/Q to Python when respectively the M/C/Q buttons is pressed. This all works fine.
Now the problem:
Python Code
if (__name__ == '__main__' and fail == False):
# Create directory
print("Startup")
index = 1 # Image counter
if os.path.exists(image_path) == False:
os.makedirs(image_path)
# Find the Arduino Port
try:
portname = ""
ports = list(serial.tools.list_ports.comports())
for p in ports:
if "Arduino" in p[1]:
portname = p[0]
break
print("Arduino found on " + portname)
except:
print("Setup failed:\n Arduino not found")
fail = True
# Open Arduino serial communication
try:
arduino = serial.Serial(portname, baudrate=9600, timeout=1)
arduino.close()
arduino.open()
print("Arduino Connected")
except serial.SerialException:
print("Setup failed:\n Could not connect to Arduino")
fail = True
# Find and open the camera stream
try:
for i in range (10):
cap = cv2.VideoCapture(i)
if (cap.read()):
if cap.isOpened() == False:
cap.open()
break
print("Camera Connected\n")
except:
print("Setup failed:\n Camera not found")
fail = True
#%%# MAIN LOOP
#====================================================================
while True:
k = arduino.readline()
if k == 'M': # Mark & capture
print('Arduino: Marked')
print ("Python Captured\n")
elif k == 'C':# Capture
print "Arduino: Python, capture this dot please" # This line is executed when K == C (button pressed on Arduino)
print "Python: Captured!\n" # This line is not executed directly afterwards, but appears together with the line above when the button is pressed for the SECOND time!
elif k == 'Q': # Quit
print "Arduino: Quit the program"
break
#=====================================================================
When running the Python code, the Arduino connection is set up. When one of the buttons is pressed, the Arduino sends the correct signal to Python, so far so good. But: only the first row of the if-loop is executed. The remaining rows are executed when the button is pressed for the second time, followed by the first row again (since the button is pressed for a second time).
For instance, running the code and pressing 'C' twice results in the following console output:
Startup
Arduino found on COM4
Arduino Connected
Camera Connected
[button C is pressed for first time]
Arduino: Python, capture this dot please
[buttong C is pressed for second time]
Python: Captured!
Arduino: Python, capture this dot please
What I've tried so far:
Placing delays in the Arduino code
Placing 'Serial.flush()' in the Arduino code
Adjusting the way the info is printed, different quotes/brackets etc.
So this is where I'm stuck and I don't really know where to look for the bug. If any extra information is necessary, I'm happy to provide it. I hope someone here can help me!
EDIT:
As I mentioned in the comments, placing a print-command in the while loop magically fixes the issue:
k = arduino.readline()
print k
if k == 'M': # Mark & capture
But why this resolves the issue is still unclear to me.
Thanks in advance,
Stijn