About Author
Joe Caldwell - electrical/controls engineer. I hope you enjoy this repository of my various projects and ideas. Thanks for looking.



Search


Daily


Projects

« Hard Drive Speakers | Main | Solar Chargeable MintyBoost »
Monday
20Jul2009

Arduino Intervalometer for Time-lapse Photography 

Last fall when I built my first intervalometer and then used it for some time-lapse photography, the limitations of such a design became apparent. With an analog timer the circuit is limited by component values to function in a fixed way. The timing ranges cannot be changed without rebuilding the circuit and there is no way to be truly precise in your timing. A few months ago I came across this design for an Arduino intervalometer which is very basic and requires reprogramming for any timing changes. After some planning I decided to take the best features of my original intervalometer and combine it with an Arduino's flexibility to make a much more versatile intervalometer.

Key features to keep from the original were:

  • Camera interface isolation
  • Timing range options
  • Battery or AC adapter power options
  • Camera connection flexibility
  • Manual controls

Additional features that I wanted to add were the following:

  • Power supply flexibility
  • LCD readout
  • Start/Stop the timing cycle

In order to maintain what worked best in the original design I simply copied it directly over to the new version. I used the same relay isolation for shutter triggering, as well as hard-wired pushbuttons for manual focus and shutter control. I also used the same 3.5mm jack to connect to the camera as the original. For power I decided to use a coaxial power jack as I had previously but this time I did not place a battery inside the enclosure. Instead, I made an adapter cable with an N style coaxial DC power plug on one end and a USB plug on the other end. With this cable I can power my new intervalometer from any 5V USB power source (PCs, wall adapters, MintyBoost, etc). In order to keep this build as simple and inexpensive as possible I decided to use the Arduino Pro and a basic LCD for a total cost of $36. The Arduino Pro is the same as a standard Arduino, except it uses all surface-mount components and has no USB interface. This keeps the cost down and reduces the board size. The LCD was simple to wire requiring only +5V, ground, 6 data lines and a dimmer potentiometer input. The final features were all implemented in the Arduino code. 

I ran into a few problems while developing the code for this project:

  • How to adjust the timing interval value
  • How to start & stop the timing cycle
  • How to switch timing ranges

For adjusting the timing interval I had originally planned to use pushbuttons, however, after playing with the idea I decided against it. I found that it was much quicker and more user friendly to use a potentiometer as a virtual selector switch. In order to do this I used the map function, to divide up the potentiometer's analog input values into the specified number of steps.

Starting and stopping the timing cycle was not as easy as it first appeared because the simplest way to wait a specific amount of time between events is to use the delay function. The problem with this is that while the program is delaying for the set amount of time, no other commands are being run and inputs are not recognized. To get around this I used a technique I found on the Arduino website which blinks an LED without using the delay function. Instead it sets a preset interval and then checks how much time has past using the millis function until enough time has gone by to trigger the desired event. This allows the processor to keep scanning the code while the timing cycle is taking place. Now if I want to cancel the timing cycle I can do so without resetting the Arduino.

To switch timing ranges I used this clever piece of code that allows you to use one button for two functions. When the button is pressed the Arduino keeps track of how long it was pressed. For short presses it performs one function and for longer presses it does another. I used this method to implement both timing range switching as well as toggling between set mode and timing mode as shown in the video below.

After getting all of my code together I assembled my new intervalometer in a 6"X4"X2" project box from Radioshack. This is somewhat oversized for these purposes, but it's cheap and readily available. Overall I am very pleased with this project. The responsiveness of the interface is very good and it triggers my camera shutter perfectly. The two timing ranges I preset in the unit are 5-60 seconds in 5 second steps and 30 seconds to 10 minutes in 30 second steps. These should cover the most common intervals I will use, and I can change them at any time if I have to. This is by far the most complicated Arduino coding that I have done and it was a great learning experience. Check out the video below for a demonstration of the device.

My finished Arduino code is shown below, or you can download the sketch here. Note: the LCD requires the updated LiquidCrystal Library, checkout this tutorial if you are using version 0016 or earlier of the Arduino software.

#include <LiquidCrystal.h>                //library for LCD control
// LiquidCrystal display with:
// RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); //Set which LCD pins are used for data
//I-O setup
const int potentiometer = 0; //Potentiometer analog input pin
const int mode = 2; //Mode button input pin
const int shutter = 3; //Shutter relay output pin
//Variables
long interval = 5000; //time between shutter presses
long previousMillis = 0; //previous millisecond value
int hold = 1000; //time shutter should be held open
int M = 0; //Mode button state
int Mstate = 0; //previous Mode button state
int StartSet = 0; //Mode state
int pot; //potentiometer reading
long range; //potentiometer position
int count = 0; //picture count
int ModeSW = 0; //Low-High set mode toggle
//Press & Hold variables
#define debounce 50 // ms debounce period to prevent flickering when pressing or releasing the button
#define holdTime 2500 // ms hold period: how long to wait for press+hold event
long btnDnTime; // time the button was pressed down
long btnUpTime; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered

//Initialize I-O
void setup() {
pinMode(shutter, OUTPUT);
pinMode(mode, INPUT);
lcd.begin(16, 2); //set LCD for 16 columns & 2 rows of display
}

void loop(){
M = digitalRead(mode); //read Mode button state
//Test for button pressed and store the down time
if (M == HIGH && Mstate == LOW && (millis() - btnUpTime) > long(debounce))
{
btnDnTime = millis();
}
//Test for button release and store the up time
if (M == LOW && Mstate == HIGH && (millis() - btnDnTime) > long(debounce))
{
if (ignoreUp == false) ModeSW = !ModeSW; //test if Low-High set mode should be toggled
else ignoreUp = false;
btnUpTime = millis();
}
//Test for button held down for longer than the hold time
if (M == HIGH && (millis() - btnDnTime) > long(holdTime))
{
StartSet = !StartSet; //toggle Set mode to Timing mode or vice versa
ignoreUp = true;
btnDnTime = millis();
}
Mstate = M;
//Test for Set Mode
if(StartSet == LOW){
lcd.home(); //set cursor to LCD column 1, row 1
lcd.print("Set Mode "); //display "Set Mode" on LCD
count = 0; //reset picture count
if(ModeSW == LOW) LowRange(); //test Low-High set mode
else HighRange();
}
//Test for Timing Mode
else{
lcd.home(); //set cursor to LCD column 1, row 1
lcd.print("Timing Mode"); //display "Timing Mode" on LCD
Shutter(); //call Shutter triggering function
lcd.setCursor(0, 1); //set cursor to LCD column 1, row 2
lcd.print(count); //display picture count number on LCD
lcd.print(" Pictures "); //display "Pictures" on LCD
}
}

//Low Set Mode function
long LowRange(){
long seconds; //shutter timing interval in seconds
pot = analogRead(potentiometer); //read potentiometer value
range = map(pot, 0, 1023, 12, 1); //divide potentiometer range into 5 second steps
interval = 5000 * range; //convert steps into 60 second range in milliseconds
seconds = interval/1000; //convert milliseconds to seconds
lcd.setCursor(0, 1); //set cursor to LCD column 1, row 2
lcd.print(seconds); //display shutter timing interval in seconds on LCD
lcd.print(" seconds "); //display "seconds" on LCD
return interval; //return shutter timing interval value to loop
}

//High Set Mode function
long HighRange(){
float minutes; //shutter timing interval in minutes
pot = analogRead(potentiometer); //read potentiomenter value
range = map(pot, 0, 1023, 20, 1); //divide pot range into 30 second steps
interval = 30000 * range; //convert steps into 10 minute range in milliseconds
minutes = interval/60000; //convert milliseconds into minutes
lcd.setCursor(0, 1); //set cursor to LCD column 1, row 2
lcd.print(minutes); //display shutter timing interval in minutes on LCD
lcd.print(" minutes "); //display "minutes on LCD
return interval; //return shutter timing interval value to loop
}

//Shutter triggering function
int Shutter(){
//Test that timing interval has passed
if((millis() - previousMillis) > interval){
previousMillis = millis(); //save the last time shutter was triggered
digitalWrite(shutter, HIGH); //trigger shutter relay coil
delay(hold); //wait preset shutter hold time
digitalWrite(shutter, LOW); //release shutter relay coil
++count; //increment picture count
return count; //return picture count value to loop
}
else return count;
}

Reader Comments (4)

Oh my gosh, this is exactly what I've been looking for! I'm hoping to build an intervalometer for my Panasonic GH1. What camera are you using with this? The GH1 apparently uses different resistance values for half-shutter-press and full-shutter-press. http://www.instructables.com/id/Panasonic-G1-GH1-Remote-Shutter-Release/ It looks to me like you're simply setting the shutter connection to high vs. low, but I suppose this is a simple modification for me to make, no?

This would be my first Arduino project but I'm excited to take the plunge!

September 27, 2009 | Unregistered CommenterKris

Aha. Canon Rebel... found it in the older intervalometer post. Sorry for the premature question!

September 27, 2009 | Unregistered CommenterKris

There is an unused Arduino in my junk box and I need an intervalometer for my Nikon D90.
Congratulations to your work ! It will help much to make it work.

November 10, 2009 | Unregistered CommenterOtto

Most excellent design! I will be eager to start the project.

November 27, 2009 | Unregistered CommenterMark Ahlman

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>