For any DIY time-lapse project, the intervalometer is the first building block, and usually the first problem to solve. An intervalometer isn't required to do much more than fire the camera at a set period of time. However, in a motion control rig or integrated with other devices it can serve as a metronome and design driver for the entire system. With careful design and a little creativity, you can build anything. In this article, we'll focus on designing an intervalometer that utilizes the easy-to-use and inexpensive Arduino microcontroller. We'll walk through the basics of building a simple circuit, different techniques for implementing our timing, and hooking up our camera to complete the process of making a working intervalometer. Without any prior experience in electronics, we'll be able to put together a great, flexible system for around thirty dollars and build the foundation for the next tutorial.
The Test Circuit
The test circuit will allows us to get the basics of wiring everything up and testing our software without worrying about putting wear and tear on our camera, or even worse - damaging it. In this simple circuit, an LED will replace our camera, with the added benefit of being easier to debug than with a camera involved. You'll likely find that replacing the camera and even motors with LEDs will make testing any stage of your project easier and less costly.
We'll need the following parts, which can be had very inexpensively from several suppliers:
- (1x) Arduino Deicimilla or Duemilinova
- (1x) 4N28 Optocoupler
- (2x) 540 Ohm resistor
- (1x) LED
- Hookup/jumper wires
- Breadboard strip
Arduino
The Arduino micorcontroller is a low-cost development board for the Atmega AVR RISC processor line. If you're unfamiliar with Arduino, or microcontrollers in general, you can think of it as a very small, 16Mhz computer that fits in the palm of your hand. Obviously, it's not very much like your desktop - it isn't multi-threaded and it doesn't have a plethora of memory, but the real benefit of the new generations of microcontrollers, such as the Arduino, is that you can build complex devices with relative ease and at a low cost. Arduino is open-source and you can either build one yourself, or buy one from any number of distributors, usually for around $20. The added benefit of Arduino over other microcontroller platforms, for our purposes, is the rich open-source library set and easy-to-use GUI that lets you quickly write software in C++ without having any prior experience in microcontrollers, assembly, or advanced electronics design.
While this lesson is specifically targeted at the Arduino platform, the information in here may easily be applied to any of the great microcontroller platforms out there.
Optocouplers
One of the first questions I get asked when talking to new DIY'ers about building motion control circuitry is "do I have to use an optocoupler?" The short answer is always an emphatic yes! The longer answer is that optocouplers are very, very cheap - a 4N28 can be had for a few cents, and your shiny dSLR is expensive - usually starting at a few hundred dollars. If you make a mistake in testing or wiring, and fry out a $20 microcontroller and $0.20 opto-coupler, you're probably not going to cry yourself to sleep that night. However, after the first, or even second time you fry an expensive camera, you might be inclined to change your ways!
The purpose of an optocoupler is to electrically isolate two different circuits, while still allowing communication between them. By electric isolation, we mean that there is no direct flow of electricity between the two circuits, and yet they can interact. This is generally achieved by having two components inside of the optocoupler: an infrared LED and a light-sensitive transistor. When power is applied to the LED, the photons from it engage the base of the transistor and allow current to flow from the collector of the transistor to the emitter. This can be seen in the symbols used to represent the different pins of an optocoupler - we see the symbols for a diode on one side, and a transistor on the other. For a crash-course on optocouplers, you can start here: www.mech.uwa.edu.au/NWS/How_to_do_stuff/micro_crash_course/optocoupler/
The remote cable port on most mid-high level dSLRs work by producing a positive voltage on one contact, and then reading for the presence of that voltage on another contact. That is, the actual trigger part of the remote is usually nothing more than a switch that connects the two lines, and triggers the camera to fire. This means that electricity is flowing down this circuit, and we have numerous ways of triggering this connection, such as: sending our own voltage signal down the wire to the camera (and thus requiring also sharing a ground line with the camera), engaging some sort of mechanical relay to connect the two lines of the camera, managing a transistor directly, or using an opto-coupler. The opto-coupler route is not only very safe, but also is extremely easy to implement and inexpensive.
Effectively, the live line from the camera will feed into the collector of the transistor side of the optocoupler, and the trigger line will feed from the emitter. Our arduino will attach to the LED side of the optocoupler.
For the purposes of building a circuit to test all of our logic with, we will replace the connection to the camera with an LED. Doing so reduces the number of variables in our learning process, provides a nice visual indicator of success, and prevents unnecessary wear on our cameras.
Building the Circuit
The following schematic describes what we're going to make. If it's all greek to you, just hang in there - we're going to show you step-by-step in photos. (As an added bonus, if you're unfamiliar with circuit diagrams, you'll be able to reference back and figure out what the symbols and connections mean based on the photos.)
Our test circuit schematic:

Step 1: Lay out all of your materials

Step 2: Run jumper wires from the 5V and GND pins on the arduino to the +/- power rails on your breadboard

Step 3: Place the optocoupler securely into the breadboard, and run a jumper from the GND rail to the cathode (k) on the opto-coupler
note: the opto-coupler chip will always have some sort of registration mark, you will use this mark to align the chip so that you can determine where each pin is. The pin layout for your chip will be in the datasheet for the chip, do not rely on your chip having the same registration mark or pin layout as the one I am using!

Step 4: Run a 540 Ohm resistor to the anode (a) on the opto-coupler

Step 5: Run a jumper wire from pin 13 on the Arduino to the 540 Ohm resistor
note: we use pin 13, because it is connected to the status LEDs on the board. This way, we can verify when our LED *should* fire, because we'll see the orange status LED fire at the same time.

Step 6: Run a jumper wire from the 5V rail to the collector (c) on the opto-coupler

Step 7: Connect the anode (a) of your LED to the emitter (e) of your opto-coupler
note: the anode can easily be distinguished from the cathode by the fact that the component inside of the LED is smaller on the anode side, and that the anode lead is usually longer than the cathode lead.

Step 7: Connect the cathode of the LED to the GND rail via a 540 Ohm resistor and a jumper wire
The finished product should look something like this:


Test the Circuit
Now, when you attach the USB cable from the Arduino to your computer, it should turn on and you'll see the yellow status LED light up on the board. At the same time that the on-board LED lights up, the red LED in your circuit should light up. If it does not, go back, double-check the datasheet for your optocoupler, and all of your connections to make sure that everything is hooked up correctly.
Writing Your Sketch
In Arduino-land, your source code is referred to as a 'sketch'. It's in this part that we'll get into the nuts and bolts of the logic we'll base our intervalometer on. It's time to go ahead and load up the Arduino IDE. If you're having trouble running the IDE, or setting your board up, drop by www.arduino.cc for help getting started there. We're going to assume that you're using at least version 015 of the interface -- this is very important.
Without a doubt, the most common example of a camera intervalometer with the Arduino, involves a simple series of delays and pin mode changes in the main loop. It will look something like this:
#define INTERVAL_TM 2000
// exposure length (how long to fire camera)
#define EXPOSURE_TM 1000
// our pin that will trigger the camera
#define CAMERA_PIN 13
void setup() {
// prepare camera pin as an output
pinMode(CAMERA_PIN, OUTPUT);
}
void loop() {
digitalWrite(CAMERA_PIN, HIGH);
delay(EXPOSURE_TM);
digitalWrite(CAMERA_PIN, LOW);
delay(INTERVAL_TM);
}
The core concepts to pay attention to here:
- The function loop() will be run over and over again, it is the main code execution point for the Arduino
- delay() waits for the specified number of milli-seconds.
- pinMode() changes the state of our pin, either HIGH (+5V) or LOW (~0V)
Effectively, what we're doing is simply changing the pin state to high (to fire our camera, or light up the LED), waiting for the pre-defined exposure length time in milliseconds, bringing the pin state back to low, and then waiting until it's time to fire the next shot.
While this is pretty straight-forward, and would certainly solve our need for firing the camera on a given interval, it has a number of draw-backs. Primarily, all we can do here is fire the camera. The delay()'s mean that nothing else will be happening at that time, and if we tried to do anything else after the delay between shots, our timing our would be off. Essentially, we're stuck.
Non-blocking Timing
So, how can we go about not wasting all of the precious capabilities of this processor while we're waiting to shoot the next shot, and while we're actually performing the shot?
We can use a non-blocking method of timing. By non-blocking we mean that our act of timing, waiting before taking an action, won't interfere with other operations. That is to say, instead of sitting around and waiting for the next time to trigger an action (fire the camera, stop exposing, etc.), we're going to do something else. What else might we like to do? Well, if you have a user interface (some buttons and an LCD for example), you can take input from the user, update the display -- or even, move some motors or check the status on some external sensor. If you're stuck in a delay() loop -- you can't do any of that.
The most basic form of non-blocking timing is to keep track of the last time you did something, and then take an action when the difference between that time and the current time is greater than or equal to your timer. In the code below, we'll use two counters, one for the last time we triggered a shot, and one for when the exposure started - so that we know when to bring the pin down low.
#define INTERVAL_TM 2000
// exposure length (how long to fire camera)
#define EXPOSURE_TM 1000
// our pin that will trigger the camera
#define CAMERA_PIN 13
// last time our camera fired
unsigned long last_tm = 0;
// counter for how long we've been exposing
unsigned long exp_tm = 0;
// whether or not we're currently exposing
bool exposing = false;
void setup() {
// prepare camera pin as an output
pinMode(CAMERA_PIN, OUTPUT);
// for debugging purposes
Serial.begin(19200);
}
void loop() {
if( exposing == false && millis() - last_tm > INTERVAL_TM ) {
// if the camera is not currently exposing, and our
// timer has elapsed, fire camera...
// reset exposure timer
exp_tm = millis();
// set flag to indicate that we're currently
// exposing
exposing = true;
// enable optocoupler
digitalWrite(CAMERA_PIN, HIGH);
} // end if not exposing and timer has elapsed
else if(exposing == true && millis() - exp_tm > EXPOSURE_TM) {
// if we're currently exposing, and our exposure
// time has elapsed...
// disable optocoupler
digitalWrite(CAMERA_PIN, LOW);
// we set this now to ensure that our
// interval time is measured from the
// time an image is completed until the
// time the next one is triggered
//
// if you want the interval time to be
// measured between the time the image
// is triggered and the next image is
// triggered, move this to before
// bringing the camera pin high
last_tm = millis();
// reset exposing flag
exposing = false;
}
}
Note that in the above code, we also have to know if we're currently firing the camera. The exposing variable keeps track of that for us. If we didn't keep track of it, we might end up trying to expose the camera when it already is, if we made the mistake of setting the exposure time longer than the interval time. While it may seem silly to keep track of this when you can just make sure that you don't set your timing to such nonsense, it's an important concept down the road when we start building more complex systems, and multiple actions can occur on their own schedule.
If you've read around on the Arduino for a while, especially on older versions, you may ask "Won't the millis() counter overflow at some point and go back to zero?" Yes, it will. After several days of running. However, as we don't care to keep track of the actual time on the wall, but instead only about how much time has passed since our last action, it's not such a big deal. Additionally, that little subtraction operation? It'll return true when millis() overflows back to zero. Yeah, they thought of that, so you don't have to. If they hadn't, it'd only work until the millis() counter overflowed.
Overflowed? What's that? Overflowing is when the value you're trying to store in a variable increases beyond the maximum value that can be expressed for a given datatype. For example, if I tried to store 300 in an 8-bit value, I'd be sorely surprised. In a signed variable, I'd get a negative value, in an unsigned I may wrap around or just stay at the maximum value, depending on the compiler.
Of course, our technique above still has a draw-back. If we were to go about other tasks while the camera is exposing, like reading buttons or keys that the user is pressing, and we took too long, we could end up over-exposing our shot, should we be in bulb mode. So, how do we prevent that?
Using Interrupts
Have no fear dear reader, I'm not going to bring you into the hairy voodoo that is writing AVR interrupts directly. Instead, we're going to use a spiffy little library that takes care of the grunt work for us, called MsTimer2. As you might guess from the name, it's a timer that is based on milliseconds, and it uses the second timer interrupt in the AVR chip. The only thing you need to worry about with that is that you won't be able to do PWM output on pins 8 and 9 - but if you didn't already guess that, it certainly won't be an issue for most applications.
It's important to note that the Arduino is single-threaded, meaning it can only do one thing at a time. However, that doesn't mean that you can't stop in the middle of something to react to something else. That's what interrupts do - they let you trigger some code to be executed when a certain condition is met.
In the following example, we use our non-blocking timer to determine when to fire the camera, but then we use the MsTimer2 interrupt to determine when to stop exposing the camera, based on the passing of time. (Or, of time having passed?)
// shot interval time
#define INTERVAL_TM 2000
// exposure length (how long to fire camera)
#define EXPOSURE_TM 1000
// our pin that will trigger the camera
#define CAMERA_PIN 13
// last time our camera fired
unsigned long last_tm = 0;
// whether or not we're currently exposing
bool exposing = false;
void setup() {
// prepare camera pin as an output
pinMode(CAMERA_PIN, OUTPUT);
// for debugging purposes
Serial.begin(19200);
}
void loop() {
if( exposing == false && millis() - last_tm > INTERVAL_TM ) {
// if the camera is not currently exposing, and our
// timer has elapsed, fire camera...
// set timer interrupt to call our
// function to disengage the camera
MsTimer2::set( EXPOSURE_TM, camera_off );
// enable timer
MsTimer2::start();
// set flag to indicate that we're currently
// exposing
exposing = true;
// enable optocoupler
digitalWrite(CAMERA_PIN, HIGH);
} // end if not exposing and timer has elapsed
}
void camera_off() {
// disable optocoupler
digitalWrite(CAMERA_PIN, LOW);
// disable timer
MsTimer2::stop();
// we set this now to ensure that our
// interval time is measured from the
// time an image is completed until the
// time the next one is triggered
//
// if you want the interval time to be
// measured between the time the image
// is triggered and the next image is
// triggered, move this to before
// bringing the camera pin high
last_tm = millis();
// reset exposing flag
exposing = false;
}
In this case, once we fire the shot, we set the timer to change the pin state to low after a certain number of milliseconds have past. That is, we register our camera_off() function as the callback associated with the interrupt.
The more adventurous reader might inquire - "Can't I just set a timer for the interval, on its trigger engage the camera, then set a timer for exposure time, and then in the camera_off() function re-register the interval timer?" (I said adventurous, right?) The short answer is no. As to why: interrupts are difficult to handle at the low level, and you want to do as little as humanly possible while in an interrupt callback, corruption and even processor lock-up can occur if you spend too long in the callback. Wormholes appear and kittens walk upside down when you try to re-register an interrupt inside of its own callback.
If you upload each of these sketches to your Arduino, and run them, you'll notice that they all do exactly the same thing: every two seconds the LED flashes for one second. While they have the same end-result, they each get there a different way, and enable or disable other activities. This is the key lesson to take away: consider all of the things that you want to do before you start writing code.
So, let's get on to hooking up our camera...
The Camera Connection
For a modern dSLR, there are generally two methods of controlling the camera remotely: hard-wired and infrared. For the purposes of this tutorial, we'll only focus on the hard-wired form. Most mid-level and higher cameras will come with a remote cable port. Unlike classic cameras where this was generally a manual connection - pressing a plunger pushed a cable into a socket, in a modern dSLR the remote port is usually a live circuit connection. For many Canon and Pentax cameras, a simple 2.5mm TRS (aka 'stereo cable' like you would use with your ipod) connector is utilized. TRS refers to 'tip, ring, sleeve' - which are three components of the connector, with the tip being the part furthest from the cable, the ring being in the center, and the sleeve being nearest the cable.
Some cameras will continue to use a standard 3-wire control, but may use a proprietary connector. For these, you will either have to sacrifice an existing remote cable as a donor, or find the part for your particular camera.
In the case of Canon and Pentax, the control circuit is very simple: the tip is the shutter trigger, the ring is the focus trigger, and the sleeve is the common connection. Connecting the common lead to the shutter trigger will result in an exposure, and connecting the common lead to the focus trigger will cause the camera to engage autofocus. On many cameras, the common is a ground connection and the shutter/focus leads will be positive voltage. On others, it may be the other way around - a simple multimeter can establish which is which for you. It is important that whichever lead is ground from your camera's port be hooked up to the emitter of the optocoupler.
The schematic below shows our final circuit. Note here that, unlike in our test circuit, the camera side of the optocoupler is now completely isolated from the left side. If you were wondering what supposed benefit the optocoupler provided, it should now be obvious.

If your camera has a standard 3-pin TRS connector, either 2.5 or 3.5 mm, you can simply take an old cable, cut the end off, and expose the three leads. Hook them up into your circuit (Replace the LED, and all connections to the arduino, including GND and +5V from the test circuit!), turn on your camera, and then plug in the Arduino with one of the sketches above installed and voila - you're taking a shot every two seconds.
- c.a. church

Including a potentiometer to set the interval.
Excellent tutorial, greatly appreciate the work gone into this.
Just wondering where a potentometer would be situated in the circuit in order to set the interval, and what alterations to the code would be needed?
Also wondering how a jack would be connected too for my 3.5mm camera connector?
If anyone has answers to these I would be very grateful...many thanks
Phil
POT, Jack
For a 3.5mm (although, I believe most camera cables have a 2.5mm connector, but some do have 3.5) TRS jack, you'd hook the shutter to the Tip, and the Common (gnd) to the sleeve. If you want to add focus control, use another opto-coupler, and hook it to the ring, sharing the same common as the shutter line.
As for a POT, you could hook that up to any analog input, and then do an analogRead() on that input and map the value to some interval time, replacing the interval variable. Mind you, a pot may be harder to use to get an exact interval, but you could make marks on your enclosure or something to indicate different known values.
!c
Regulating 12v power supply
Thanks so much for your help. I have finally got the test circuit working with two potentiometers, one to adjust the exposure of the camera and another to drive a DC motor. I have also uploaded the code onto an ATtiny45 so no longer need the Arduino. My problem is, is that I have one 12v power source for the motor, and a separate one (5v) to power the ATtiny45 microprocessor. I am not sure how to use the 12 volt supply for the motor but also regulate its power for the microprocessor. I am wondering if this link provides the answer:
http://www.learningaboutelectronics.com/Articles/How-to-connect-a-voltage-regulator-in-a-circuit
but have another lead from the positive of the power source going to the motor and the microprocessor replacing the LED.
Any help on this would be greatly appreciated, I am completely stuck on this one, I have already blown one regulator which stunk out the whole house with burnt plastic.
thanks in advance
Phil
Help
Hi there,
Thanks so much for posting this. Its really helpful. I'm trying to build a rig of my own and my test circuit is built, but won't light. I'm using a 4N27 Otopcoupler, I checked the specs the 4N27 and 4N28 seem to be identical. Yet my light won't turn on, and the Arduino Deicimilla has the green light on, but a flashing orange light in addition.
If anyone has any insight or willingness to help me out, I would love it. Thanks! My email is eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%61%2e%63%61%74%74%61%72%69%6e%40%67%6d%61%69%6c%2e%63%6f%6d%22%3e%61%2e%63%61%74%74%61%72%69%6e%40%67%6d%61%69%6c%2e%63%6f%6d%3c%2f%61%3e%27%29%3b'))
Thanks!
DC or USB
Hey,
Just wondering how you would power the arduino when in the field?
-S.
Nice tutorial. I'll
Nice tutorial. I'll definitely going to try this and figure it myself.
_____________________
This looks like a great
This looks like a great tutorial. Can't wait to have a good read when I finish work tonight!