This project provides a complete hardware and software solution for capturing "holy grail" timelapses—such as sunrises or sunsets—where the ambient light changes dramatically. It uses an Arduino to programmatically control a DSLR's shutter, adjusting the exposure time with a non-linear curve to produce smooth, flicker-free results.
The final hardware: (1) Arduino, (2) Shutter release circuit, (3) 2.5mm TRS port adapter, (4) 2.5mm shutter cable, (5) Interface, (6) 7-segment display
Standard camera modes are not suitable for this task.
- Manual Mode is static and does not adapt to the changing light, leading to under or over-exposed footage.
- Automatic Exposure (AE) Mode (like Aperture Priority) introduces "flicker" as the camera's meter makes slight adjustments between shots.
Manual Mode (left) vs. AE Mode Flicker (right)
The key challenge is that ambient light during a sunrise or sunset does not change linearly. It follows a logistic curve, changing slowly at the extremes (full day/night) and very rapidly during the transition.
Ambient brightness curve (left) and the required complimentary shutter speed curve (right).
To achieve a perfectly smooth timelapse, this project implements a custom, complimentary shutter speed curve. It also calculates a dynamic interval (the pause between shots) to ensure the final video plays back at a smooth, consistent perceived speed.
Commercial intervalometers that offer exposure ramping typically only use linear interpolation, which is insufficient for this non-linear problem.
The project is split into two parts:
- Python Script (
calculate.py
): A Python script that does the heavy lifting. You configure your desired parameters (e.g., number of frames, start/end shutter speeds), and it calculates the precise, non-linear shutter durations and inter-shot pauses. It then generates Arduino-ready C++ code. - Arduino Sketch (
shutter_controller.ino
): A simple sketch that reads the timing arrays generated by the Python script. It triggers the camera's shutter via a basic circuit, executing the pre-calculated sequence perfectly.
Follow these steps to create your own custom timelapse sequence.
Open the calculate.py
file. At the top of the script, you can edit the core parameters for your timelapse:
# --- Core Parameters ---
num_frames = 240 # The total number of photos to take
# --- Calculate Shutter and Pause Durations ---
# Shutter speeds (in ms) increase from fast (day) to slow (night)
shutters = times100(100, 180000, num_frames) # (start_speed, end_speed, frames)
# Pause times (in ms) decrease as light changes faster
pauses = times100(120000, 1000, num_frames - 1) # (start_pause, end_pause, frames-1)
Execute the script from your terminal:
python calculate.py
The script will run the analysis, display the plots for your sequence, and most importantly, print a block of C++ code to the terminal.
Copy the entire C++ code block from your terminal output. It will look like this:
// --- COPY AND PASTE THESE LINES INTO YOUR ARDUINO SKETCH ---
// Automatically generated for 240 frames.
const unsigned long shutterListMS[] = {100, 200, 200, ...};
const unsigned long pauseListMS[] = {120000, 117700, 115300, ...};
// --- END OF ARDUINO CODE BLOCK ---
Open the shutter_controller.ino
sketch in the Arduino IDE. Paste the copied code, replacing the existing shutterListMS
and pauseListMS
arrays.
- Upload the updated sketch to your Arduino.
- Connect the Arduino to your camera's shutter release port using the circuit.
- Set your camera to Bulb (B) mode. This allows the Arduino to control the exposure time completely.
- Power on the Arduino. It will wait for the initial pause (
initialPauseMS
) and then begin the capture sequence.
The shutter release circuit is very simple and uses an optocoupler to safely trigger the camera without a direct electrical connection.
- Arduino (any model, e.g., Uno, Nano)
- PC817 Optocoupler (or similar)
- 220Ω Resistor
- 2.5mm TRS (stereo) jack or cable to connect to the camera
- (Optional) 7-segment display for frame count feedback