0

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.

timemage
5,6391 gold badge14 silver badges25 bronze badges
asked Feb 11, 2021 at 12:46
2
  • 1
    If (digitalRead(pir) == LOW) then you tell the servo to jump to 180 with this line: for (pos = 180; pos >= 0; pos -= 1) Commented Feb 11, 2021 at 14:02
  • 1
    I'd run your code through 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. Commented Feb 11, 2021 at 14:45

1 Answer 1

2

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);
}
answered Feb 11, 2021 at 14:06
4
  • If pir is LOW, the OP's speed-controlled code will keep cycling between 180 and zero again and again. Commented 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. Commented Feb 11, 2021 at 14:43
  • I pasted the code, works like a charm, thanks a lot to you two guys !! Commented Feb 11, 2021 at 17:58
  • It sounds like you should "accept" this answer. Commented Feb 12, 2021 at 18:58

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.