Projects

Perfect Timing - Intervalometer

Arduino-Powered Camera Controller

Liam Davies

Issue 50, September 2021

This article includes additional downloadable resources.
Please log in to access.

Log in

Remotely control your camera or other workshop gadgets with this handheld intervalometer, with Bluetooth Low Energy, a gesture sensor, and a flash laser-cut case to boot!

BUILD TIME: A weekend
DIFFICULTY RATING: Intermediate

As cameras become more and more integrated with the workflows and lifestyle of photographers, manufacturers are jamming awesome connectivity technology into new DSLRs and mirrorless cameras. However, there are a couple of issues with these additional wireless features becoming commonplace.

With our Canon 200D II, for example, it must be paired with Bluetooth to act as a remote control, but it features no Live View or playback functionality. To access these features, you need to connect to it over WiFi, set up one of two ways.

The ‘hotspot’ mode of the camera creates a WiFi access point that can be set up anywhere, but disables your controller device’s internet connection in the meantime – even if your phone has 4G reception. This is frustrating if you have to disconnect from the camera’s WiFi to visit a website or use an app.

The second mode connects your camera to your household or workplace WiFi, and if your phone is on the same network, communication can be accomplished through a dedicated router. Naturally, taking photos outside of the WiFi range can’t be accomplished as there is zero connection between your phone and the camera.

On a different topic, plenty of people still use older DSLRs with poor connectivity or even vintage cameras that have less electronic sophistication than a 1950’s farm tractor. There’s absolutely nothing wrong with this, and some analog aficionados prefer the beautiful simplicity of the method. If your camera supports some sort of electronic trigger, there’s a good chance it will work with this project – albeit possibly with some adaptation or some light-hearted hacking.

This project won’t expand the inbuilt wireless processing of your camera but will provide another point of control for using it conveniently. Our aim for this project is to build a remote camera trigger that can be customised to do whatever you want it to do, whilst making wireless communication as simple as possible.

For those who are new or interested in photography, a remote trigger is useful for a number of purposes but is most commonly used for preventing blurred long exposures. If a camera is shaken or bumped enough to move light from the same object across multiple pixels, blurring results. More often than not, this comes as a result of pressing the camera’s shutter button by hand. A remote trigger eliminates this by simply being as far away from the camera as possible, usually with a cable or over a wireless connection.

There are other instances where a remote trigger is very useful, too. When doing group photos or shots where the photographer cannot be behind the camera, a remote trigger helps significantly.

However, you can also further automate taking photos by extending the remote shutter to be an intervalometer, which can take multiple photos with predetermined delays set up as the user desires. There are typically four separate settings available on an intervalometer.

The first setting is Delay and is simply the time in seconds, between activating the intervalometer and taking the first photo. Modern cameras and even smartphones have this feature built-in, and typically have a short delay of about 2-3 seconds and a long delay of 10-15 seconds too. Intervalometers let you set exactly what time you would like, anywhere from none at all (instant) to many hours.

The second setting is Exposure, or “Long” as it’s sometimes labelled, which is how many seconds your camera’s shutter is open for. Note that cameras won’t actually obey intervalometer control of the exposure unless it is in BULB mode, in which the shutter is open as long as the button is pressed.

The third setting is Interval and is how long the intervalometer waits between consecutive photos. This is useful if you are capturing very long timelapses, or for events that occur with a consistent interval between them.

The fourth and final setting is Count, or “N” – simply the number of photos you wish to capture.

Besides the simple use of taking a large collection of photos over time for timelapses, Intervalometers may also be useful for more specialised use-cases like astrophotography. Photographing the stars requires a careful balance of exposure time – not enough data is captured with short exposures, and star streaking results with long exposures. We made a Star Tracker back in Issue 44 if you’d like more information.

How It Works

Before we get into the fancy tech that will help us take photos easily, we’re going to start with the basics of how you can remotely trigger your camera. While there are many different configurations for this, in the Canon lineup this most frequently consists of three contacts on a 2.5mm jack. This is usually marked as the ‘remote’ port on the side of the camera and has a GND, Focus and a Shutter contact, which can be shorted together to trigger the associated actions.

Unfortunately, camera manufacturers often have proprietary connectors to their shutter cables or sometimes even separate wiring methods. We found a good guide on this website for further information about these configurations: https://doc-diy.net/photo/remote_pinout

Shorting the trigger signals to ground can be done directly with electronics like a MOSFET or transistor. However, should our circuit accidentally produce a high voltage, it will feed back into the camera’s circuits and potentially damage the internal electronics. To avoid this, we can use either an optocoupler or a relay to isolate the two circuits. We featured a Camera Trap project back in Issue 30 with this setup, so check that out if you’re interested in a compact setup.

With this project, we’re using relays to accomplish the camera triggering. While it’s overkill from a power perspective, galvanic isolation is the priority – physically isolating the two circuits. There are also some other advantages to using relays for this project. First of all, we’re also going to add functionality to trigger external circuits with the intervalometer – making it handy for testing any project. Also, the ‘click’ of the relay activating is a good way of knowing that your camera has fired – newer mirrorless cameras are nearly silent so it’s hard to tell that they’ve fired from a couple of metres away. (Not to mention the relay sound is incredibly satisfying!)

The main issue with relays is the additional power and voltage required to drive them. When it comes to comparing the direct alternative, optocouplers – which are essentially just integrated LEDs – relays need enough voltage to energise the solenoid coil and close the contacts. There are 5V relays available, but these are sometimes a little annoying to get hold of from Australian suppliers and hence we’ve opted to use some 12V relays with a 9V battery as a power source. As long as the battery has a reasonable amount of remaining charge, the 9V is able to activate the relays happily. To keep it compact, we’re using a very simple NPN transistor set up to drive current through the relay.

Extra Features

We also want to add some extra flair compared to what’s already on the market. First up, we’re adding hand gesture control for more convenient access to the core features of the intervalometer. This way, it isn’t required to pick up the remote and shake the camera while doing so.

The hand gesture sensor we’re trying for this project is a small breakout board based on the PAJ7620, which can detect up to 15 distinct gestures, including the 8 cardinal and diagonal directions (plus forward and back), circular and waving hand movements. We explored this module in more detail back in Issue 32, so check that out if you’re interested.

While the gesture module is fully customisable with Arduino code, as a basic controlling system we plan on implementing two simple gestures – one for a single, immediate photo and one for activating the programmed photo sequence. The problem with adding more gestures control to the system is that it becomes likely a gesture was incorrectly detected and takes unnecessary photos.

Bluetooth Low Energy

The HC-05 is an incredibly popular Bluetooth module compatible with Arduino modules over a very simple serial connection. Its been on the market a while now, however, Jaycar has discontinued the HC-05. While we could get it from several other stores, we wanted to try Jaycar’s new XC4382 Bluetooth Low Energy (or BLE for short) module, the HM-10 as it’s known across the internet. While it may be assumed that BLE should operate largely the same as Bluetooth, there are actually a great number of changes to how it works. As it says on the tin, BLE consumes significantly less energy but more importantly, is used for transmitting very small packets of data and requires little processing overhead to get it working!

Unlike a standard Bluetooth connection, BLE doesn’t stay paired all the time and only communicates when it needs to, sending only the data required for the application. This makes it largely unsuitable for streaming applications like Bluetooth speakers, but perfect for small devices like heartrate monitors, weather sensors, and, you guessed it, our camera controller!

There are a massive variety of different interfaces that are now available for electronics enthusiasts to experiment with, however, we want a small but highly readable display for our controller. We initially tried an 128x128 OLED screen which proved to be quite frustrating. It frequently blacked out and refused to work correctly, and when it did it had a poor refresh rate. This may have been due to the strange interactions with the ESP8266 WiFi processor we first tried to use, or it may have just been plain faulty.

We eventually settled on a 4-digit alphanumeric display and an 8-long bank of LEDs. This way, we can display short words and numeric values, in addition, to graphically showing the progress of the camera controller. For the input, we are aiming to use both a Bluetooth partner app and physical buttons. Keeping it simple, one rotary encoder and a pushbutton should do the trick in terms of navigation.

With the project planned out, it was time to assemble the prototype.

The Prototype:

Parts Required:Jaycar
1 x TPIC6C595 Shift Register-
8 x 5mm Yellow LEDsZD0160
8 x 220Ω Resistors*RR0556
3 x 10kΩ Resistors*RR0596
1 x 1kΩ Resistor*RR0572
2 x 2kΩ Resistors*RR0579
2 x BC547 NPN TransistorsZT2152
2 x 1N4004 Diodes or equivalent*ZR1007
1 x HM-10 Bluetooth ModuleXC4382
1 x Gesture Sensor PAJ7620XC3742
1 x 4-digit Alphanumeric LED BackpackXC3715
1 x Logic Level Shifter ModuleXC4486
1 x Arduino Uno or CompatibleXC4410
2 x 12V SPDT 5A RelaysSY4062
1 x 3.5mm Stereo Chassis SocketPS0132

* Quantity required, may only be sold in packs.

^ This appears to be a standard Bluetooth 4.0 module rather than BLE. You may need to make code modifications if using.

First up, we need to wire the shift register for the LEDs. While there are several different methods for driving LEDs with a limited number of microcontroller pins, we had some TPIC6C595 shift registers on hand. They function almost identically to the standard serial-in-parallel-out SN74HC595 registers that are very common with Arduino kits.

For those who just read that as a random arrangement of numbers and letters, a shift register is a simple chip that converts (in its most basic form) a digital clock line and a digital data line to a set of digital outputs. It essentially allows us to write digital data to three digital pins (DATA, CLOCK and LATCH) and individually change the state of the eight LEDs connected to the chip.

We used the TPIC6C595 in the Racing Dashboard project in Issue 42 & 43 for controlling the large 7-segment display, and we’re using it the same way here. 5V needs to be connected to Pin 1 (VCC) and Ground needs to be connected to Pin 16 (GND). We’re also using a 10kΩ pullup resistor between the CLR pin and 5V to ensure the register actually retains the data we send it!

Also, don’t forget to connect the two ground rails together on the top and bottom side of the breadboard. Since we’re using both a 9V rail AND a 5V rail for this project (9V is required for the relays), we need to ensure that the upper red rail (5V) and the lower rail (9V) are kept isolated, so don’t ever connect them together.

Next up, we can pop in the LEDs for the status bar. The anodes need to be connected to 5V through a resistor, which we’ll talk more about the value of in the next section. It primarily depends on the forward voltage of the LED and how bright you’d like them.

Ok, we’ll admit this isn’t the cleanest wiring in the world, but it does the trick for connecting each LED’s cathode (the flat side) to the TPIC6C595’s outputs in a compact way. There is a bank of four outputs on each side, ranging from pins 3 – 6 and 11 – 14.

We can move on from the TPIC6C595 and work on the transistors that will drive the relay system. Note that normally we use MOSFETs for this type of purpose, however, transistors were better suited to our initial choice of microcontroller, the ESP8266. We were concerned that the lower logic level (3.3V) of the ESP8266 wouldn’t be high enough to fully turn on a MOSFET. The ESP8266 ended up having other communication-based problems that would be too lengthy to list here!

The transistors are basic BC547 NPNs, which will do fine to drive the small amount of current through the relays. Just remember the flyback diode and a 10kΩ current-limiting resistor for the microcontroller pin.

Since the relays we chose were not unfortunately breadboard-spacing compatible, we had to solder on some extension wires to plug them in via a row of headers. Each relay has a set of three headers for the camera side (COM, NC, NO) and two headers for the coil terminals. Be very careful with positioning the headers as one side will have 9V across it, which you definitely do not want to plug into your camera’s shutter port.

This step will vary based on your camera model, however, we used a 3.5mm jack and used alligator clips to connect it to the breadboard for testing. Since our final build uses a 3.5mm jack, you may have to make your own adapter to convert to the shutter port of your camera. On Canon cameras, the lowest sleeve is the ground cable which is connected to the COM connection of both relays. However, don’t connect it to our circuit’s ground as that would prevent any benefits of galvanic isolation.

Next, we need to set up our level shifter and the Bluetooth LE module. Both of these modules have two communication lines. The Bluetooth module has an RX and TX line which we will communicate with a Serial connection, and the level shifter will take an I2C connection with a Data and a Clock line. In the next couple of steps, we’ll add the gesture sensor onto the level shifter.

We need to make some adaptions to step down our data signals from 5V to 3.3V, which is what the level shifter is for – at least for the gesture sensor. The Bluetooth module is 5V tolerant, however, many enthusiasts online recommend a simple voltage divider to drop the RX line down to 3.3V, which helps with ensuring that the module isn’t damaged. This method shouldn’t be used with high-frequency data transmission due to the filtering effect of the resistors and parasitic capacitance, but is effective for simple applications.

Next up, it’s time to connect the four-digit alphanumeric display. This LED layout is commonly seen on microwaves and kitchen appliances and differs slightly from the standard 7-segment displays in that it can display any letter of the alphabet. For example, X, R, Q, Z, W, V and K are all letters that would be impossible to display on a regular 7-segment display due to their diagonal strokes. The HT16K33 chip built into the backpack handles the LED driving for us, so all that is needed is an I2C connection to facilitate driving the display. It is 5V compatible so the data lines can directly connect to the 5V SDA and SCL lines on the Arduino Uno.

We’re now connecting the gesture sensor, which we’re using some jumper wires to extend it away from the breadboard. During testing, placing it on the breadboard with the other components tends to interfere with the gesture sensing so isolating it helps the recognition work better. Again, it’s connected via the level sensor’s 3.3V I2C connection.

Since we’ve finished the breadboard electronics, we can now hook it into our Arduino Uno. You can use pretty much any Arduino-based board for this project, so long as it has enough GPIO pins and storage space. The power wiring simply needs a 5V and Ground cable which is inserted into your breadboard’s main power rails. The 3.3V header from your Arduino also needs to be connected to the LV side of the level shifter and the VCC of the Gesture sensor to provide it with the correct voltage.

We now need to connect all our data wires to the Arduino Uno. This is always a bit of a spaghetti convention when prototyping, so the wiring instructions can be followed with the Fritzing layout or the schematic. This circuitry is simpler than the main build, as we soon plan to add a rotary encoder, power switches, a dedicated 3.3V regulator for the gesture sensor, and additional screw terminals for accessing the trigger outputs and inputs.

Anyhow, there are four main banks of jumper wires that need to be connected:

  • The SDA and SCL I2C lines to the level shifter (i.e. the gesture sensor) and the alphanumeric display (A4 and A5).
  • The SRCK, SCK, and SDATA lines to the TPIC6C595 for the LED progress bar (Pins D10, D11 and D13).
  • The RX and TX lines to the HC-05 Bluetooth LE Module (Pins D8 and D9).
  • The transistor base lines for the shutter and focus relays (Pin D4 and D5).

We loaded up an early version of the Intervalometer code to test the core parts of the project are functioning as expected.

void loop() {
  // put your main code here, to run repeatedly:
  uint8_t data = 0;
  paj7620ReadReg(0x43, 1, &data); 
// Read Bank_0_Reg_0x43/0x44 for gesture result.
  if (data == GES_LEFT_FLAG) {
    writeWord("LEFT");
    alpha4.writeDisplay();
    Serial.println("Left");
  }
  else if (data == GES_RIGHT_FLAG)
  {
    writeWord("RGHT");
    alpha4.writeDisplay();
    Serial.println("Right");
  }
  if((millis() - lastTime) > interval) {
    if(num <= 0) {
      num = 20;
    }
    lastTime = millis();
    writeWord("    ");
    delay(10);
    writeWord((String)num);
    alpha4.writeDisplay();
    num--;
  }
  if((millis() - lastTime) < shutterTime) {
    digitalWrite(4,HIGH);
    digitalWrite(5,HIGH);
  } else {
    digitalWrite(4,LOW);
    digitalWrite(5,LOW);
  }
  RS_6c595_SendData(0xFF >> 
(int)(((millis() - lastTime)/(float)interval)*9));
}

This is the loop function we used to ensure the gesture sensor, LEDs and relays are good to go. The PAJ7620 module operates on an I2C connection and a good library is available to run it. After the register are read, it's just a matter of comparing it to the gesture flags. The camera control itself just runs on a loop, counting down from 20 and clicking on and off the relays each time.

The Main Build:

Additional Parts Required:Jaycar
1 x Vertical Rotary EncoderSR1230
1 x 12x12mm Tactile PushbuttonSP0608
4 x 10mm M3 Screws*HP0403
4 x 20mm M3 Screws*HP0410
8 x 15mm M3 Tapped Spacer*HP0904
3 x 2-way Screw TerminalsHM3130
1 x Switched Audio 3.5mm SocketPS0133
1 x 16mm Brushed Aluminium 1/4" KnobHK7009
1 x ATmega328P MicrocontrollerZZ8727
1 x 16MHz Quartz Crystal Oscillator*Included with above
2 x 22pF Ceramic Capacitors*RC5316
1 x 9V Battery HolderPH9235
1 x 9V BatterySB2423
1 x DIP28 IC SocketPI6510
2 x 1µF Electrolytic CapacitorsRE6032
1 x USB-to-Serial ConverterXC4464
1 x 7805 5V RegulatorZV1505
Cables necessary to connect to your shutter port

* Quantity required, may only be sold in packs.

PCB

We’ve opted to design and order a PCB for the final build of this project, for a few reasons. Since an intervalometer or a camera controller is expected to be as small as possible to slot into a bag, this needs to be compact. Second, a PCB cleans up the electronics and provides more reliable operation. During the fundamental build, the breadboard connections caused some very intermittent performance. This caused a lot of headaches until we realised the ground rail was partially faulty. A PCB should avoid these issues and provide very consistent operation.

We have featured several guides regarding the design of PCBs, so we’re not going to flesh it out here. Refer to the PCB design guide using EAGLE in Issue 34 if you’re interested. The PCB we designed is 130mm x 60mm, so it should fit nicely in the palm and be somewhat operable with one hand.

Before we delve into the build, there were several mistakes that found their way into the ordered PCB, however, we’ve fixed the issues and the components we’ve selected should now slot nicely into the board. So, if you download our Gerber files to order the PCB for yourself, don’t worry if some parts of the PCB look visually different.

To start with, we recommend soldering the flattest components first so they don’t fall out when the board is flipped over. There are several resistors for this build, especially related to the LED bar. Depending on the desired brightness and LED colour, you may have to experiment to decide what LEDs to use. For the brightest yellow LEDs, 150Ω resistors will do the trick, but we used 220Ω simply because of availability and we didn’t mind slightly dimmer LEDs. Keep in mind that brighter LEDs will be better during the day, but substantially more frustrating when taking photos at night due to the glare. You’ll also need to solder in the flyback diodes and the 16MHz crystal for the ATmega328P.

We also highly recommend testing mechanical components before soldering them in! We, unfortunately, discovered the ON/OFF switch we used didn’t actually work and refused to connect the common and upper terminals together.

Next up, we can do the LEDs and terminals on the top of the PCB. While the terminals aren’t essential, they’re a convenient method for connecting our camera controller to external circuits. Note that we’ve actually included three sets of two terminals. Two sets are for the output terminals, (Focus and Shutter) and one set is for an external trigger. This means other circuits can also trigger the intervalometer by simply shorting the connections together. The screw terminals can be slid together with the small dovetail joiners to provide more rigidity as well as making it look a little better too.

Regarding the LEDs, we’ve opted for some nice yellow ones, but it’s totally customisable to pick whatever colour is desired. Just be aware that some colours have different forward voltages so pick your resistors appropriately. We didn’t discuss this during the fundamental build, but both the alphanumeric display and the LED bar are both PWM dimmable. The TPIC6C595 has a G pin that can be driven using a PWM pin to rapidly turn on or off the bar display at a set rate, and the character display has a software command to turn its brightness display. Handy!

The audio jack is Jaycar’s switched 3.5mm PCB mount jack which has a nifty see-through top cover to see the internals. You can also use this jack in other applications to actively switch between signals when a plug is inserted.

Next, we can solder in the main breakout modules. While we could implement many of the components directly onto the main PCB via surface-mount technology, this is not accessible for those getting started in soldering and is very finicky! The main modules on the front are the level shifter and the gesture sensor. For the gesture sensor, we also added a 3mm hole that can be used to support the sensor with M3 nuts and bolts.

This keeps it upright and stops it from ‘flopping’ about. The IC socket for the ATmega328P, buttons and the TPIC6C595 can also be added at this stage. We’re soldering the TPIC6C595 directly into the board above the LEDs as we need as much clearance as possible to mount the alphanumeric display. As long as we don’t blow the chip up, this should work fine (touch wood).

Time to flip the board on its back and pop in the bigger components. The two relays slide into the holes along the bottom of the board and should fit snugly together. The 9V battery holder has two terminal connections on the right side and can also be secured with M2 bolts if more sturdiness is desired. The 7805 5V regulator is also secured to the backside with a M3 bolt.

We also soldered on a six-wide header that enables access to the programming pins on the ATmega328P. To program it, you’ll need a USB-to-Serial converter, however, in a pinch you could always pull out the chip and place it into an Arduino Uno board. Be very careful that the programmer is plugged in with the correct orientation, as the connector is reversible, but the electronics, unfortunately, aren’t.

The electronics are done. We ran some quick test code from the fundamental build and confirmed that everything fired up as expected.

Enclosure

We’re taking a slightly different approach with designing the enclosure for our Intervalometer project. Normally, we would whip out a quick CAD model and throw it on the 3D printer for a couple of hours and out pops a durable, albeit not aesthetically perfect, case.

For this project, we designed a laser-cut faceplate and backplate for the intervalometer, which will sandwich the PCB between the protective acrylic plates. Acrylic doesn’t win any awards for durability or fingerprint resistance, but it certainly does look a treat. It has a sleek, glossy finish and with a sprinkle of engraving, professional looks can be accomplished with minimal effort.

The other reason we opted to go with laser cutting is it will make the LED displays much easier to read. Using a tinted acrylic sheet will reduce the brightness of the displays, however, it will largely block out the unlit LED segments and provide a substantial amount of contrast.

We don’t have a laser cutter in our office, so we outsourced our laser cutting here from a Sydney company called Online Laser Cutting. It a comparable cost as 3D printing, so it’s very accessible to get a custom design cut and shipped to you within a day or two for a price that won’t break the bank.

We used Adobe Illustrator to design the cutouts for the material. If you’re using Illustrator, RGB colour and millimetre measurement settings need to be used, but beyond that, it’s a pretty simple process. Red vector lines (0.1pt) fully cut through the material, blue-coloured lines represent vector engraving (i.e. the laser head follows the line) and black fills tell the cutter to fully engrave the area. Engraving has a different effect on every material, but with acrylic, it provides a cloudy, rough texture - perfect for providing emphasis on logos and text. Sending the .AI file to the laser cutter business will be enough for them to handle the rest.

Once shipped, the acrylic panels come with adhesive covers that should be peeled off as soon as possible. If you wait too long, it’ll be more annoying to peel off. We found that a pair of jewellery tweezers was effective in getting the tiny adhesive bits removed from the centre of the lettering.

Note: Unwritten Laser Cutting Rule #23: All nearby bystanders must stay silent whilst acrylic adhesive backing is peeled satisfyingly.

The sheets themselves ‘sandwich’ the PCB, while allowing the battery to slightly extrude to reduce the thickness of the unit. They’re held in with 15mm M3 couplers with screws inserted from both sides. You may have to use nuts or washers to help get the spacing correct.

Due to some spacing problems, the relays were too wide to fit through the acrylic cut-out, so the acrylic sits further out than we’d like. Regardless, the finish looks great, and the acrylic provides a very sleek aesthetic. It looks more like a commercial electronics kit than a DIY project!

The Code

There are two major components on the software side of this project to get it running properly: the Arduino software and the accompanying Android app. From a software design standpoint, we’re aiming to have all features of the camera intervalometer accessible from the intervalometer itself, but additional control can be found with the accompanying Bluetooth app.

Arduino Program

We've chosen to leave the Arduino code for this project quite open-ended so it's possible to implement plenty of other functionality if desired. Unlike other camera controllers on the market, we've added a quick-select time system that permits easy selection of time increments. For example, instead of selecting individual digits in a 00:00 format, you can move the rotary encoder to quickly move through steps of 1", 3", 5", etc.

However, the hardware in this project is more than capable of being programmed to be very precise with triggering, including additional functionality like focus delays and exposure bracketing. Additional control can be gained through the external trigger port if you'd like to hook it up to external events. Anyway, enough talk! Here's the setup code responsible for the setting up the bulk of the modules on board:

setup() {
  pinMode(VOLTAGE_SENSE, INPUT);
  pinMode(BUTTON_1, INPUT);
  pinMode(BUTTON_2, INPUT);
  pinMode(RS_6c595_DIMMER, OUTPUT);
  alpha4.begin(0x70);
  displayBatteryVoltage();
  alpha4.writeDisplay();
  Serial.begin(9600);
  BTserial.begin(9600);
  uint8_t error = 0;
  delay(1000);
  //Reading the encoder position so we don't 
  //immediately register an encoder movement.
  last_encoder_pos = enc.read();
  pinMode(RELAY_CH1, OUTPUT);
  pinMode(RELAY_CH2, OUTPUT);
  error = paj7620Init(); // initialize Paj7620 registers
  if (error)
  {
    Serial.print("INIT ERROR,CODE:");
    Serial.println(error);
  }
  else
  {
    Serial.println("INIT OK");
  }
... Code Omitted ... }

You can see it's mostly a case of just initialising all the important electronics on board, including pinMode to set the input and output modes and setting the registers for the gesture and alphanumeric display.

The Arduino program has two main modes to its operation; the sequence editor and the sequence player. The sequence editor allows you to use the rotary encoder to select and modify different lengths of time and photo sequences. By rotating the encoder to a menu option, it can be pressed in to enter editing mode. The mode lights then flash and a new value can be entered into the display. Although there are a number of ways to implement this, we opted for the simple method and used a pre-determined table of values to determine each time amount.

unsigned long time_delays[] = {
    250,  // 1/4 second
    500,  // 1/2 second
    1000, // 1 second
    2000, // 2 seconds
// --(array continues)--
    4 * 3.6e6,    // 4 hours
    4.5 * 3.6e6,  // 4.5 hours
    5 * 3.6e6,    // 5 hours
};

To format the durations in a nice friendly way on the screen, we’ve added a converter function that changes the millisecond times into a readable 4-character format:

String getFriendlyDurationName 
  (unsigned long time)
{
  switch (time)  {
  case 0 ... 499:
    return "1/4"";
  case 500 ... 999:
    return "1/2"";
  case 1000 ... 59999:
    return (String)(time / 1000) + """;
  case 60000 ...((60000 * 60) - 1):
    return (String)(time / 60000) + "'";
  case (60000 * 60)...(10 * 60000 * 60):
    return String(time / (float)(3.6e6), 1) + "Hr";
  default:
    return "-";
  }
}

If you’re confused about all the slashes in the code, when using the “ quotation mark in displays, it’s important to use a preceding backslash to escape it. The Arduino compiler’s lexical analyser gets understandably confused with three quotation marks in a single variable, so the backslash tells the compiler to ignore it and just use it in the variable itself.

Right now, we have support from a 1/4 second to 5 hours, however, if this is not enough control, custom code can be written to better suit your application. It’s worth noting there isn’t much point of shorter exposures as the camera’s inbuilt shutter controller will do a better job at that speed, so we’ve only provided a quarter of a second just to trigger the camera.

The code is quite long, so you can find the rest in the project files on our website.

The sequence player is the other part of the code and is responsible for timing and actuating the relays. To do this, we’ve written a separate C++ class called Sequence that handles its own data and methods. When pressing the white ‘Start’ button, the code converts the selected values into a Sequence object which both holds timing data and has its own functions.

Note: Comments in the following code have been removed, please see code in Digital Resources for comments.

#ifndef SEQUENCE
#define SEQUENCE
class Sequence {
    public:
        Sequence();
        unsigned long delay;
        unsigned long exposure;
        unsigned long count;
        unsigned long interval;
        void start(unsigned long);
        bool getStatus(unsigned long);
        bool getCompletedStatus();
        int getLights(unsigned long);
        int getNum(unsigned long);
    private:
        bool completed = false;
        unsigned long startTime = 0;
};
#endif

It might seem a little over-engineered to create a whole class for this purpose, but there are a couple of reasons why we opted to go this route. First, it allows future expansion with multiple Sequence instances. Presets and save-files can be created so the user does not have to re-enter commonly used photo sequences after the Intervalometer is powered off.

Second, it provides a very compact way of handling the data associated with timing. Since it’s a single variable in the main class, it can be passed around as a variable to manage data in a clean way. Finally, we can also serialise and deserialise these sequence objects over Bluetooth to transmit data from the Android app if we need to. Awesome!

Android App

When deciding on a development platform for this app, various systems were considered to strike a balance between a customised experience and minimal-fuss programming.

We first tried developing an Android Studio app to implement a custom Bluetooth Low Energy controller. While we did manage to get some functionality working, it was very buggy and tended to crash frequently. There is a lot of backend programming required to get the Bluetooth Low Energy attributes and service functionality implemented. Some more tinkering may have made the app better, but unfortunately time prohibited the development of the app so we eventually settled on using the Blynk service.

Anybody who's dabbled with IoT embedded systems will have heard of this platform, but for readers who haven't, it's essentially a drag-and-drop system for creating polished mobile apps with IoT integration.

The mention of 'Drag and drop' may instantly turn off some from the platform, but it is a seriously powerful bit of kit that makes prototyping projects look professional.

The great thing about the platform is that it's as simple as importing the Blynk libraries into your Arduino Code and popping in your Blynk API key. Then, just design the app by dragging and dropping UI elements into the interface.

You can connect the value of data inputs to virtual or physical pins on your microcontroller with a very simple dropdown menu in the app.

Then, the corresponding code in your Arduino program looks like this:

BLYNK_WRITE(V2)
{
  unsigned long interval = param[0].asLong() * 1000;
  ble_seq.interval = interval;
}

We added code for controlling all Intervalometer functionalities over Bluetooth, including some extra features like controlling display brightness and enabling or disabling the gesture sensor. We did have some problems getting Blynk working smoothly with Bluetooth LE, most likely due to the prototype implementation of BLE within Blynk. On startup, the intervalometer tends to hang and refuse to do any further actions until it's connected properly. To fix this, we added a Bluetooth enable feature that would start Blynk and its communication functions when both middle buttons are pressed:

if(digitalRead(BUTTON_1) && digitalRead(BUTTON_2) && !use_ble) {
    writeWord(" BT ");
    alpha4.writeDisplay();
    delay(800);
    alpha4.clear();
    use_ble = true;
    Blynk.begin(BTserial, auth);
  }

Where To From Here?

While we’re happy with the finished project, there are a number of changes we could make to really refine the electronics.

First up, it probably needs to cut back on the carbs considering that the project is looking fairly thick. Most of the size comes from the 9V battery and the relays considering that not much space is utilised on the rear of the PCB. Unfortunately, this is the primary limitation of through-hole boards as multiple components are difficult to place on directly opposing sides of the board without causing spacing problems. We’d love to see (and are considering ourselves) a redesigned PCB with SMD components that should have a significantly reduced footprint. Reducing the use of the breakout boards and instead directly soldering the core components onto the main PCB would also reduce thickness.

Besides the physical construction of the project, several electronic improvements would also be super interesting to investigate. We often use 5V 7805 regulators and a 9V battery in these projects due to the simplicity of implementation – which is OK for low-power projects like this. However, the 7805 regulator becomes more inefficient as higher battery voltages are supplied. We’re now investigating using Li-ion 18650 batteries (the same batteries used in electric cars and laptops) and regulation circuitry to provide efficient and rechargeable power to future projects.

Liam Davies

Liam Davies

DIYODE Staff Writer