I have this project with my Arduino UNO where I want my servo motor SG90 to go full speed to 180 degrees when the PIR sensor sends HIGH value and go slowly back to zero when the value is LOW.
I have this code working where the servo goes full speed back to zero:
#include <Servo.h>
Servo myservo; //creates a servo object
int pos = 0; //variable to store servo position
//amount of time we give the sensor to calibrate(10-60 secs according to the datasheet)
int calibrationTime = 30;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int pir = 12; //digital pin connected to the PIR's output
int pirPos = 13; //connects to the PIR's 5V pin
void setup() {
myservo.attach(4); //attaches servo to pin 4
Serial.begin(9600); //begins serial communication
pinMode(pir, INPUT);
pinMode(pirPos, OUTPUT);
digitalWrite(pirPos, HIGH);
//time for calibration
Serial.println("calibrating sensor ");
for (int i = 0; i < calibrationTime; i++) {
Serial.print(calibrationTime - i);
Serial.print("-");
delay(1000);
}
Serial.println();
Serial.println("done");
//this waits until the PIR's output is low before ending setup
while (digitalRead(pir) == HIGH) {
delay(500);
}
Serial.print("SENSOR ACTIVE");
}
void loop() {
if (digitalRead(pir) == HIGH)
myservo.write(180); // tell servo to go to position in variable 'pos'
Serial.print("Motion detected!");
if (digitalRead(pir) == LOW)
myservo.write(0); // tell servo to go to position in variable 'pos'
Serial.print("Motion ended!");
}
I'd like the servo to go slowly back to zero, so I tried this :
#include <Servo.h>
Servo myservo; //creates a servo object
int pos = 0; //variable to store servo position
//amount of time we give the sensor to calibrate(10-60 secs according to the datasheet)
int calibrationTime = 30;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int pir = 12; //digital pin connected to the PIR's output
int pirPos = 13; //connects to the PIR's 5V pin
void setup() {
myservo.attach(4); //attaches servo to pin 4
Serial.begin(9600); //begins serial communication
pinMode(pir, INPUT);
pinMode(pirPos, OUTPUT);
digitalWrite(pirPos, HIGH);
//time for calibration
Serial.println("calibrating sensor ");
for (int i = 0; i < calibrationTime; i++) {
Serial.print(calibrationTime - i);
Serial.print("-");
delay(1000);
}
Serial.println();
Serial.println("done");
//this waits until the PIR's output is low before ending setup
while (digitalRead(pir) == HIGH) {
delay(500);
}
Serial.print("SENSOR ACTIVE");
}
void loop() {
if (digitalRead(pir) == HIGH)
myservo.write(180); // tell servo to go to position in variable 'pos'
Serial.print("Motion detected!");
if (digitalRead(pir) == LOW)
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
Serial.print("Motion ended!");
}
The problem is with this code the servo does go slowly back to zero but then goes full speed back to 180 and again and again ....
Any idea? I'm a beginner in Arduino, so I assume it must not be that hard to figure out. Thanks.
1 Answer 1
Don't set the pos to 180 in the (digitalRead(pir) == LOW)
branch if you do not want it to repeatedly jump up to 180 for as long as the condition is true.
void loop() {
if (digitalRead(pir) == HIGH)
pos = 180;
myservo.write(pos); // tell servo to go to position in variable 'pos'
Serial.print("Motion detected!");
if (digitalRead(pir) == LOW)
for (; pos > 0; pos -= 1) { // decay to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
Serial.print("Motion ended!");
}
Alternately, you could use pos
as a state variable and simplify things:
void loop() {
if (digitalRead(pir) == HIGH)
pos = 180;
elif (pos > 0 ){
pos--;
delay(15);
}
myservo.write(pos);
}
-
If
pir
is LOW, the OP's speed-controlled code will keep cycling between 180 and zero again and again.Dave X– Dave X2021年02月11日 14:30:40 +00:00Commented Feb 11, 2021 at 14:30 -
"long as the condition is true" or maybe "as long as the input remains
LOW
". I'm going to delete my previous comments above (and this one later), because with your good clarifications they're going to look more out of sync.timemage– timemage2021年02月11日 14:43:16 +00:00Commented Feb 11, 2021 at 14:43 -
I pasted the code, works like a charm, thanks a lot to you two guys !!Nathan Ghali– Nathan Ghali2021年02月11日 17:58:54 +00:00Commented Feb 11, 2021 at 17:58
-
It sounds like you should "accept" this answer.timemage– timemage2021年02月12日 18:58:37 +00:00Commented Feb 12, 2021 at 18:58
(digitalRead(pir) == LOW)
then you tell the servo to jump to 180 with this line:for (pos = 180; pos >= 0; pos -= 1)
Tools
/Auto Format
in the IDE, which is something you should do before posting in the future, for the sanity of your readers, if not for your own.