Movie camera trap -sketch problems

I am trying to make a camera trap system for a friend. i.e. A system to automatically start and stop a movie camera when triggered by a wild animal. I have used an IF beam for the sensor and this seems to work well. The camera needs two contacts to be shorted to start a movie and the same contact shorted again to stop the recording. I will be using optocoupler on pin 3 to do the shorting.

Below is the code that I am having problems with.
The LED on pin 9 is there just to indicate when filming is taking place. I dont have the actual camera with me.

long shutterOnInterval is the period that the contacts will be shorted (probably dosn't need to be this long)
long filmPeriod is the time of filming

So the idea is that when the IR beam is broken the short is made by the shutterpin, the camera then films for the period set, then another short is sent to stop the filming.

At the moment it works ok so long as I re trigger in less than 5 seconds following a filming period. If I dont, the shorting signal is sent every 5 seconds even without any beam breaking.

If I dont break the beam at all the shorting signal is again sent every 5 seconds.

I suspect my problem is due to some timer related command not being in the right place but I just cant see it. Any help much appreciated.

Eventually I would like it if the filming period could be extended if further beam breaks occur during the initial filming period, but that's for later.

int IR_sensor = 11; // input from IR sensor
int shutter = 3; // led pin
int filming_led = 9;


long shutterOnInterval = 500;
long filmPeriod = 5000;
int timerRunning = 0;
int filming = 0;
unsigned long  startTime = 0;
unsigned long  timeNow = 0;

void setup() {
  pinMode(IR_sensor, INPUT);
  pinMode(shutter, OUTPUT);
  pinMode (filming_led, OUTPUT);
  Serial.begin(9600);
}

void loop() {

  //read the IR sensor. If HIGH, start the on/off signal
  if ((digitalRead(IR_sensor) == HIGH) && (timerRunning == 0))
  {
    startTime = millis();
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, HIGH);
    timerRunning = 1;
    filming = 1;
    Serial.println("signal and  filming started");

  }

  //stop the on/off signalafter the lamponinterval. filming still running
  if ((timerRunning == 1) && (timeNow - startTime) >= shutterOnInterval )
  {
    digitalWrite(shutter, LOW);
    timerRunning = 0;
    Serial.println("signal stopped BUT Still filming");

  }
  //if filming period is done, stop filming and send on/off signal
  timeNow = millis();
  if (((timeNow - startTime) > filmPeriod) && (filming = 1))
  {
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, LOW);
    filming = 0;
    timerRunning = 1;
    startTime = millis();
    Serial.println("filming ended and signal to stop is started");
  }

  //stop the on/off signal after the lamponinterval and after the filmPeriod
  timeNow = millis();
  if ((timerRunning == 1) && (timeNow - startTime) >= shutterOnInterval )
  {
    digitalWrite(shutter, LOW);
    timerRunning = 0;
    Serial.println("filming stopped and signal SENT");

  }
}

Use Serial.println of startegic variables in the loop. That's debugging.

You almost certainly mean comparison for equality '==', not assignment '=', in this part of your espression:

&& (filming = 1))

There may be others. An easy mistake to make, and miss.

I suggest you to go to the IDE Preferences and crank up all warnings and verbosity.

The red ink would have spotted that, and asked if you are sure that's what you meant. Sometimes that is what you want, but so rare it is that it rises to the level of something the compi,er can warn you about, if you let it.

HTH

a7

Thanks Alto777, that was it. I love this forum. I had sat there for hours looking at this one.

Can you give me any help on my future task.

"Eventually I would like it if the filming period could be extended if further beam breaks occur during the initial filming period,"

Optocouplers REQUIRE a voltage difference between the two contacts. What is the voltage and polarity of the voltage?

1 Like

Do a simple experiment connect the opto coupler to your camera and then using a resistor in series with its LED turn it on and off a few times does the camera operate?

Yes, that's easy if you just

  if ((digitalRead(IR_sensor) == HIGH)
  {
    startTime = millis();
  }

Place that after the entire if statement that checks for the sensor and timerRunning is false (zero).

"As long as the sensor is HIGH, or becomes HIGH again, keep bumping the start time along.

The timer will run out only if a protracted period where the sensor doesn't bump the start time to now, so it will run as long as there is motion, plus filmPwriod number of milliseconds.

That is if your code is working… I can't say for sure. It looks plausible, but just sitting under the unbrella reading it I have to say probably.

a7

Thanks A7, that looks doable, but in the mean time I spoke to soon. My setup appears to be working, the leds light up when they should. But something else is not right. The 4 main tasks are not being done in the right order. I have to go now but will post more, probably tomorrow.
Thanks to all you others who have given advice too.

I have just had another hour at it but cant find what is wrong. I made the change you suggested with the "==" and If I watch the LED's it all looks like things are running exactly as they should. But I added some Println commands at the end of each of the four "if" sections (I cant remember why) and these indicate that things are not running as they should. Here is my latest code and the serial monitor output.

int IR_sensor = 11; // input from IR sensor
int shutter = 3; // led pin
int filming_led = 9;


long shutterOnInterval = 1000;
long filmPeriod = 5000;
int timerRunning = 0;
int filming = 0;
unsigned long  startTime = 0;
unsigned long  timeNow = 0;

void setup() {
  pinMode(IR_sensor, INPUT);
  pinMode(shutter, OUTPUT);
  pinMode (filming_led, OUTPUT);
  Serial.begin(9600);
  Serial.println("IR_sensor_V3.ino");
}

void loop() {

  //read the IR sensor. If HIGH, start the on/off signal
  if ((digitalRead(IR_sensor) == HIGH) && (timerRunning == 0))
  {
    Serial.println("start 1");
    startTime = millis();
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, HIGH);
    timerRunning = 1;
    filming = 1;
    Serial.println("1 signal and  filming started");
  }


  //stop the on/off signal after the lamponinterval. filming still running
   timeNow = millis();
  if ((timerRunning == 1) && (timeNow - startTime) >= shutterOnInterval )
  {
    Serial.println("start 2");
    digitalWrite(shutter, LOW);
    timerRunning = 0;
    Serial.println("2 signal stopped BUT Still filming");
  }

  
  //if filming period is done, stop filming and send on/off signal
  timeNow = millis();
  if (((timeNow - startTime) > filmPeriod) && (filming == 1))
  {
    Serial.println("start 3");
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, LOW);
    filming = 0;
    timerRunning = 1;
    startTime = millis();
    Serial.println("3 filming ended and signal to stop is started");
  }


  //stop the on/off signal after the lamponinterval and after the filmPeriod
  timeNow = millis();
  if ((timerRunning == 1) && (timeNow - startTime) >= shutterOnInterval )
  {
    Serial.println("start 4");
    digitalWrite(shutter, LOW);
    timerRunning = 0;
    Serial.println("4 filming stopped and signal SENT");

  }
}

Below is the serial monitor output. I have manually eddited in a line space between each of 3 "beam breaks" to make it easier to see what is going on.

IR_sensor_V3.ino
start 1
1 signal and filming started
start 2
2 signal stopped BUT Still filming
start 3
3 filming ended and signal to stop is started
start 4
4 filming stopped and signal SENT

start 1
1 signal and filming started
start 2
2 signal stopped BUT Still filming
start 3
3 filming ended and signal to stop is started
start 2
2 signal stopped BUT Still filming

start 1
1 signal and filming started
start 2
2 signal stopped BUT Still filming
start 3
3 filming ended and signal to stop is started
start 2
2 signal stopped BUT Still filming

Any ideas?

Try this way:

int IR_sensor = 11; // input from IR sensor
int shutter = 3; // led pin
int filming_led = 9;
long shutterOnInterval = 1000;
long filmPeriod = 5000;
int timerRunning = 0;
int filming = 0;
unsigned long  startTime = 0;
unsigned long  timeNow = 0;
//--------------------------------------------------------------------
void setup() {
  pinMode(IR_sensor, INPUT);
  pinMode(shutter, OUTPUT);
  pinMode (filming_led, OUTPUT);
  Serial.begin(9600);
  Serial.println("IR_sensor_V3.ino");
}
//--------------------------------------------------------------------
void loop() {
  //read the IR sensor. If HIGH, start the on/off signal
  if ((digitalRead(IR_sensor) == HIGH) && (timerRunning == 0))  {
    Serial.print("start 1 ");
    startTime = millis();
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, HIGH);
    timerRunning = 1;
    filming = 1;
    Serial.println("1 signal and  filming started");
  }
  //stop the on/off signal after the lamponinterval. filming still running
  //timeNow = millis();
  if ((timerRunning == 1) && (millis() - startTime) >= shutterOnInterval )  {
    Serial.print("start 2 ");
    digitalWrite(shutter, LOW);
    timerRunning = 2;
    Serial.println("2 signal stopped BUT Still filming");
  }
  //if filming period is done, stop filming and send on/off signal
  // timeNow = millis();
  if (((millis() - startTime) > filmPeriod) && (filming == 1))  {
    Serial.print("start 3 ");
    digitalWrite(shutter, HIGH);
    digitalWrite(filming_led, LOW);
    filming = 0;
    timerRunning = 3;
    startTime = millis();
    Serial.println("3 filming ended and signal to stop is started");
  }
  //stop the on/off signal after the lamponinterval and after the filmPeriod
  //timeNow = millis();
  if ((timerRunning == 3) && (millis() - startTime) >= shutterOnInterval ) {
    Serial.print("start 4 ");
    digitalWrite(shutter, LOW);
    timerRunning = 0;
    Serial.println("4 filming stopped and signal SENT");
  }
  if ((digitalRead(IR_sensor) == HIGH) && (timerRunning == 2) && (filming == 1))  {  //Extende time
    startTime = startTime + filmPeriod;
    Serial.println("extended");
  }
}

Ruilviana, thank you so much. I was starting to lose hope.

This is my version of @ruilviana's version of @Bnorm's sketch.

By moving to a switch/case explicit FSM model, we can simplify the flags and counters and roll them all up into the state of the process.

As far as what it does with the outputs and what it prints, I ripped that all and copied it into the case code. Try it here, the functionality should be the same:

Wokwi_badge UA Camera Trap

// https://forum.arduino.cc/t/movie-camera-trap-sketch-problems/1250853
// https://wokwi.com/projects/395926058392791041

const byte IR_sensor = 11; // input from IR sensor
const byte shutter = 3; // led pin
const byte filming_led = 9;

unsigned long shutterOnInterval = 333;
unsigned long filmPeriod = 5000;

unsigned long startShutter = 0;
unsigned long startFilming = 0;

unsigned long now;

enum fsmState {IDLE, START, FILM, FINI, DONE} theState;


void setup() {
  pinMode(IR_sensor, INPUT);
  pinMode(shutter, OUTPUT);
  pinMode (filming_led, OUTPUT);
  Serial.begin(9600);
  Serial.println("IR_sensor_V3_X.ino");

  theState = IDLE;
}


void loop() {

  bool irHit = digitalRead(IR_sensor) == HIGH;  // pulled_down pushbutton, PRESST
  now = millis();

  switch (theState) {
  case IDLE :  // wait for sensor
    if (irHit) {
        Serial.print("start 1 ");
        startShutter = now;
        startFilming = now;
        digitalWrite(shutter, HIGH);
        digitalWrite(filming_led, HIGH);
        Serial.println("signal and filming started");

        theState = START;
    }
  
    break;

  case START :  // finish out start shutter
    if (now - startShutter >= shutterOnInterval) {
      digitalWrite(shutter, LOW);
      theState = FILM;
      Serial.println("2 signal stopped BUT Still filming");
    }

// intentional no break here - check filming timer too, then exclusively

  case FILM :  // finish filming period, extend maybe
    if (irHit) startFilming = now;    // activity moves the marker along 

    if (now - startFilming > filmPeriod)  {
      Serial.print("start 3 ");
      digitalWrite(shutter, HIGH);
      digitalWrite(filming_led, LOW);
      startShutter = now;
      theState = FINI;
      Serial.println("3 filming ended and signal to stop is started");
    }

    break;
  
  case FINI :  // finish out end shutter
    if (now - startShutter >= shutterOnInterval) {
      Serial.print("start 4 ");
      digitalWrite(shutter, LOW);
      theState = DONE;
      Serial.println("4 filming stopped and signal SENT");
    }

    break;

  case DONE :  // all done. rinse for repeat
// auto re-arm. motion had shown long quiet period, so unconditionally.
    Serial.println("5 system idle awaits motion");      
    theState = IDLE;

    break;
  }
}

a7

A whole new world.
I need to learn about the enum.

Many thanks

I am making progress but have run into a problem.

I have added a some features to my code based on my freinds requests:-

I have got my indicator led's to go off after a period of time (leds not good with jumpy wildlife)
After a filming period I have added a "buffering" period for the camera to do its saving.

All good so far. Note- I have changed some pin allocations. (just due to physical placements on my board).

So far I have been testing this on my own Canon DSLR and it works fine, but my freind has a high end Sony A7Sii and apparently it needs the focus signal before the shutter signal to start filming.

I have tried a couple of approaches including using delay(), (even though I suspect this practice is frowned upon), but I am stuck.

I am planning to start with a period of 50ms between the start of the focus signal and the start of the shuter signal. It may be that the end of filming signal also needs the focus signal first too.

Here is my latest code. I would appreciate some help.

// https://forum.arduino.cc/t/movie-camera-trap-sketch-problems/1250853
// https://wokwi.com/projects/395926058392791041

const byte IR_sensor = 12; // input from IR sensor
const byte shutter = 11; // to the shutter opto isolator
const byte focus = 10; // to the focus opto isolator
const byte filmingLed = 2; // filming operation indicator
const byte shutterLed = 13; // shutter operation indicator

unsigned long shutterOnInterval = 333;
unsigned long focusOnInterval = 333;
unsigned long filmPeriod = 5000;
unsigned long buffering = 2000;
unsigned long firstTenMins = 600000;

unsigned long startShutter = 0;
unsigned long startFocus = 0;
unsigned long startFilming = 0;

unsigned long now;

enum fsmState {IDLE, START, FILM, FINI, DONE} theState;


void setup() {
  pinMode(IR_sensor, INPUT);
  pinMode(shutter, OUTPUT);
  pinMode(focus, OUTPUT);
  pinMode (filmingLed, OUTPUT);
  pinMode (shutterLed, OUTPUT);
  Serial.begin(9600);
  Serial.println("IR_sensor_V9.ino");

  theState = IDLE;
}


void loop() {

  bool irHit = digitalRead(IR_sensor) == HIGH;  // pulled_down pushbutton, PRESST
  now = millis();

  switch (theState) {
    case IDLE :  // wait for sensor
      if (irHit) {
        Serial.print("start 1 ");
        startShutter = now;
        startFocus = now;
        startFilming = now;
        digitalWrite(shutter, HIGH);
        digitalWrite(focus, HIGH);

        if (now < firstTenMins) {
          digitalWrite(filmingLed, HIGH);
          digitalWrite(shutterLed, HIGH);
        }
        Serial.println("signal and filming started");

        theState = START;
      }

      break;

    case START :  // finish out start shutter
      if (now - startShutter >= shutterOnInterval) {
        digitalWrite(shutter, LOW);
        digitalWrite(focus, LOW);
      
          digitalWrite(shutterLed, LOW);
        
        theState = FILM;
        Serial.println("2 signal stopped BUT Still filming");
      }

    // intentional no break here - check filming timer too, then exclusively

    case FILM :  // finish filming period, extend maybe
      if (irHit) startFilming = now;    // activity moves the marker along

      if (now - startFilming > filmPeriod)  {
        Serial.print("start 3 ");
        digitalWrite(shutter, HIGH);
        digitalWrite(focus, HIGH);
        if (now < firstTenMins) {
          digitalWrite(shutterLed, HIGH);
        }
          digitalWrite(filmingLed, LOW);
       
        startShutter = now;
        theState = FINI;
        Serial.println("3 filming ended and signal to stop is started");
      }

      break;

    case FINI :  // finish out end shutter
      if (now - startShutter >= shutterOnInterval) {
        Serial.print("start 4 ");
        digitalWrite(shutter, LOW);
        digitalWrite(focus, LOW);
        digitalWrite(shutterLed, LOW);
        delay(buffering);
        theState = DONE;
        Serial.println("4 filming stopped and signal SENT");
      }

      break;

    case DONE :  // all done. rinse for repeat
      // auto re-arm. motion had shown long quiet period, so unconditionally.
      Serial.println("5 system idle awaits motion");
      theState = IDLE;

      break;
  }
}

Haha, us? Frown? Never. :expressionless:

Here's a case where most ppl would just use a delay, at least for now to be sure it is the, and all of, whatever issues arrived with the use of a different camera.

First, however, check or have your friend see if there is any way to change the settings on the camera that might be a satisfactory solution.

Assuming the focus is first and the shutter second as you press the button, and in reverse as you release the button, I would just use a function

void nameThisBetter(bool pressing)
{
  if (pressing) {
      digitalWrite(focus, HIGH);
      delay(77);   // add 33 percent to the minimum that works reliably
      digitalWrite(shutter, HIGH);
  }
  else {
      digitalWrite(shutter, LOW);
      delay(12);   // add 33 percent to the minimum that works reliably
      digitalWrite(focus, LOW);
  }
}

To engage you woukd just call it where you currently do the two digital writes:

        startShutter = now;
        startFocus = now;
        startFilming = now;

        nameThisBetter(true);    // push the double button

And the exercises for the reader are two: think up a better name for the function than nameThisBetter(), and figure out how to call it on the other end to release the double button.

I put two different delays in, each side could have its own limit or requirement. I tried to get the HIGH and LOW sense of the focus and shutter outputs right, but that is the kind of mistake I make, so.

When (if) the 77 millisecond delay becomes a problem, the matter can be handled without delay in a number of ways. It would add clutter, but two additional full fledged states in the machinery you have could be written to pause (not delay(), haha) between the digitalWrite() operations.

But srsly if nothing else is going on for 77 milliseconds you may never need to revisit this. Now if you were also cranking out the national anthem or something, it might need to be "fixed".

a7

I went the simple route and just added delays at the start filming sequence and again at the stop filming sequence.

Today I got my hands on the posh Sony camera and after a very short time it became clear that no delays at all are required. It does need the focus signal and the shutter signal at the same time though.

All that stress for nothing!

My friend is very pleased and I am too. Thanks so much for your help.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.