A Wee Scottish Game Studio

Work has been getting in the way of hacking for the last week or...

Adjusting the IR Signal

Just a quick post. The weather has continued to be miserable, so I’ve not...

Making it Tick

Today I’d hoped to go out and create a time lapse video with my...

Time Lapses

Work has been getting in the way of hacking for the last week or so and I’ve still not had chance to get out with the camera. Hopefully this weekend.

The main programming challenge for the intervalometer was getting a simple menu working with just 2 buttons and a 16×2 character LCD. I’ve already said that with hindsight I’d go for a 3-button interface, so I’m not going to go into great detail about how this works.

The next problem came when I had built the circuit into a box and tried using it with the camera. While testing it had been a bit unreliable, but I put that down to odd angles, clutter on the desk, wishful thinking, whatever… However, once in the box I soon discovered that it was just unreliable. I suspected that the IR signal was inaccurate but how to tell. By this time I’d bought a second arduino, this time a Mega ADK (Android fun coming soon). So I added an IR detector and using the code from the tutorial  on www.ladyada.net I could see the on off times of the Nikon remote control and my intervalometer. There were a few discrepancies and some fiddling with values got my signal much closer. If you compare my code from the previous post to that in the tutorial you can see the changes.

There isn’t an error in the original code, and its values should work in theory. However in practice it looks tolerances in the clock speed of the arduino means that the arduino Delay() ad Milli() functions are not accurate. So if you follow this design you will also need to adjust  the timings to get reliable firing of the shutter. So you may also need 2 arduinos to get this working.

My next project is underway. It will be a robot arm using 7 servos. At this point I’m cutting parts from 4mm acrylic using a CNC mill, unfortunately my attempt t prepare files for the CNC machine with Open Source softare has failed and I have reverted to using a well known CAD program and a commercial CAM program I have been using for a couple of years.

I’m also think about other uses for the intervalometer. For example attaching a motion detector, or sound detector could allow me to set up to do some wildlife photography, or just caputure people entering and leaving a building. I’d love to hear other suggestions of what could be done with a camera and an automated IR remote control shutter.

On the plus side my Ubunto machine upgraded to 11.10 Oneiric Ocelot this week without a hitch and just one restart. That’s not something I’ve ever been able to say about upgrading Windows!

Posted by Mike with No Comments

Just a quick post. The weather has continued to be miserable, so I’ve not had chance to use the intervalometer. So onto the source code:

/*
Nikon D5000 Controller

 */

// include the library code:
#include <LiquidCrystal.h> 

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int IRledPin = 9;                // assign the Infrared emitter/ diode
                                 //  to pin 13
int exposureInterval = 2000;       // default exposure interval
int exposureLength = 10000;       // default exposure length
int Btn1 = 7;                      // Up button
int Btn2 = 6;                      // Down button
int menuoption = 1;                // Start of menu system
int runOption = 0;                 // 0 Stopped, 1 Time Lapse, 2 ...
int exitmenu = 0;                  // ready to exit the menu and start
                                   //  running
int Btn1State;                    // the Up Button 1 reading
int lastBtn1State = LOW;          // the previous Button 1 reading
int Btn2State;                    // the Down Button 2 reading
int lastBtn2State = LOW;          // the previous Button 2 reading

int days, hours, mins, secs;      // For formatting times
int fractime;                     // Fractions of a second

void setup() {
  pinMode(IRledPin, OUTPUT);    // Infra red remote control led
  pinMode(Btn1, INPUT);      // UI Button
  pinMode(Btn2, INPUT);   // UI Button 2

  Serial.begin(9600); //debug only remove from final

  lcd.begin(16, 2);             // set up the LCD's number of rows and
                                //columns:
  splashScreen();
}

void splashScreen() {
  lcd.clear();
  lcd.print("Nikon Control"); // Print a message to the LCD.
  lcd.setCursor(0, 1);        // Next line
  lcd.print("Press both btns");    

}

// argument is time in milliseconds
void print_time(int t_milli)
{
  char buffer[16];                  //buffer for printing interval
  int inttime;

  inttime = t_milli / 1000;     // inttime is the total number of
                                // number of seconds
  fractime = t_milli % 1000;     // fractimeis the number of
                                 //thousandths of a second

  // number of days is total number of seconds divided by 24 divided
  // by 3600
  days = inttime / (24 * 3600);
  inttime = inttime % (24 * 3600);

  // Now, inttime is the remainder after subtracting the number of
  // seconds in the number of days
  hours = inttime / 3600;
  inttime = inttime % 3600;

  // Now, inttime is the remainder after subtracting the number of
  // seconds in the number of days and hours
  mins = inttime / 60;
  inttime = inttime % 60;

  // Now inttime is the number of seconds left after subtracting the
  // number in the number of days, hours and minutes. In other words,
  // it is the number of seconds.
  secs = inttime;

  // Don't bother to print days and hours
  sprintf(buffer, "%02d:%02d.%03d", mins, secs, fractime);
  lcd.print(buffer);
}

// This procedure sends a 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to
// send codes
void pulseIR(long microsecs) {
  // Count down from the number of microseconds we are told to wait

  cli();  // this turns off any background interrupts

  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
    digitalWrite(IRledPin, HIGH);  // takes about 3 microseconds
    delayMicroseconds(10);         // hang out for 10 microseconds
    digitalWrite(IRledPin, LOW);   // Also takes about 3 microseconds
    delayMicroseconds(10);         // hang out for 10 microseconds

    // so 26 microseconds altogether
    microsecs -= 26;
  }

  sei();  // this turns them back on
}

void SendNikonCode() {
  // This is the code for Nikon D5000 etc

 pulseIR(1650);
  delay(27);
  pulseIR(362);
  delayMicroseconds(1500);
  pulseIR(362);
  delayMicroseconds(3440);
  pulseIR(362);
  delay(63); // wait 65 milliseconds before sending it again

  pulseIR(1650);
  delay(27);
  pulseIR(362);
  delayMicroseconds(1500);
  pulseIR(362);
  delayMicroseconds(3440);
  pulseIR(362);

}

boolean debounce(int button, boolean last)
{
  boolean current = digitalRead(button);
  if (last != current)
  {
    delay(5);
    current = digitalRead(button);
  }
  return current;
}

void setExposureInterval() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Set Period"); // Print a message to the LCD.

  while (debounce(Btn1, lastBtn1State) == HIGH && debounce(Btn2,
                                            lastBtn2State) == HIGH) {
  } //Wait for let go

  while (exitmenu == 0) {
    if (debounce(Btn1, lastBtn1State) == HIGH && debounce(Btn2,
                       lastBtn2State) == HIGH) { //Exit menu and start
      exitmenu = 1;
    }
    lcd.setCursor(0, 1);
    print_time(exposureInterval);
    while (debounce(Btn1, lastBtn1State) == HIGH && debounce(Btn2,
                                           lastBtn2State) == HIGH) {
    } //Wait for let go
    delay(200);
    if (debounce(Btn1, lastBtn1State)) {
      exposureInterval = exposureInterval + 250;
    }
    if (debounce(Btn2, lastBtn2State) == HIGH &&
                                            exposureInterval > 250) {
      exposureInterval = exposureInterval - 250;
    }    
  }
  exitmenu = 0;
  lcd.clear();
  lcd.print("Time Lapse: Up  ");    
  lcd.setCursor(0, 1);        // Next line
  lcd.print("Long Exp:   Down");    

  while (exitmenu == 0) {
    if (debounce(Btn1, lastBtn1State) == HIGH) {  //Time Lapse    
      runOption = 1;
      exitmenu = 1;
    }
    if (debounce(Btn2, lastBtn2State) == HIGH) {  //Long Exposure     
      runOption = 2;
      exitmenu = 1;
    }
  }
}

void runTimeLapse() {          //Make the exposure at the set interval
  Serial.println("Exposure");
  SendNikonCode();                 // take the picture
  unsigned long currentMillis = millis();
  unsigned long endMillis = currentMillis + exposureInterval;
  while (currentMillis < endMillis) {   // delay in milliseconds which
                                        // allows us to do timelapse
    if (debounce(Btn2, lastBtn2State) == HIGH) { //Stop the time lapse
      runOption = 0;
      exitmenu = 0;
      splashScreen();
    }
    currentMillis = millis();          // Getting closer
  }
}

void longExposure() {
  SendNikonCode();                 // take the picture
  delay(exposureInterval);         // No need to 'interrupt', so delay
                                   // OK
  SendNikonCode();                 // take the picture
}

void showMenu() {
  if (debounce(Btn1, lastBtn1State) == HIGH && debounce(Btn2,
                                       lastBtn2State) == HIGH) {
    setExposureInterval();
  }    
}

void loop() {
  char buffer[16];  //buffer for building display string
  showMenu();       // Back to set interval

  // Option 1 is for time lapse
  if (runOption == 1) {
    lcd.clear();
    sprintf(buffer, "Int: %02d:%02d.%03d", mins, secs, fractime);
    lcd.print(buffer);
    lcd.setCursor(0, 1);         // Next line             
    lcd.print("Down To Stop    ");    
  }

  while (runOption == 1) {
    runTimeLapse();
  }

  // Option 2 is for long exposure on Bulb setting
  if (runOption == 2 ) {
    lcd.clear();               
    sprintf(buffer, "Exp: %02d:%02d.%03d", mins, secs, fractime);
    lcd.print(buffer);
    lcd.setCursor(0, 1);         // Next line               
    sprintf(buffer, "Up To Start     ");
    lcd.print(buffer);
  }

  while (runOption == 2) {

    if (debounce(Btn1, lastBtn1State) == HIGH) { //make the exposure
      lcd.setCursor(0, 1);
      lcd.print("Running...      ");
      longExposure();
      runOption = 0;    // Done so back to waiting for two buttons
      exitmenu = 0;
      splashScreen();
    }
  }
}

Now this is not all my own code. I found help for the InfraRed control from the excellent tutorial here on www.ladyada.net. I’ll go into this code in more detail in a future post, as it didn’t quite work out of the box. The print_time function came from a digital clock project, which for the moment I can’t find. When I do, I’ll post the details.

There are quite a few examples of using an Arduino to control Nikon IR, but none I found went as far as making it a useful tool. They would allow you to set one interval when you programmed the device, then you’d have to reprogram to get a different interval. So a large part of my code is driving a display to provide a menu and set the interval. I decided to go for a two-button interface, with hindsight three buttons would have been much easier. I also discovered that the same control could be used to start and stop a long exposure in Bulb mode so I incorporated that.

Next time I’ll  go through the code and explain what it’s doing.

Posted by Mike with 2 Comments

Today I’d hoped to go out and create a time lapse video with my intervalometer, but this being Scotland it’s raining and the sky is a uniform grey. So a good opportunity to go over the intervalometer design.

The circuit is very simple, most of the details can be cobbled together using the examples on the Arduino website. So this morning I’ve been playing with an Open Source drafting tool to draw a circuit diagram. Fritzing is provided by the Interaction Design Lab of the University of Applied Sciences Potsdam. I just set about drawing my circuit and learning Fritzing along the way. The result is not pretty, but it will do. That is no fault of Fritzing! For my next project I’ll spend some time learning how to use it properly.

Intervalometer Circuit Diagram

Intervalometer Circuit Diagram

Now this is far from perfect, but that’s what happens when you don’t RTFM. To get the circuit diagram into the post I used GIMP for the first time, the open source graphics tool. The UI is very unfamiliar, but I managed to crop the export from Fritzing. When it comes to processing the images from the camera I’ll need to get a lot more familiar with GIMP. It looks very different to Photoshop!

For this project I source my components from Ebay. A bag of 5 IR LEDS for about £1.00, the 16×2 LCD panel for £2.95, two panel momentary pushbuttons for £2.95, a bag of 5 trimmer potentiometers for about £1,  and a clone Arduino Nano board for £11.00. All prices including postage.

I built the circuit first on a breadboard then, once I had the code working, moved it to a piece of veroboard and mounted the whole lot in a small plastic box I got from Farnell.

Next time I’ll post and explain the code I’m using now and how I got there.

Just spotted a small error in the circuit diagram, R6 should be 10k Ohm the same as the pull down on the other switch.

Posted by Mike with 1 Comment

Recently while trying to find bits of the Internet that I’d missed I found Arduino. A simple to program micro-controller with some great community contributions. It’s open source hardware. I soon got an idea for a project and set to. I’d make an intervalometer for my Nikon D5000 DSLR camera. The D5000 in common with a few Nikon DSLRs has an infra-red remote control to fire the shutter. I’d build an infrared remote control and a timer to fire it at preset intervals so I could do time lapse photography. This project is now complete and I hope to create a video very soon to upload here.

But that was just the start. I decided to give myself a further challenge. I may pay for a few electronic components, but all the software I’ll use with my projects will be free, open source. So far I’ve changed from Windows 7 to the Ubunto 11.04 Linux distribution and I’m developing Arduino code on using the open source Arduino IDE. But the challenge is about to begin. No more Photoshop, or Windows tools to process photographs and create the video.

Posted by Mike with 1 Comment