Open Arduino

Enter Your Project for a chance to win a grand prize for the most innovative use of Arduino or a $200 shopping cart! The Birthday Special: Arduino Projects for Arduino Day!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll

 

board

The basic idea was to create IR intervalometer for my Nikon DSLR. I have found in network information about captured raw signal from existing Nikon ML-L3 remote control. So, I have decided to use this information and Arduino Uno to create IR time-lapse intervalometer device for Nikon DSLR. Original RAW IR signal is modulated with 38kHz frequency and have following timings:

- 2.0 ms - on

- 28.0  ms - off

- 0.5 ms - on

- 1.5 ms - off

- 0.5 ms - on

- 3.5 ms - off

- 0.5 ms - on

- 63.5 ms - off

 

First step was to create a shield for arduino with support for IR LED and one button. IR diode is driven by NPN transistor to achieve 35 mA of current and larger distance for control. Button it pulled-up to 5 volt. Here is schematic:

schematic

Second step was to create program. Value of current interval for time-lapse is stored in EEPROM and it is possible to update it by USB serial by sending command:

- setInterval:12345 (five digit value of interval in seconds). I have used two libraries:

- first for button debouncing. Here is library source: https://github.com/thomasfredericks/Bounce2

- second for driving IR LED. Here is library source: https://github.com/z3t0/Arduino-IRremote

ide

Here is flow diagram for program:

flow

Source code is also available in attachment.

/*
   Basic IR intervalometer for Nikon DSLC cameras
   by kk99
   2018
*/

#include 
#include 
#include 

IRsend irSend;
Bounce debouncer = Bounce();

const int BUTTON_PIN = 2;
const unsigned long DEFAULT_TIMELAPSE_INTERVAL_SEC = 5;
const int EEPROM_ADDRESS = 0;
bool isWorkingMode = false;
bool requestNextPhoto = false;
bool isUpdateTimelapseInterval = false;
unsigned int timelapseIntervalValueToUpdate = 0;
unsigned long timelapseIntervalMs = 0;
unsigned long lastPhotoTime = 0;

unsigned long getTimelapseInterval(void)
{
  unsigned long timelapseIntervalVal = 0;
  EEPROM.get(EEPROM_ADDRESS, timelapseIntervalVal);
  return timelapseIntervalVal;
}

void setTimelapseInterval(unsigned long timelapseIntervalVal)
{
  EEPROM.put(EEPROM_ADDRESS, timelapseIntervalVal);
}

void takePhoto(void)
{
  // modulation frequency in kilohertz
  int frequency = 38;
  // signal for take a photo by Nikon DSLR
  unsigned int irSignal[] = {2000, 28000, 500, 1500, 500, 3500, 500, 63500};
  irSend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), frequency);
}

void workingModeLED(bool on)
{
  if (on) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void setup() {
  // initialize serial communication
  Serial.begin(9600);
  // initialize digital pin for builtin status LED as an output
  pinMode(LED_BUILTIN, OUTPUT);
  workingModeLED(false);

  // initialize digital pin for button as an input
  pinMode(BUTTON_PIN, INPUT);
  // setup button debouncer
  debouncer.attach(BUTTON_PIN);
  debouncer.interval(50);

  // read timelapse interval in seconds
  unsigned long tempTimelapseIntervalVal = getTimelapseInterval();
  if (tempTimelapseIntervalVal == 0) {
    Serial.println("Restored default value of time-lapse interval");
    tempTimelapseIntervalVal = DEFAULT_TIMELAPSE_INTERVAL_SEC;
    setTimelapseInterval(tempTimelapseIntervalVal);
  }
  timelapseIntervalMs = tempTimelapseIntervalVal * 1000;
  Serial.println("Intervalometer initialized");
}

void loop() {
  // update time
  unsigned long timestamp = millis();

  // check button state
  debouncer.update();
  bool buttonState = debouncer.fell();
  if (buttonState) {
    isWorkingMode = !isWorkingMode;
  }

  // update status LED
  workingModeLED(isWorkingMode);

  if (isWorkingMode) {
    // check timelapse interval
    if (requestNextPhoto) {
      unsigned long diffMs = timestamp - lastPhotoTime;
      if (diffMs > timelapseIntervalMs) {
        requestNextPhoto = false;
      }
    }

    // take a photo
    if (!requestNextPhoto) {
      Serial.println("Captured picture");
      takePhoto();
      requestNextPhoto = true;
      lastPhotoTime = timestamp;
    }
  } else {
    requestNextPhoto = false;
    lastPhotoTime = 0;
    if (isUpdateTimelapseInterval) {
      unsigned long currentTimelapseInterval = timelapseIntervalMs / 1000;
      if (currentTimelapseInterval != timelapseIntervalValueToUpdate) {
        setTimelapseInterval(timelapseIntervalValueToUpdate);
        timelapseIntervalMs = timelapseIntervalValueToUpdate * 1000;
        Serial.println("Updated value of time-lapse interval");
      }
      isUpdateTimelapseInterval = false;
    }
  }
}

void serialEvent() {
  if (isUpdateTimelapseInterval) {
    return;
  }

  const int dataLength = 18;
  if (Serial.available() < dataLength - 1) {
    return;
  }

  int i = 0;
  char receivedData[dataLength] = { 0 };
  while (Serial.available() > 0) {
    char character = Serial.read();
    if (i < dataLength - 1) {
      receivedData[i] = character;
    }
    i++;
  }

  char *data = strstr(receivedData, "setInterval:");
  if (data) {
    data += 12;
    int timelapseIntervalVal = atoi(data);
    if (timelapseIntervalVal > 0) {
      Serial.println("Got new value of time-lapse interval in seconds:");
      Serial.println(timelapseIntervalVal);
      isUpdateTimelapseInterval = true;
      timelapseIntervalValueToUpdate = timelapseIntervalVal;
    }
  }
}

Here is example video of remote controlling of Nikon DSLR: