High speed camera shutter release (in progress)

My first Arduino project is going to be a high speed camera shutter release. Triggered by an infrared beam with an adjustable delay before triggering the camera (set by the keypad and LCD). I've mostly been waiting for stuff in the mail but the last few days have been hands on. Got the display and keypad hooked up and working. The next steps are to get it to interface with the camera and flash (Canon 5D) and get the infrared emitter and detector setup. Some photos are below just for kicks, hopefully I'll have some photos of glass breaking and other things smashing before too long if it all goes well. The solder job is on the back of the LCD, does it look okay? First time I've soldered anything in almost 10 years!

The LCD works, sweet!

Cheap keypad from SparkFun that was easy to setup with the Keypad library.

Why are these necessary? The Keypad library said to use resistors on the pins for each row.

Currently powering the LCD with a 7805 regulator because it uses 280 mA according to the paper, is that safe to power directly form the Arduino?

The solder job on the back of the LCD, good, bad?

Holy crap the infrared LED is bright (and its not pointing at the camera)! Taken with my infrared modified Canon 20D to make sure it was actually emitting. Double and triple checked the voltage and its running the at the correct voltage. I'll post some more pictures and questions when I get to another good stopping place. Cheers!

Great start. Keep us posted.

The camera is hooked up now and I have a small enclosure for the infrared light source. Still need to hook up the photo transistor to detect the infrared light and work out the code for the keypad to enter the delay.

This is the adapter from the Canon N3 connector to 3.5mm stereo so I can easily extend and access the camera.

From the end of the cable going into the Arduino.

Two optoisolators are used to interact with the camera while keeping them on separate circuits. They are 4N35 optoisolators bought from a local electronics shop.

This is the whole circuit as of tonight. Hopefully the next iteration of it will be soldered to a board and on its way into an enclosure.

The infrared light source in its new enclosure with a switch. Running on a single AA battery and no other components.

It works! Couldn't tell without taking a shot with a modified camera to see the infrared light. When I get some time this week I'll probably be asking some questions about the keypad code. Thanks everybody for answering my questions in other threads thus far. Cheers!

Cool. I'm collecting parts and building circuits to do something similar, myself. Please do keep posting updates.

Tonight I got the phototransistor hooked up and printing out values. I used the matched emitter and sensor from Radio Shack for this. The infrared LED is extraordinarily bright from the testing I've done and is isolated to a very small wavelength, awesome. Though the phototransistor that comes with it is basically as sensitive to visible light as it is infrared, or at least that what it seems like which is not very cool. On my desk is a small lamp with a CFL that registers between 900-1000 which produces relatively little infrared light. Using the infrared LED at zero range registers slightly above 1000. I've got some old infrared gels laying around that might be able to reduce the phototransistor sensitivity of visible light to reduce the chance of unintentional triggers.

Next step now is to try it with some simple tests to see how consistent the results are. If the results from the initial tests are good that pretty much leaves setting it up in an enclosure and finishing the software. The keypad interface code seems like the most complicated part from messing around but I'm thinking a huge case switch with a mode for each button. Depending on the mode of the system each button will be context sensitive. Any thoughts or methods for keypads and interfacing that might be better than a huge case swtich would be greatly appreciated! Sorry no pictures tonight. Cheers!

Got the code in pretty good working shape. There needs to be some cleanup but it works for now. I'm thinking about enclosures now and have been looking at Protocase. Holy crap they are expensive! Was over $100 for a simple small case with a few holes cut according to their free CAD thingy. Guess its Dremel time! I would post the code but its longer than the 9500 character limit for the forum, will post in a file when its cleaned up. Going to test the new code and everything in my garage now. Cheers!

Here’s the functional code. Haven’t been able to do a test shoot yet, working some overtime lately. Thinking about testing with a light bulb or a glass of water dropping to the floor. Cheers!

#include <LiquidCrystal.h>
#include <Keypad.h>

// Setup LCD pins
LiquidCrystal lcd(22,24,26,30,32,34,36,38,40,42,44);

// Setup keypad information and pins
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {53,51,49,47};
byte colPins[COLS] = {43,41,39};
Keypad kpd = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);

// Setup camera pins
int focusPin = 52;
int shutterPin = 50;

// Setup sensor pins
int infraredPin = 0;

// Set program mode for dealing with user input
// 0 - idle
// 1 - millisecond input
// 2 - microsecond input
// 3 - infrared threshold input
// 4 - armed
// Initial program mode is idle
int programMode = 0;

// Default setup if none is selected by the user
unsigned int millisecondDelay = 250;
unsigned int microsecondDelay = 25000;
int infraredThreshold = 512;

// Setup initial infrared sensor value
int infraredReading = 1;


void setup()
{
  // Set modes for camera pins
  pinMode(focusPin,OUTPUT);
  pinMode(shutterPin,OUTPUT);

  // Display startup message
  lcd.begin(20,4);
  lcd.print(" Arduino High Speed");
  lcd.setCursor(0,1);
  lcd.print("Shutter Release v1.0");
  lcd.setCursor(0,2);
  lcd.print("  # TO ENTER SETUP");
  lcd.setCursor(0,3);
  lcd.print("      * TO ARM");
}


void loop()
{
  // Get current infrared sensor value
  infraredReading = analogRead(infraredPin);

  // Check for armed mode and trigger if beam is cut
  if(programMode == 4 && infraredReading < infraredThreshold)
  {
    delay(millisecondDelay);
    delayMicroseconds(microsecondDelay);
    digitalWrite(shutterPin,HIGH);
    delay(5);
    digitalWrite(shutterPin,LOW);
    digitalWrite(focusPin,LOW);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("SHUTTER RELEASED:");
    lcd.setCursor(0,1);
    lcd.print("Dont forget to arm");
    lcd.setCursor(0,2);
    lcd.print("again for the next!");
    programMode = 0;
  }

  // Get key from keypad and respond accordingly
  if(programMode != 4){
    char key = kpd.getKey();
    if(key)
    {
      switch(key)
      {
      case '*':
        // Arm if program mode is idle
        switch(programMode)
        {
        case 0:
          programMode = 4;
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("ARMED:");
          lcd.setCursor(0,1);
          lcd.print("Photo will be taken");
          lcd.setCursor(0,2);
          lcd.print("when IR beam is cut!");
          digitalWrite(focusPin,HIGH);
          break;
        case 1:
          millisecondDelay = 0;
          lcd.setCursor(0,3);
          lcd.print("0                   ");
          break;
        case 2:
          microsecondDelay = 0;
          lcd.setCursor(0,3);
          lcd.print("0                   ");
          break;
        case 3:
          infraredThreshold = 0;
          lcd.setCursor(0,3);
          lcd.print("0                   ");
          break;
        }
        break;
      case '#':
        switch(programMode)
        {
        case 0:
          programMode = 1;
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("SETUP:");
          lcd.setCursor(0,1);
          lcd.print("Set ms + #");
          lcd.setCursor(0,2);
          lcd.print("No MIN or MAX for ms");
          lcd.setCursor(0,3);
          lcd.print(millisecondDelay);
          break;
        case 1:
          programMode = 2;
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("SETUP:");
          lcd.setCursor(0,1);
          lcd.print("Set us + #");
          lcd.setCursor(0,2);
          lcd.print("Attn MIN:3 MAX:16383");
          lcd.setCursor(0,3);
          lcd.print(microsecondDelay);
          break;
        case 2:
          programMode = 3;
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("SETUP:");
          lcd.setCursor(0,1);
          lcd.print("Set IR threshold + #");
          lcd.setCursor(0,2);
          lcd.print("Attn MIN:0 MAX:1024");
          lcd.setCursor(0,3);
          lcd.print(infraredThreshold);
          break;
        case 3:
          programMode = 0;
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("IDLE: press * to arm");
          lcd.setCursor(0,1);
          lcd.print("ms delay = ");
          lcd.print(millisecondDelay);
          lcd.setCursor(0,2);
          lcd.print("us delay = ");
          lcd.print(microsecondDelay);
          lcd.setCursor(0,3);
          lcd.print("IR threshold = ");
          lcd.print(infraredThreshold);
          break;
        }
        break;
      default:
        switch(programMode)
        {
        case 1:
          millisecondDelay = millisecondDelay * 10 + int(key-48);
          lcd.setCursor(0,3);
          lcd.print(millisecondDelay);
          break;
        case 2:
          microsecondDelay = microsecondDelay * 10 + int(key-48);
          lcd.setCursor(0,3);
          lcd.print(microsecondDelay);
          break;
        case 3:
          infraredThreshold = infraredThreshold * 10 + int(key-48);
          lcd.setCursor(0,3);
          lcd.print(infraredThreshold);        
          break;
        }
        break;
      }
    }
  }
}

It works! I used a rubber ball to test the timing until I got it right and then used a light bulb for the first test. The results from the rubber ball were very consistent which was great news. No points for creativity here, but it freaking works!

Nice job thats pretty cool and maybe i can show it to my friend who is into photography to get him to pick up his arduino again (He used it like once and i keep bugging him about it)

Also thanks for posting the code i think this may help me with a different learning project im working on using a lcd and keypad.

Before calling it quits tonight I dropped a few more bulbs. Some original resolution images are below if you'd like to see them which are about 2MB each. Forgot to mention earlier that I'm working on the enclosure now. Its an aluminum two piece that I got from a local shop, big enough to fit the panel mount six AA battery compartment I have too so I can it on batteries if needed. Until next time, cheers!

http://www.whenpicsfly.com/tool/arduino/highSpeedShutterRelease/bulbTest1.jpg http://www.whenpicsfly.com/tool/arduino/highSpeedShutterRelease/bulbTest2.jpg http://www.whenpicsfly.com/tool/arduino/highSpeedShutterRelease/bulbTest3.jpg

Was on hiatus for a while but have been getting back into the Arduino lately. This time I’ve started with just the breadboard in an effort to reduce the cost of the final product. Using the Mega was too expensive compared to a ATmega328 chip. Next steps are to design and mill a PCB for it, then mill an enclosure. Updated source too for use with a serial LCD and larger keypad (for added functions later). Any suggestions on guides for designing and milling a PCB? I’ve not done that before but have access to a Taig mill.

#include <Keypad.h>

// Setup keypad information and pins
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {
    '1','2','3','A'  }
  ,
  {
    '4','5','6','B'  }
  ,
  {
    '7','8','9','C'  }
  ,
  {
    '*','0','#','D'  }
};
byte rowPins[ROWS] = {
  9,10,11,12};
byte colPins[COLS] = {
  3,4,5,6};
Keypad kpd = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);

// Setup camera pins
int focusPin = 7;
int shutterPin = 8;

// Setup sensor pins
int infraredPin = 0;

// Set program mode for dealing with user input
// 0 - idle
// 1 - millisecond input
// 2 - microsecond input
// 3 - infrared threshold input
// 4 - armed
// Initial program mode is idle
int programMode = 0;

// Default setup if none is selected by the user
unsigned int millisecondDelay = 250;
unsigned int microsecondDelay = 25000;
int infraredThreshold = 512;

// Setup initial infrared sensor value
int infraredReading = 1;


void setup()
{
  // Enable serial to communicate with LCD
  Serial.begin(9600);

  // Set modes for camera pins
  pinMode(focusPin,OUTPUT);
  pinMode(shutterPin,OUTPUT);

  // Display startup message
  selectLineOne();
  Serial.print(" Arduino High Speed");
  selectLineTwo();
  Serial.print("Shutter Release v1.1");
  selectLineThree();
  Serial.print("  # TO ENTER SETUP");
  selectLineFour();
  Serial.print("      * TO ARM");
}


void loop()
{
  // Get current infrared sensor value
  infraredReading = analogRead(infraredPin);

  // Check for armed mode and trigger if beam is cut
  if(programMode == 4 && infraredReading < infraredThreshold)
  {
    delay(millisecondDelay);
    delayMicroseconds(microsecondDelay);
    digitalWrite(shutterPin,HIGH);
    delay(5);
    digitalWrite(shutterPin,LOW);
    digitalWrite(focusPin,LOW);
    clearLCD();
    selectLineOne();
    Serial.print("SHUTTER RELEASED:");
    selectLineTwo();
    Serial.print("Dont forget to arm");
    selectLineThree();
    Serial.print("again for the next!");
    programMode = 0;
  }

  // Get key from keypad and respond accordingly
  if(programMode != 4){
    char key = kpd.getKey();
    if(key)
    {
      switch(key)
      {
      case '*':
        // Arm if program mode is idle
        switch(programMode)
        {
        case 0:
          programMode = 4;
          clearLCD();
          selectLineOne();
          Serial.print("ARMED:");
          selectLineTwo();
          Serial.print("Photo will be taken");
          selectLineThree();
          Serial.print("when IR beam is cut!");
          digitalWrite(focusPin,HIGH);
          break;
        case 1:
          millisecondDelay = 0;
          selectLineFour();
          Serial.print("0                   ");
          break;
        case 2:
          microsecondDelay = 0;
          selectLineFour();
          Serial.print("0                   ");
          break;
        case 3:
          infraredThreshold = 0;
          selectLineFour();
          Serial.print("0                   ");
          break;
        }
        break;
      case '#':
        switch(programMode)
        {
        case 0:
          programMode = 1;
          clearLCD();
          selectLineOne();
          Serial.print("SETUP:");
          selectLineTwo();
          Serial.print("Set ms + #");
          selectLineThree();
          Serial.print("No MIN or MAX for ms");
          selectLineFour();
          Serial.print(millisecondDelay);
          break;
        case 1:
          programMode = 2;
          clearLCD();
          selectLineOne();
          Serial.print("SETUP:");
          selectLineTwo();
          Serial.print("Set us + #");
          selectLineThree();
          Serial.print("Attn MIN:3 MAX:16383");
          selectLineFour();
          Serial.print(microsecondDelay);
          break;
        case 2:
          programMode = 3;
          clearLCD();
          selectLineOne();
          Serial.print("SETUP:");
          selectLineTwo();
          Serial.print("Set IR threshold + #");
          selectLineThree();
          Serial.print("Attn MIN:0 MAX:1024");
          selectLineFour();
          Serial.print(infraredThreshold);
          break;
        case 3:
          programMode = 0;
          clearLCD();
          selectLineOne();
          Serial.print("IDLE: press * to arm");
          selectLineTwo();
          Serial.print("ms delay = ");
          Serial.print(millisecondDelay);
          selectLineThree();
          Serial.print("us delay = ");
          Serial.print(microsecondDelay);
          selectLineFour();
          Serial.print("IR threshold = ");
          Serial.print(infraredThreshold);
          break;
        }
        break;
      default:
        switch(programMode)
        {
        case 1:
          millisecondDelay = millisecondDelay * 10 + int(key-48);
          selectLineFour();
          Serial.print(millisecondDelay);
          break;
        case 2:
          microsecondDelay = microsecondDelay * 10 + int(key-48);
          selectLineFour();
          Serial.print(microsecondDelay);
          break;
        case 3:
          infraredThreshold = infraredThreshold * 10 + int(key-48);
          selectLineFour();
          Serial.print(infraredThreshold);        
          break;
        }
        break;
      }
    }
  }
}


//Serial LCD Functions
void selectLineOne(){
  Serial.print(0xFE, BYTE);
  Serial.print(128, BYTE);
}

void selectLineTwo(){
  Serial.print(0xFE, BYTE);
  Serial.print(192, BYTE);
}

void selectLineThree(){
  Serial.print(0xFE, BYTE);
  Serial.print(148, BYTE);
}

void selectLineFour(){
  Serial.print(0xFE, BYTE);
  Serial.print(212, BYTE);
}

void goTo(int position) {
  if (position<20){ 
    Serial.print(0xFE, BYTE);
    Serial.print((position+128), BYTE);
  }
  else if (position<40){
    Serial.print(0xFE, BYTE);
    Serial.print((position+128+64-20), BYTE);
  }
  else if (position<60){
    Serial.print(0xFE, BYTE);
    Serial.print((position+128+20-40), BYTE);
  }
  else if (position<80){
    Serial.print(0xFE, BYTE);
    Serial.print((position+128+84-60), BYTE);
  } 
  else { 
    goTo(0); 
  }
}

void clearLCD(){
  Serial.print(0xFE, BYTE);
  Serial.print(0x01, BYTE);
}

void backlightOn(){
  Serial.print(0x7C, BYTE);
  Serial.print(157, BYTE);
}

void backlightOff(){
  Serial.print(0x7C, BYTE);
  Serial.print(128, BYTE);
}

void backlight50(){
  Serial.print(0x7C, BYTE);
  Serial.print(143, BYTE);
}

void serCommand(){
  Serial.print(0xFE, BYTE);
}

Re: soldering on the LCD

It's obviously working, so that's good. Overall, it looks fine, but I think (at least from the picture) that a couple of the pins are either not fully soldered, or potentially have "cold" joints. It could be the flash or angle of light/reflection I am seeing, too.

Looking from the left, pins that are visible, I would check the 2nd, 3rd, and 6th pin in the photo. A reheat and maybe a touch of solder and they would be perfect (and potentially prevent a debugging headache later).

Other than that, it looks sweet! Great pics, too! High speed photography is awesome to see.

:)