4

I'm creating a PIR motion sensor doggy door.

The problem I'm having with it is, it runs 3 times, I've figured out how to pause when reaches 180° but not how to stop.

I was thinking I could use detach my servo and attach after a delay of 30,000 and then re-attach return to 0 degrees, then wait for next PIR high.

But I don't know how to code it into what I have or even if it would work.

My code:

/* This code sweeps a servo from 0 degrees to 180 when the PIR sensor detects motion.
   Special thanks goes to the author of the PIR sensor code, whose code helped tremendously
   in the making of this code and Instructable.
   author of PIR sensor code: Kristian Gohlke / krigoo (_) gmail (_) com / http://krx.at
**/

#include <Servo.h>

Servo myservo; //creates a servo object
//a maximum of eight servo objects can be created
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 pirPin = 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(pirPin, INPUT);
  pinMode(pirPos, OUTPUT);
  digitalWrite(pirPos, HIGH);
  //give the sensor time to calibrate
  Serial.println("calibrating sensor ");
  for (int i = 0; i < calibrationTime; i++) {
    Serial.print(calibrationTime - i);
    Serial.print("-");
    delay(1000);
  }
  Serial.println();
  Serial.println("done");
  //while making this Instructable, I had some issues with the PIR's output
  //going HIGH immediately after calibrating
  //this waits until the PIR's output is low before ending setup
  while (digitalRead(pirPin) == HIGH) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("SENSOR ACTIVE");
}

void loop() {
  if (digitalRead(pirPin) == HIGH) {
    //if the PIR output is HIGH, turn servo
    /*turns servo from 0 to 180 degrees and back
      it does this by increasing the variable "pos" by 1 every 5 milliseconds until it hits 180
      and setting the servo's position in degrees to "pos" every 5 milliseconds
      it then does it in reverse to have it go back
      to learn more about this, google "for loops"
      to change the amount of degrees the servo turns, change the number 180 to the number of degrees you want it to turn
    **/
    for (pos = 0; pos < 180; pos += 1) {
      //goes from 0 to 180 degrees
      myservo.write(180);
      delay(8000); ////stops motor for 8 seconds
      for (pos = 180; pos >= 90; 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
      }
      myservo.write(90);
      delay(4000); //stops motor for 4 seconds
      for (pos = 90; pos <= 180; pos += 1) {
        // goes from 0 degrees to 180 degrees
        // in steps of 1 degree
        myservo.write(pos); // tell servo to go to position in variable 'pos'
        delay(15); // waits 15ms for the servo to reach the position
      }
      //to make it go slower, increase the number.
      if (lockLow) {
        //makes sure we wait for a transition to LOW before further output is made
        lockLow = false;
        Serial.println("---");
        Serial.print("motion detected at ");
        Serial.print(millis() / 1000);
        Serial.println(" sec");
        delay(50);
      }
      takeLowTime = true;
    }

    if (digitalRead(pirPin) == LOW) {
      if (takeLowTime) {
        lowIn = millis(); //save the time of the transition from HIGH to LOW
        takeLowTime = false; //make sure this is only done at the start of a LOW phase
      }
      //if the sensor is low for more than the given pause,
      //we can assume the motion has stopped
      if (!lockLow && millis() - lowIn > pause) {
        //makes sure this block of code is only executed again after
        //a new motion sequence has been detected
        lockLow = true;
        Serial.print("motion ended at "); //output
        Serial.print((millis() - pause) / 1000);
        Serial.println(" sec");
        delay(50);
      }
    }
  }
}

Could I also just change the jumper pin on the PIR hardware for a retriggering set high to keep the door open when the dog is there so it won't just close on them?

I'm using this PIR: pir

6
  • Can you add you code rather than link to it. Jul 28, 2016 at 6:29
  • Sorry that's a blocked site for me. Hope someone else can help. Jul 28, 2016 at 9:51
  • Please can you confirm you want you servo to turn to 180 degrees when you PIR sensor sends a high. You want your servo to wait for 30 seconds and then return to zero? Jul 28, 2016 at 12:05
  • I've just realised the servo is opening the door, not moving the PIR sensor :) Jul 28, 2016 at 13:39
  • 1
    Please edit your post, post your code, and format the code using the code formatting markdown (four leading spaces). For help see Markdown help. You should be able to do this by selecting the code and pressing Ctrl+K to have your browser do this for you.
    – Nick Gammon
    Jul 29, 2016 at 5:56

1 Answer 1

1

I haven't been able to compile or test this but I think it should do what you are asking for, or at the very least steer you in the right direction.

// This code waits for a signal from the PIR sensor.
// When the signal is recieved it rotates the servo 180 degrees and waits 30 seconds
// it then rotates the servo back to 0 (to close the door)

#include <Servo.h>

const int ServoIntraStepDelay   =  15;      // Delay between servo steps (ms)
const int ServoAngleStep        =   1;      // The angle by which the servo position is changed every step (degree) 
const int ServoAngleMinimum     =   0;      // The min angle of the servo (degrees)
const int ServoAngleMaximum     = 180;      // The max angle of the servo (degree)
const int DoorOpenPeriod        = 30 * 1000;// The time the door will remain open for (ms)
const int DoorClearPoll         = 100;      // The interval betwen polls to the sensor when checking to see if the door is clear(ms)
const int DoorClearPeriod       = 5000;     // The interval that the PIR sensor must report low before closing the door (ms)

const int PIRCalibrationTime    = 30;       //amount of time we give the sensor to calibrate(10-60 secs according to the datasheet) (s)

const int PinPIRData            = 12;       //digital pin connected to the PIR's output
const int PinPIRPower           = 13;       //connects to the PIR's 5V pin
const int PinServoPower         = 4;        // The pin that controls the servo. 

Servo myservo;                              //creates a servo object

void setupCalibratePIR()
{
        //give the sensor time to calibrate
    Serial.println("Calibrating sensor ");
    for(int i = 0; i < PIRCalibrationTime; i++)
    {
        Serial.print(PIRCalibrationTime - i);
        Serial.print("-");
        delay(1000);
    }
    Serial.println();
    Serial.println("done");
    //while making this Instructable, I had some issues with the PIR's output
    //going HIGH immediately after calibrating
    //this waits until the PIR's output is low before ending setup
    Serial.print("Waiting for PIR sensor to report low");
    while (digitalRead(PinPIRData) == HIGH) 
    {
        delay(500);
        Serial.print("."); 
    }
    Serial.print("SENSOR ACTIVE");  
}

void turnServo (const int& from, const int& to, const int& step)
{
    for(int pos = from; pos <= to; pos += step)
    { 
        myservo.write(pos); 
        delay(ServoIntraStepDelay); 
    } //to make it go slower, increase the number.
}

// Test the PIR sensor and ensure that it reports low for a specific time
void waitForDoorClear ()
{
    bool doorIsNotClear = true;
    while (doorIsNotClear)
    {
        doorIsNotClear = false;
        for (int doorClear = 0; !doorIsNotClear && (doorClear * DoorClearPoll) < DoorClearPeriod; ++doorClear)
        {   // Poll every few ms and check that the sensor in LOW
            // As soon as it is high this loop will exit which restarts the time that the low signal must been seen for.
            delay (DoorClearPoll);
            doorIsNotClear = (digitalRead(PinPIRData) == HIGH);
        }
    }   // This is potentially an infinite loop.
}

void setup()
{
    Serial.begin(9600);                     // Begins serial communication
    myservo.attach(PinServoPower);          // Connect to the servo object
    pinMode(PinPIRData, INPUT);             // Connect the PIR data 
    pinMode(PinPIRPower, OUTPUT);           // Connect the PIR power    
    digitalWrite(PinPIRPower, HIGH);        // Turn on the PIR power

    setupCalibratePIR();                    // Calibrate the PIR sensor
}
// attach
void loop()
{

    if(digitalRead(PinPIRData) == HIGH)
    { //if the PIR output is HIGH, turn servo

        turnServo (ServoAngleMinimum, ServoAngleMaximum, ServoAngleStep);
        delay (DoorOpenPeriod - DoorClearPeriod);
        waitForDoorClear ();
        turnServo (ServoAngleMaximum, ServoAngleMinimum, -ServoAngleStep);
    }
}

You weren't that far off.

7
  • a bunch of errors Arduino: 1.6.9 (Windows 7), Board: "Arduino/Genuino Uno" : In function 'void setupCalibratePIR()': matt:39: error: 'pirPin' was not declared in this scope while (digitalRead(pirPin) == HIGH) ^ : In function 'void turnServo(const int&, const int&, const int&)': matt:49: error: 'os' was not declared in this scope for(int pos = from; pos <= to; [os += step) ^ matt:49: error: expected ',' before '+=' token for(int pos = from; pos <= to; [os += step) ^ matt:49: error: expected identifier before '+=' token Jul 28, 2016 at 14:17
  • Yep, sorry like I said I can't compile it at work. pirPin should be PinPIRData. os should be pos that will clear those three. Jul 28, 2016 at 14:43
  • ive figured them out for(int pos = from; pos <= to; [pos += Step) im guessing step is ServoAngleStep but it says expected ',' before '+=' token ??? Jul 28, 2016 at 14:47
  • That's the [ I must have hit that key instead of P. I have updated the code, This time I know it compiles, well in visual studio. Jul 28, 2016 at 15:02
  • the code runs but it is always open now until power is off only then will it return to 0 degrees ive tried changing the code but it doesnt seem to work for me Jul 29, 2016 at 1:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.