Intervalometer: Arduino + old(ish) Canon digicam

I built an intervalometer circuit to take time lapse sequences, and rigged a Canon A75 for remote control so I don't have to use an SLR.

I thought I'd share and see if anybody has ideas for mounting (other than stuffing it in a clear Pelican case), sorry for the first blurry shot:

The program has two modes, toggled by the button:

  • Running: camera triggered periodically, LCD (backlight off) counts down to each shot, displaying camera status during each shot,
  • Stopped: lcd backlight turns on and the dial adjusts the period between shots.

The system consists of:

  • iDuino running (program to be posted in a few minutes...),
  • Interface:
  • 16x2 serial LCD,
  • Dial (10k pot),
  • Button,
  • LED for blinken,- Pololu 5V power source,
  • Modified Canon PowerShot A75:
  • Power button leads,
  • Shutter, half shutter, and ground leads with 2.5mm jack.

Soldering leads to the A75 was pretty easy, and I've noticed that some newer Canons have lots of test pads for easier hacking servicing...:wink:

/*
*  Adjustable intervalometer for my hacked Canon A75
*/

int camPowerPin = 5;     // pin to short power on/off lines
int halfPin = 11;        // pin to trigger half shutter
int shutterPin = 10;     // pin to trigger the shutter
int camPowerPinTime = 1000;  // time to hold down power pin
int halfPinTime = 500;      // time to hold down the hald shutter
int shutterPinTime = 2500;  // time of hold down the shutter
long camPowerOnMax = 15000;  // if period is this or longer, camera will power cycle 
int potPin = 0;          // pin for analog read of potentiometer to determine period
int goPin = 4;           // pin for the start/stop button
int isRunning = 0;       // status of whether or not the system is running
int i;
long j;
int ledPin = 13;
long delayMs = 500;      // delay between shots, in ms
long lastShutter = 0;
long periods[13] = {  5000, 7000, 10000, 15000, 30000, 45000, 60000, 120000, 300000, 600000, 900000, 1800000, 3600000 };
//                     5s    7s    10s   15s     30s    45s    1min  2min     5min   10min   15min    30min    1hr
int numPeriods = 13;     // number of periods to choose from
int potVal = 0;
int goVal = 0;

//debounce
long time = 0;         // the last time the output pin was toggled
long debounce = 500;   // the debounce time, increase if the output flickers
int previous = 0;

void setup()
{
  Serial.begin(4800);
  serLcdStartup();
  delay(500);
  backlightLevel(25);
  pinMode(camPowerPin, OUTPUT);
  pinMode(halfPin, OUTPUT);
  pinMode(shutterPin, OUTPUT);
  digitalWrite(camPowerPin, LOW);
  digitalWrite(halfPin, LOW);
  digitalWrite(shutterPin, LOW);
  pinMode(ledPin, OUTPUT);
  pinMode(potPin, INPUT);
  pinMode(goPin, INPUT);
  lastShutter = millis();
  delay(1000);
}

void loop(){
  // Debounce start/stop button and toggle the mode and backlight
  goVal = digitalRead(goPin);
  if (goVal == HIGH && previous == LOW && millis() - time > debounce) {
    if (isRunning == 0) {
      isRunning = 1;
      backlightLevel(0);
      delay(50);
      lastShutter = 2000 + millis() - delayMs;
    }
    else {
      isRunning = 0;
      backlightLevel(25);
      delay(50);
    }
    time = millis();
  }
  previous = goVal;


  // If we're running...
  if (isRunning == 1) {
    // See if it's time to take a shot
    if ( (millis() - lastShutter) >= delayMs ) {
      lastShutter = millis();
      if (delayMs >= camPowerOnMax) {
        gotoLineTwo();
        Serial.print("A75 ON...    ");
        toggleCamPower();      
      }  
      gotoLineTwo();
      Serial.print("Half shutter... ");
      halfShutter();
      gotoLineTwo();
      Serial.print(" ** SHUTTER **  ");
      shutterRelease();
      if (delayMs >= camPowerOnMax) {
        gotoLineTwo();
        Serial.print("A75 OFF...      ");
        delay(1000);
        toggleCamPower();      
      }
      reportPeriod( delayMs );
    }
  }

  // If we're stopped
  if (isRunning == 0) {
    // Figure out delay from the input pot
    potVal = 1023-analogRead(potPin);              // read value from the pot
    for (int i=0; i<numPeriods; i++) {
      if ( (1024*i)/numPeriods < potVal && (1024*(i+1))/numPeriods >= potVal ) delayMs = periods[i];
    }  
    reportPeriod( delayMs );
  }

  // Report the status on the second line
  gotoLineTwo();
  if (isRunning == 1) {
    Serial.print("   ");
    j = (delayMs - (millis() - lastShutter))/1000;
    Serial.print( j );
    Serial.print("s to go...");
  }
  else if (isRunning == 0) Serial.print(" ** STOPPED **  ");

  delay(50);  // just a little breathing room...
}





void reportPeriod( long periodMs ) {
  // Report the delay period
  gotoLineOne();
  Serial.print("  Period: ");
  if (periodMs < 1000)  {
    Serial.print(periodMs);
    Serial.print("ms  ");
  }      
  else if (periodMs < 60000)  {
    j = periodMs/1000;
    Serial.print(j);
    Serial.print("s    ");
  }      
  else if (periodMs < 3600000) {
    j = periodMs/60000;
    Serial.print(j);
    Serial.print("min  ");
  }
  else  {
    j = periodMs/3600000;
    Serial.print(j);
    Serial.print("hr   ");
  }
}

void toggleCamPower(){
  digitalWrite(camPowerPin, HIGH);
  digitalWrite(ledPin, HIGH);
  delay(camPowerPinTime);
  digitalWrite(camPowerPin, LOW);
  digitalWrite(ledPin, LOW);
}

void halfShutter(){
  digitalWrite(halfPin, HIGH);
  delay(halfPinTime);
  digitalWrite(halfPin, LOW);
}

void shutterRelease(){
  digitalWrite(shutterPin, HIGH);
  delay(shutterPinTime);
  digitalWrite(shutterPin, LOW);
}

(didn't fit in the last post-- just the serialLCD functions)

// LCD functions
void serLcdStartup() { delay(100); clearLCD(); delay(100); displayOff(); delay(100); displayOn(); delay(100); clearLCD(); delay(100);}
void scmd(){ Serial.print(0xFE, BYTE); }  // command code
void displayOn(){ scmd(); Serial.print(0x0C, BYTE); }
void displayOff(){ scmd(); Serial.print(0x08, BYTE); }
void clearLCD(){ scmd(); Serial.print(0x01, BYTE); }
// Cursor positioning
void gotoLineOne(){ gotoLineOnePos(0); }
void gotoLineOnePos(int pos){ scmd(); Serial.print(128+pos, BYTE); }
void gotoLineOnePosClear(int pos, int digits){ gotoLineOnePos(pos);
  while ( digits > 0) { Serial.print(" "); digits--; } gotoLineOnePos(pos); }
void gotoLineTwo(){ gotoLineTwoPos(0); }
void gotoLineTwoPos(int pos){ gotoLineOnePos(pos+64); }
void gotoLineTwoPosClear(int pos, int digits){ gotoLineOnePosClear(pos+64, digits); }
void cursorRight(){ scmd(); Serial.print(0x14, BYTE); }
void cursorLeft(){ scmd(); Serial.print(0x10, BYTE); }
void cursorRightX(int x){ int c; for (c=1; c<=x; c++){ cursorRight(); } }
void cursorLeftX(int x){ int c; for (c=1; c<=x; c++){ cursorLeft(); } }
// Scroll text
void scrollRight(){ scmd(); Serial.print(0x1C, BYTE); }
void scrollLeft(){ scmd(); Serial.print(0x18, BYTE); }
// Cursor display
void ulCursorOn(){ scmd(); Serial.print(0x0E, BYTE); }
void ulCursorOff(){ displayOn(); }
void bbCursorOn(){  scmd(); Serial.print(0x0D, BYTE); }
void bbCursorOff(){ displayOn(); }
// Backlight
void blcmd(){ Serial.print(0x7C, BYTE); }  
void backlightLevel(int level) {  // set the backlight to the level 0-
  if (level > 29) { level = 29; }
  blcmd(); Serial.print(128+level, BYTE); }
void backlightOn(){ backlightLevel(30); }
void backlightOff(){ backlightLevel(0); }
// Splash screen
void toggleSplash() { blcmd; Serial.print(0x09, BYTE); }
void setSplash() { blcmd; Serial.print(0x0A, BYTE); }
// Serial rate changing: MAKE SURE TO RESTART WITH THE RIGHT BAUD RATE!!!
void set2400baud(){ blcmd(); delay(100); Serial.print(0x0B, BYTE); }
void set4800baud(){ blcmd(); delay(100); Serial.print(0x0C, BYTE); }
void set9600baud(){ blcmd(); delay(100); Serial.print(0x0D, BYTE); }
void set14400baud(){ blcmd(); delay(100); Serial.print(0x0E, BYTE); }
void set19200baud(){ blcmd(); delay(100); Serial.print(0x0F, BYTE); }
void set38400baud(){ blcmd(); delay(100); Serial.print(0x10, BYTE); }

Nicely done! I'm fascinated by arduino-camera interfaces. Thanks for sharing :slight_smile:

I wonder if your sketch will suffer from the millis overflow problem when running for more than 9.5 hours. Time calculation using millis give incorrect values when millis reaches 34,359,739ms, but there are a number of solutions to this that you can find in this forum.

One solution that minimizes changes to your code is to reset the count before it overflows. In your application you could reset the value every time you fire the shutter.
Here is reset code:

extern volatile unsigned long timer0_overflow_count;

timer0_overflow_count = 0;

Yes, it will suffer the millis() rollover strangeness, but I have a simple solution: not to run it for more than a few hours! Heh...:stuck_out_tongue: [w/dunce cap] I'll patch it asap-- thanks for the how-to!

Hi salsaman, I'm very interested in the dirty details of how did you hack your Canon A75... do you have any additional pictures / posts regarding which cable goes where? I have a Canon A60 and I'd like to implant a 2,5mm jack to do what you did, in a "not-so-spaghetti-looking" fashion...
Thanks!

Nicely done! I'm fascinated by arduino-camera interfaces. Thanks for sharing

Can you think of any Arduino camera interfaces besides an intervalometer or some form of tripwire/tripsound/etc? I'm trying to think of a new project.

A few months ago I built an IR intervalometer for my Nikon D90. Then after I had it working but not assembled into a housing, I did some quick math and at 24 frames per second, five minute of time-lapse will need 7200 exposures. I just can't bring myself to put that kind of wear and tear on the mechanics of the camera. It's rated for 100,000 exposures and I don't want to wear out the $1000 body prematurely.

I have a cannon powershot A510, the form factor is realy similar to yours. I'd also be interested in how you hacked the trigger etc.

@estranged: you may want to google for CHDK.

Yeah, I've read about CHDK before, unfortunately they don't have anything for the A510, and I'm not up to starting a project like that.

I'm starting with Arduino and did not know this project is very good.
I would like to make one could you indicate how well the circuit?
How can you connect the LCD with a few cables?

Thanks

The lcd may have an serial backpack.
Nice project :wink:

Thank you.
But I would like to know how to link all components of a circuit is there to show?

Antonio,

I built an Arduino intervalometer (and more) a couple of years ago. I've included a schematic that you might use as a source of ideas for your own design.

http://www.mrgoodbench.com

Good luck!

Tom