Toggled LED and MotorFan State unable to TOGGLE back after delay - arduino

functionality:
User approaches ultrasonic/infra-red sensor connected to Arduino Uno, if the proximity distance is less than 20cm, triggerPin of ultrasonic/infra-red sensor will toggle from LOW to HIGH -> list of '0's will be toggled to list of '1's.
When the ultrasonic/infra-red sensor is toggled from '0' to '1', the state LED and state MotorFan will toggle to HIGH from LOW. Both states will remain as long as the return data from the ultrasonic sensor is '1'.
When user leaves the proximity of the ultrasonic/infra-red sensor, triggerPin of ultrasonic/infra-red sensor will toggle from HIGH to LOW -> list of '1's will be toggled to list of '0's.
However, at this point, the state LED and state MotorFan will remain in state HIGH for 10s, before toggling to state LOW. In the event, that another user approaches the proximity sensor and the ultrasonic/infra-red sensor toggles back to '1' within the delay of the 10s, state LED and state MotorFan should remain in state HIGH without toggling.
Therefore, the correct flow as follows:
ultrasonic/infra-red Sensor returns '0's -> but when sense user within (distance < 20) ultrasonic/infra-red sensor toggles to '1's when ultrasonic/infra-red sensor toggles to '1's, MotorFan state and LED state will toggle to HIGH from LOW ultrasonic/infra-red Sensor is returns '1's when sensing proximity-> but when sense user more (distance > 20) ultrasonic/infra-red sensor toggles to '0's, at this moment, MotorFan state and LED state will remain in state HIGH for 10s before toggling to LOW. Condition: when another user approaches before the 10s delay is up, MotorFan state and LED state will remain in state HIGH.
What I have done:
I have assigned the following digital pins for the following vairable:
trigPin of ultrasonic sensor is digital Pin 8 echoPin of ultrasonic sensor is digital Pin 9 FanPin of motor Fan is digital Pin 5 LED is assigned to relay 4.
Secondly, I have tried to make use of millis() to get the time and if it should exceed limit of 10000, it will digitalWrite both state to LOW from HIGH.
Code:
const int trigPin = 8;
const int echoPin = 9;
//Motor-Fan connected to arduino pin number
const int FanPin = 5;
byte relay = 4;
long duration;
int distance;
unsigned long Timer;
unsigned long Interval = 10000; //teh repeat Interval
void setup() {
Timer = millis();
pinMode(FanPin, OUTPUT); // Set pinMode for FanPin as OUTPUT, display
pinMode(trigPin, OUTPUT);
pinMode(relay, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600); // Open serial port to communicate with the Ultrasaonic Sensor
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
if (distance < 20) {
// Write a pin of HIGH
Serial.println("1");
//Set motor-fan to operate
digitalWrite(FanPin, HIGH);
digitalWrite(relay, HIGH);
} else {
Serial.println("0");
//Check if Timer is longer than 10s
if ((millis() - Timer) > Interval) {
digitalWrite(FanPin, LOW);
digitalWrite(relay, LOW);
}
}
delay(100);
}
Issue:
The Sensor is able to toggle from '0' to '1' when sense proximity, secondly, it is also able to toggle both the LED state and motorFan state to HIGH from LOW.
However, Both the LED state and motorFan toggle back to LOW when the Arduino sensor toggle from HIGH to LOW without waiting for the 10s delay
I would like to request for some assistance on this as I am absolutely stuck on this problem.
Thanks

You assign a value to Timer in setup() function, which means you do it only once, when the system starts. I would move Timer = millis(); to if (distance < 20) { condition. Then, if user moves out if sensing distance, you will already have a time of "last contact".
Remember: if you want to have something executed only at startup - put it in setup(). If you want something to be executed repeatedly - put it in the loop().

Related

Arduino - Light is staying on for more than expected duration

Code is suppose to Light the inbuit-LED at Pin 13 whenever Pin 5 is High, however i have encountered couple of problem.
While measuring Voltage though Digital Meter - one pin at arduino GND and other at 1,2,3,4. They are showing some non-zero values. Earlier triggering Pin was 4 and light was staying on all the time.
When Pin 5 is high (by connecting 5V Pin from Arduino to Pin 5) it lights the LED as it should, but if Pin 5 stays high for more than 1/2 second, light stays high for more than 0.5 second even after the Pin 5 is disconnected from 5V Pin.
int buttonState = LOW;
int light = 13;
void setup() {
// put your setup code here, to run once:
pinMode(gateopen,INPUT);
pinMode(light, OUTPUT);
}
void loop()
{
// put your main code here, to run repeatedly:
buttonState = digitalRead(gateopen);
if (buttonState == HIGH)
{
digitalWrite(light, HIGH);
}
else
{
digitalWrite(light, LOW);
}
//delayMicroseconds(500);
}
As suggested earlier, use a pull down resistor. Or change your circuit to active low and use INPUT_PULLUP.
I believe you're using delayMicroSeconds, which means the led is just blinking waaay too fast for your eyes. If you want 'half a second' as you hinted on your query, you would be using delay(500) instead.
You are experiencing electrical noise, just like Juraj said, just put a 220 Ohm pull down resistor

How to constantly listen for button input in Arduino?

I am trying to create a working physical simulation of a traffic light intersection. I want to listen for button readings (pedestrian buttons to turn pedestrian lights green) continuously throughout the program and want to run a different function that will handle pedestrian lights if the buttons are ever pressed during the program.
I have tried it with while loops and if conditions but it just won't work because then it would read the button input at a specific point in time when I want it to read the readings constantly throughout the program and break the loop if the condition is ever untrue (while and do-while loops only check the condition at the end of the loop when I want it to check the condition throughout the loop). I also need to get which button was pressed if that possible. Then depending on which button was pressed, I want to run a function called pedes() or pedes2().
Feel free to ask if you need any clarifications.
I have posted my original code below that I want to run constantly until a button will be pressed.
Thanks!
// If at any point in time during this code, a button is pushed, I want to run a function called
pedes() or pedes2() depending on which button is pressed.
// First set of Trafiic Lights
int redT = 13 ;
int yellowT = 12;
int greenT = 11;
// First set of Pedestrian Lights
int redP = 10;
int greenP = 9;
// Second set of Traffic Lights
int redT2 = 8;
int yellowT2 = 7;
int greenT2 = 6;
// Second set of Pedestrian Lights
int redP2 = 5;
int greenP2 = 4;
// Pedestrian Buttons
int buttonT = 3;
int buttonT2 = 2;
int buttonT3 = 1;
int buttonT4 = 0;
int buttonStateT = 0;
int buttonStateT2 = 0;
int buttonStateT3 = 0;
int buttonStateT4 = 0;
// Booleans which will handle which button was pressed
void setup() {
// First set of Trafiic Lights
pinMode(redT, OUTPUT);
pinMode(yellowT, OUTPUT);
pinMode(greenT, OUTPUT);
// First set of Pedestrian Lights
pinMode(redP, OUTPUT);
pinMode(greenP, OUTPUT);
// Second set of Traffic Lights
pinMode(redT2, OUTPUT);
pinMode(yellowT2, OUTPUT);
pinMode(greenT2, OUTPUT);
// Second set of Pedestrian Lights
pinMode(redP2, OUTPUT);
pinMode(greenP2, OUTPUT);
// Pedestrian Buttons
pinMode(buttonT, INPUT);
pinMode(buttonT2, INPUT);
pinMode(buttonT3, INPUT);
pinMode(buttonP4, INPUT);
}
void loop() {
// Resetting all the traffic lights
digitalWrite(redP, HIGH); // Turns on red pedestrian LED from 1st bunch
digitalWrite(redP2, HIGH); // Turns on red pedestrian LED from 2nd bunch
digitalWrite(yellowT, LOW); // Turns off yellow traffic LED from 1st bunch
digitalWrite(yellowT2, LOW); // Turns off yellow traffic LED from 1st bunch
digitalWrite(redT, HIGH); // Turns on red traffic LED from 1st bunch
digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch
delay(2000);
digitalWrite(redT, LOW); // Turns off red traffic LED from 1st bunch
digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch
digitalWrite(greenT, HIGH); // Turns on green traffic LED from 1st bunch
digitalWrite(greenT2, LOW); // Turns off green traffic LED from 2nd bunch
delay(10000); // Pauses program for 8 seconds
digitalWrite(greenT, LOW); // Turns off green traffic LED from 1st bunch
digitalWrite(yellowT, HIGH); // Turns on yellow traffic LED from 1st bunch
delay(3000); // Pauses program for 3 seconds
digitalWrite(yellowT, LOW); // Turns off yellow traffic LED from 1st bunch
digitalWrite(redT, HIGH); // Turns on red traffic LED from 1st bunch
delay(2000); // Pauses program for 3 seconds
digitalWrite(redT2, LOW); // Turns off red traffic LED from 2nd bunch
digitalWrite(greenT2, HIGH); // Turns on green traffic LED from 2nd bunch
delay(6000); // Pauses program for 8 seconds
digitalWrite(greenT2, LOW); // Turns off green traffic LED from 2nd bunch
digitalWrite(yellowT2, HIGH); // Turns on yellow traffic LED from 2nd bunch
delay(3000); // Pauses program for 3 seconds
digitalWrite(yellowT2, LOW); // Turns off yellow traffic LED from 2nd bunch
digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch
delay(2000); // Pauses program for 3 seconds
}
Instead of constantly polling you could use an interrupt on the button pin and set a flag or call a function from within the interrupt routine.
Also make sure to debounce the button in hardware or software.
Since you seem to be learning, here are some extra improvements you could add as an exercise:
To switch the lights you could use timer interrupts instead of delays (you could even put the mcu in sleep mode in between).
Another improvement would be to create a TrafficLight class which contains all the logic. Here is an interesting tutorial. This way you could easily create multiple objects: TrafficLight tl1(..), tl2(..); or even arrays of traffic lights (for example with the same timings).
You could then even create a class Intersection which contains all the traffic lights and the logic for that intersection.
Well if you delay for 10 seconds you cannot react to something in the meantime.
You can use millis() to implement a non-blocking delay.
https://www.arduino.cc/en/tutorial/BlinkWithoutDelay
Instead of being idle and unable to respond you spend your time with checking and responding to your button states and/or time conditions.
Avoid using delays. Delays will pause everything until the time is up, which makes everything less responsive. Delays are useful when learning how to code, but they can hinder usability if you need to react to an external sensor or button.
A better habit to get into is using timers instead of delays. This lets your code keep looping without pausing, and you can add code to check for user input more frequently.
Here is an example of what you should NOT do:
void loop() {
digitalWrite(MY_LED,HIGH);
delay(1000);
digitalWrite(MY_LED,LOW);
delay(1000);
//This code only gets reached every 2 seconds
//This means you may need to hold the button for up to
//2 seconds before it will print a message
if (digitalRead(MY_BUTTON) == LOW) {
Serial.println("You pressed the button");
}
}
You can use millis() to return the number of milliseconds since the arduino started running. Here is a basic example of a timer:
bool ledState = false;
unsigned long toggledTime = 0; //The last time we toggled the led
void loop() {
//Calculate how much time has passed since the last time
//we turned the LED on or off
unsigned long timeElapsedSinceLastToggle = millis() - toggledTime;
//If 1000ms (1s) has passed, we'll toggle the LED
if (timeElapsedSinceLastToggle > 1000) {
ledState = !ledState; //Invert the state
digitalWrite(MY_LED,ledState); //Perform the action
toggledTime = millis(); //Reset our timer to the current time
}
//This code now checks very frequently since the code above
//never uses delay()
if (digitalRead(MY_BUTTON) == LOW) {
Serial.println("You pressed the button");
}
}
I would recommend using a different timer for each LED that you want to toggle. This will make your code much more responsive, and your buttons will respond (nearly) instantly.
There is one thing you will want to be careful with regarding timers. millis() is how many milliseconds since boot, but what happens when your code runs for a very long time? millis() resets (starts over at 0) after about 50 days. For lots of people, this doesn't matter much, but it is worth keeping in mind if your code will be running indefinitely for long periods of time.

Concerning HC-SR04's capability in measuring distance

I am currently working with the HC-SR04 ultrasonic sensor to measure the distance from the sensor to the surface.
Problem is that the resulting value from the sensor is neither consistent nor accurate within reason.
I read that the HC-SR04 has a maximum reading range of up to 400cm.
My current situation is that the sensor can reasonably measure up to 20 cm, but when it exceeds that it rapidly fails.
For example, the distance between the sensor and surface is approximately 170cm, but the sensor says it is approximately 50cm.
Here is how pins are connected.
HC-SR04------Arduino.
Trig to 13.
Echo to 12
Vcc to 5V
GND to GND
Here is my code for Arduino.
#define echoPin1 12
#define trigPin1 13
float duration;
float distance1_1;
void setup()
{
pinMode (echoPin1, INPUT);
pinMode (trigPin1, OUTPUT);
digitalWrite(trigPin1, LOW);
Serial.begin (9600);
Serial.println("Program Begins");
}
void loop()
{
DIST();
delay (1000);
}
void DIST()
{
digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
duration=pulseIn(echoPin1, HIGH);
distance1_1=(duration*0.0343)/2;
Serial.println("Distance")
Serial.println(distance1_1);
}
Try using different Arduino pins for connecting the echo and trigger pins. The pin 13 of Arduino is connected to the LED and there are some reports of problems while using pin13 for the ultrasonic sensor on certain Arduino models/revisions. So first try changing the pins.
Next, try a spare sensor (if available) and see if the results are consistent. Sometimes the problem is with the broken ultrasonic sensor.
Also, we need to know the exact hardware setput i.e. how are you mounting the sensor. There could be stray reflections from the nearby objects so need to be careful while mounting the sensor.
Finally, the return type of pulseIn is unsigned long. So you should
store the value from pulseIn in a long datatype, not float.

PIR Sensor that turns on DC Motors

I'm working on a side project where once motion is detected by the PIR sensor, the DC motors (2x) will turn on for 5 seconds and then shut off. And if the motion has stopped, then the DC motors will turn off.
So my problem is that I am not achieving the desired results I just mentioned above. From my perspective, it seems that my motion sensor is just going off and on, on its own and the DC motors are behaving how they should be with going on for 5 seconds, but the motion sensor is saying that there is motion despite there being motion, which causes the DC motors to run. The DC motors should run when there is motion.
I have tried this exact hardware and components on another arduino UNO and breadboard, the problem seems to be code related.
I have also tried taking a step back and seeing if I can get the motion detection to turn on a LED light. In the Serial monitor it seems to be picking up that there is motion being detected, but really there isn't.
I also tried adjusting the potentiometer on the PIR sensor as well as (adjusting the sensitivity and time) of it. I have also tried switching the "repeatable" trigger and the "non-repeatable" trigger around and seeing if that was an issue.
I have tried swapping the 9V battery to see if that was affecting the performance of the DC motors.
I also doubled checked and made sure each wire was in the correct placement.
As of now, below is the serial monitor... for the given code I provided. This is what the it is providing me. **Keep in mind, that I am not putting any motion into the arduino unit, and for some odd reason it detects that there is motion.
Here is what the Serial Monitor is showing...
2:31:43.219 -> Motors are ON
02:31:43.219 -> Motion detected!
02:31:48.215 -> Motors are ON
02:31:48.249 -> Motors are OFF
02:31:48.249 -> Motion stopped!
02:31:53.232 -> Motors are ON
02:31:53.232 -> Motion detected!
02:31:58.220 -> Motors are ON
02:31:58.253 -> Motors are OFF
02:31:58.253 -> Motion stopped!
02:32:03.238 -> Motors are ON
02:32:03.238 -> Motion detected!
02:32:08.230 -> Motors are ON
02:32:08.265 -> Motors are OFF
02:32:08.265 -> Motion stopped!
const int switchMotion=2;
const int motorPin=9;
const int motorPinB=8;
int motionState=0;
int motionDetected = LOW;
void setup() {
//Selecting as an input and output the switch and the motor
pinMode(switchMotion,INPUT);
pinMode(motorPin,OUTPUT);
pinMode(motorPinB, OUTPUT);
Serial.begin(9600); //Set serial out if we want debugging
delay(5000); //Allow time for the PIR Sensor to calibrate
}
void loop() {
motionState = digitalRead(switchMotion); // Reads the motion sensor
if(motionState == HIGH) // checks if Sensor is HIGH
{
digitalWrite(motorPin,HIGH); //turn on Motor A
digitalWrite(motorPinB,HIGH); //turn on Motor B
delay(5000); //runs for 5 seconds and stops
Serial.println("Motors are ON");
if (motionDetected == LOW) {
Serial.println("Motion detected!"); // print Motion Detected
motionDetected = HIGH; // update variable state to HIGH
}
else {
digitalWrite(motorPin,LOW); //turn off Motor A
digitalWrite(motorPinB,LOW); //turn off Motor B
Serial.println("Motors are OFF");
if (motionDetected == HIGH){
Serial.println("Motion stopped!");
motionDetected = LOW; // update variable state to LOW
}
}
}
}
The goal is to have it where once an individual is near the PIR motion sensor the DC motors turn on for a set period of time and when the time period is up, the motors turn off and there is a set delay time for the motion sensor to detect movement again for the DC motors to turn on again. It should be a constant cycle, where when there is not movement - the DC motors should be off. And when there is movement - the DC motors should be on. The exception is that there is a cooling time.
Actual results are that
I expect motionDetected to function properly, but when it's time to test it, it is reading that there is motion detected/not detected despite there being no real movement. My expected results is for the motion sensor to function properly so the DC motors can turn on/off accordingly.
I'm not sure I understand but if i'm correct isn't this just what you are looking for:
const int switchMotion = 2;
const int motorPin = 9;
const int motorPinB = 8;
void setup() {
//Selecting as an input and output the switch and the motor
pinMode(switchMotion,INPUT);
pinMode(motorPin,OUTPUT);
pinMode(motorPinB, OUTPUT);
Serial.begin(9600); //Set serial out if we want debugging
delay(5000); //Allow time for the PIR Sensor to calibrate
}
void loop() {
if(digitalRead(switchMotion) == HIGH) // checks if Sensor is HIGH
{
Serial.println("Motion detected!");
digitalWrite(motorPin, HIGH); //turn on Motor A
digitalWrite(motorPinB, HIGH); //turn on Motor B
Serial.println("Motors are ON");
delay(5000); //runs for 5 seconds and stops
digitalWrite(motorPin, LOW); //turn off Motor A
digitalWrite(motorPinB, LOW); //turn off Motor B
Serial.println("Motors are OFF");
}
// You can add a delay here if you want
}
Your logic is messed up.
If the sensor is low, nothing happens.
first run of loop after sensor turned high:
turn on the motors,
wait 5 seconds,
print "Motors are ON",
print "Motion detected",
set motionDetected HIGH.
second run of loop (if sensor is still high):
turn on the motors,
wait 5 seconds,
print "Motors are ON",
now motionDetected is HIGH so:
turn off motors
print "Motors are OFF"
print "Motion stopped"
set motionDetected LOW
second run of loop if (sensor is low again):
nothing happens -> motors stay on
To fix this make sure the else belongs to the correct if!
You want to turn the motors off when the sensor is low, not when the sensor is high and was high before.
Also the prints should be placed befor the delay. What's the point of printing "motion detected" 5 seconds after you actually detected it.

Arduino Motor fan will not TOGGLE from HIGH to LOW after delay

Functionality:
Have made use of of IR sensor to toggle the state of LED light and motorFAN. Therefore, when trigger distance condition is met, both LED light and motorFAN state will toggle from LOW to HIGH. After a delay of 5 seconds, the motorFAN state will toggle from HIGH to LOW, while the state of the LED light will remain HIGH, as long as the trigger distance condition is met. The LED light will toggle to LOW when the trigger distance is no longer satisfied.
Issue:
When the trigger distance condition is met, both the LED light and motorFAN state will toggle from LOW to HIGH.
However, the motorFan state will not toggle from HIGH to LOW after a 5 seconds delay, it will still remain HIGH.
Second issue, after both LED light and motorFan state has toggled to LOW from HIGH when the trigger distance condition is no longer satisfied. And when the condition is satisfied again, only the LED light is toggled to HIGH from LOW but the motorfan state is not toggled and remain in state of LOW.
Hence, need to ask for help in rectifying the issue and what has been done wrong.
Thanks.
Code:
const int signalPin = 1; //wire pin to analog for IR Sensor
//Motor-Fan connected to arduino pin number
//const int FanPin = 5;
//Motor-Fan Relay
byte FanRelay = 4;
//const int FanRelay = 4;
//Light Relay
byte LightRelay = 6;
//const int LightRelay = 5;
int IRSignal; //variable signal, will hold the analog value read by Arduino
long duration;
int distance;
unsigned long Timer;
unsigned long Interval = 10000; //teh repeat Interval
unsigned long SmellInterval = 10000;
void setup()
{
//Execute only once at startup
//pinMode (FanPin , OUTPUT) ; // Set pinMode for FanPin as OUTPUT, display
pinMode (signalPin, INPUT); //infared sensor line will be an input to the Arduino
pinMode(FanRelay, OUTPUT);
pinMode(LightRelay, OUTPUT);
Serial.begin(9600); // Open serial port to communicate with the Ultrasaonic Sensor
}
void loop()
{
//execute multiple times in a loop
IRSignal = analogRead(signalPin); //arduino reads the value from the infared sensor
distance = 9462 / (IRSignal -16.92);
Serial.println(distance);
if(distance < 30 && distance > 0)
{
Timer = millis();
// Write a pin of HIGH
Serial.println("1");
digitalWrite (FanRelay, HIGH);
digitalWrite (LightRelay, HIGH);
if (Timer > SmellInterval){
//digitalWrite (FanPin, LOW);
digitalWrite (FanRelay, LOW);
}
}
else
{
Serial.println("0");
//Check if Timer is longer than 10s
if ((millis()-Timer)>Interval){
//digitalWrite (FanPin, LOW);
//digitalWrite (FanRelay, LOW);
digitalWrite (LightRelay, LOW);
}
}
delay(1000);
}
The issue lies here:
Timer = millis();
....
if (Timer > SmellInterval){
//digitalWrite (FanPin, LOW);
digitalWrite (FanRelay, LOW);
}
The Timer variable will hold current value of millis() which is system time from the last reset. That means that, the if condition will be satisfied always after 10s of running the program.
This is why FanRelay remains low the second time your condition is satisfied - enough time expired, so immediately after it is turned on, it is turned off.
Turning off after a delay will also not work (BTW both your delays are 10s, not 5s like you mention in the post). You need to save the time only the first time the distance condition was met and check the time difference from that moment.
See https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay for a similar example. Also your design will be much more readable and easy to debug if you use a state machine concept. Some reading on wiki, and StackOverflow. In a state machine you define a set of states (like no_object_detected, object_just_detected, object_detected_a_while_ago), and transitions between them (when they happen, and what should be done when they occur).

Resources