Go Down

Topic: While, Break for Trail Camera (Read 3738 times) previous topic - next topic

bagpiper03

I have attached a digital camera to an Arduino Mini.

4 wires from the camera are attached to the Arduino

-Ground
-"Power on"
-"Focus"
-"Shutter"

4N35 relays make the various connections to ground in order to get the camera to "do what it do."

A PIR detector is attached to an input pin.

I am trying to complete the sequence of events as shown in the comments on the sketch.

The problem is what to do when I "break" out of the "while."

I want it to turn the camera off and wait for more motion, but  it doesn't seem to take another reading from the PIR within the "while", even though I think I am telling it to.

Help please?


Code: [Select]

const int pirPin = 8;
const int powerPin = 9;
const int focusPin = 7;
const int shutterPin = 4;

void setup (){
  pinMode(pirPin, INPUT);
  pinMode(powerPin, OUTPUT);
  pinMode(focusPin, OUTPUT);
  pinMode(shutterPin, OUTPUT);
  delay(30000);                      // Allow time for the PIR to power up and calibrate, around 30 seconds.
}

void loop (){                        // Do nothing until motion is detected from the PIR.
  int val = digitalRead(pirPin);
  if (val == HIGH)                   // If motion is detected, turn the camera on.
  {
    digitalWrite(powerPin, HIGH);
    delay(500);
    digitalWrite(powerPin, LOW);
    delay(2000);                     // Wait 2 seconds.
  }
  while (val == HIGH)                // While motion is detected, leave the camera on and take pictures, see below.
  {
    if (val == LOW)                  // If no motion is detected,
    {
      digitalWrite(powerPin, HIGH);  // turn the camera off
      delay(500);
      digitalWrite(powerPin, LOW);
      delay(2000);                   // Wait 2 seconds.
      break;                         // break out of the "while" and return to the beginning of the loop.
    }
    digitalWrite(focusPin, HIGH);    // focus
    delay(1500);
    digitalWrite(shutterPin, HIGH);  // snap a picture
    delay(500);
    digitalWrite(focusPin, LOW);     // release the focus
    digitalWrite(shutterPin, LOW);   // and shutter
    delay(5000);                     // wait 5 seconds and return to the beginning of the while to check for more motion
  }
}




AWOL

#1
Dec 03, 2013, 07:16 pm Last Edit: Dec 03, 2013, 07:22 pm by AWOL Reason: 1
What changes the variable "val" in your while loop?

Code: [Select]
while (val == HIGH)                // While motion is detected, leave the camera on and take pictures, see below.
  {
    if (val == LOW)

You've just tested to see if it is HIGH.
Unless you've got a hidden interrupt, its value is unlikely to have changed.

bagpiper03


What changes the variable "val" in your while loop?


I guess I don't understand the question.

If the command is "while", I guess I assume that it checks it again at the beginning of each "while" loop, after every picture is taken. 

Is that not correct?

AWOL

It does check the value at the top of the while loop, but if there's nothing in the while loop to read the value, once it is in the while loop, it is never going to leave it.
You need to read the pin inside the while loop.

bagpiper03


It does check the value at the top of the while loop, but if there's nothing in the while loop to read the value, once it is in the while loop, it is never going to leave it.
You need to read the pin inside the while loop.


OK and this is a incredibly stupid question, but what is the syntax to call for a digitalRead of a variable I have already defined?

Just "digitalRead(pirPin)" ?

Or can I just say, "val" ?

AWOL

It's just an assignment of the value read by digitalRead to the variable

bagpiper03


It's just an assignment of the value read by digitalRead to the variable


I guess i didn't understand the definition of a variable.  I supposed that it was constantly reading the pin to determine the value, but it only does that at the beginning of the overall loop, nowhere in the while loop.

So once the variable is defined at the beginning of the while loop, it's not going to check it again unless I tell it to.

int val = digitalRead(pirPin);

So I repeat the call for the variable again at the bottom of the while loop with the same line of code.

Code: [Select]
 
while (val == HIGH)                // While motion is detected, leave the camera on and take pictures, see below.
  {
    if (val == LOW)                  // If no motion is detected,
    {
      digitalWrite(powerPin, HIGH);  // turn the camera off
      delay(500);
      digitalWrite(powerPin, LOW);
      delay(2000);                   // Wait 2 seconds.
      break;                         // break out of the "while" and return to the beginning of the loop.
    }
    digitalWrite(focusPin, HIGH);    // focus
    delay(1500);
    digitalWrite(shutterPin, HIGH);  // snap a picture
    delay(500);
    digitalWrite(focusPin, LOW);     // release the focus
    digitalWrite(shutterPin, LOW);   // and shutter
    delay(5000);    // wait 5 seconds and return to the beginning of the while to check for more motion
    int val = digitalRead(pirPin);
  }


Does that seem correct?

AWOL

No, that introduces another variable of the same name that immediately goes out of scope.
Lose the "int".

bagpiper03


No, that introduces another variable of the same name that immediately goes out of scope.
Lose the "int".


OK Thanks for the help I will let you know if I get it working.

lar3ry

#9
Dec 03, 2013, 08:21 pm Last Edit: Dec 03, 2013, 08:23 pm by lar3ry Reason: 1

So I repeat the call for the variable again at the bottom of the while loop with the same line of code.

Does that seem correct?

In addition to what AWOL says, checking the PIR value at the bottom of the while loop is not the right thing. Consider: you are in the loop because the PIR value is HIGH. You immediately check for it being LOW, and it isn't, so you (again, immediately) bypass the "power down" code. If you check for the PIR value at the bottom of the while loop, and set val, to LOW, you will not re-enter the while again, so the if (LOW)  statement is never executed, and your power down code is never executed.

Logically, if you enter the while loop, you want to take a picture, so just take the picture. If you add a digitalRead() of the pirPin after the delay(5000), you will be checking it after the picture is taken. And if you move your if(LOW) statement and the power down code contained in that block down to just after the digitalRead(), it will, if the pirPin is LOW, execute your power down code, and drop out of the while (ie. will not re-enter the while). You can also remove the break,  within the if, because the while will not be re-entered anyway.

So, your while loop would look like this...
Code: [Select]

while (val == HIGH)                // While motion is detected, leave the camera on and take pictures, see below.
 {
   digitalWrite(focusPin, HIGH);    // focus
   delay(1500);
   digitalWrite(shutterPin, HIGH);  // snap a picture
   delay(500);
   digitalWrite(focusPin, LOW);     // release the focus
   digitalWrite(shutterPin, LOW);   // and shutter
   delay(5000);                     // wait 5 seconds then check for more motion
   
   val = digitalRead(pirPin);
   if (val == LOW)                  // If no motion is detected,
   {
     digitalWrite(powerPin, HIGH);  // turn the camera off
     delay(500);
     digitalWrite(powerPin, LOW);
     delay(2000);                   // Wait 2 seconds.
   }
 }


bagpiper03

Quote

In addition to what AWOL says, checking the PIR value at the bottom of the while loop is not the right thing. Consider: you are in the loop because the PIR value is HIGH. You immediately check for it being LOW, and it isn't, so you (again, immediately) bypass the "power down" code. If you check for the PIR value at the bottom of the while loop, and set val, to LOW, you will not re-enter the while again, so the if (LOW)  statement is never executed, and your power down code is never executed.

Logically, if you enter the while loop, you want to take a picture, so just take the picture. If you add a digitalRead() of the pirPin after the delay(5000), you will be checking it after the picture is taken. And if you move your if(LOW) statement and the power down code contained in that block down to just after the digitalRead(), it will, if the pirPin is LOW, execute your power down code, and drop out of the while (ie. will not re-enter the while). You can also remove the break,  within the if, because the while will not be re-entered anyway.

So, your while loop would look like this...



Hey that did it!  I don't know why it didn't occur to me that the order of the functions in the while loop was important.

A follow up question: if an "if" can get me out of the loop, by making the while condition false, then what's the point of a "break"??

Thanks so much to you both for the help!

lar3ry

A while loop depends on a condition to either continue or to exit the loop. It's not really the if that tells the loop to exit, in the code I posted. Rather, the if only ensures that the pirPin going LOW causes the if block to execute. The thing that causes the while to exit is the setting of val when you read the pirPin. Since val is set to LOW, the while says "OK fine. I'm not doing this any more.".

A break is a handy thing that allows you to do things that would otherwise require a huge, perhaps overly complex conditional in the while statement. Here's a simple example..

Code: [Select]

   while (1) {       // this evaluates to true. essentially an infinite loop
       // do a whole bunch of things here
      if ( (thing 1 != thing2 && thing3 > thing4) ^ (thing5 == 8 || thing6 >= thing2) || (abort  ) {
      break;
      // do a whole bunch more things here
      if (a whole different set of things) {
          // do other stuff
      }
  }


If you've ever tried to make a conditional that says the negative of that if, you'll appreciate the ease of saying well, here are the things that let me out of the loop, rather than here are the things that let me keep going.  A break is handly for any loop construct, be it while(), for(), do(),  or a non-loop function like switch(),  allowing you to exit from various blocks of code , like nested if statements within a loop, or even to allow you multiple exits from the loop with simple if or switch() statements.

bagpiper03


If you've ever tried to make a conditional that says the negative of that if, you'll appreciate the ease of saying well, here are the things that let me out of the loop, rather than here are the things that let me keep going.  A break is handly for any loop construct, be it while(), for(), do(),  or a non-loop function like switch(),  allowing you to exit from various blocks of code , like nested if statements within a loop, or even to allow you multiple exits from the loop with simple if or switch() statements.


Clearly I have a lot to learn.  Thanks again for the help.  BTW, I dig your profile pic.  A couple of your waxwings showed up in my yard last week in Saint Louis.  They didn't stay long though, I really need a flowering crab or cherry tree or something.

lar3ry


Clearly I have a lot to learn.  Thanks again for the help.  BTW, I dig your profile pic.  A couple of your waxwings showed up in my yard last week in Saint Louis.  They didn't stay long though, I really need a flowering crab or cherry tree or something.


A lot to learn. Yes, but to that I say "Join the club!" I'm here to learn, because I find that the best way to learn is to try to teach. I programmed AVRs for many years, but only in assembler. This C++ as used in AVRs is all new to me.

Yes, the waxwings up here really like to raid the dried fruit on the trees in fall and winter. I'm surprised they shoow up in Saint Louis this time of year.

bagpiper03

I thought you guys who helped me with this project would like to see the end result.  Here are the best pictures from the maiden voyage of the arduino trail cam:

https://www.facebook.com/media/set/?set=a.10201942803264864.1073741831.1028117358&type=1&l=a91dbb32e9


Go Up