Time Lapse with Arduino and Panasonic FZ50

Hi,

here is a first video of my Arduino Time Lapse Intervallometer:

It is Full-HD if your computer can handle it (make it fullscreen).

Shots are taken during aprox one hour with this hardware:

Carsten

NICE! I love time lapse photography.

I've got an FZ50 and bought an Arduino to build just this thing! Do you happen to have the schematics or code posted anywhere? Great job!

The schematics are base on http://www.mindspring.com/~tom2000/Projects/AI-1_Remote/AI-1_Remote.html

The display is basically just a HD44780-compatible LCD in 4-bit mode go to

http://www.arduino.cc/playground/Code/LCD

to get an idea.

/*
  X Assist Time Lapse Device
  
  Author: Carsten Wartmann
  Copyright (c) 2009  Carsten Wartmann. All right reserved.

  This is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser Public License for more details.

  You should have received a copy of the GNU General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
Conrad:
1x SOLID-STATE-RELAY LH1540-AT
4x FOTOTRANSISTOR/OPTOKOPPLER 4N25-000E
4x 1,8k
4x 27k
4x 33k
*/

/* Todo 

- keep params in EEPROM
- besseres Focusmangement (bei Autofocus Focustime abziehen von Interval)
- F/f Auto/Manual Focuswahl

*/

// Pins
#define CLOCK  2   // grau     : on the 74HC164 
#define DATA   3   // rot/ws   : on the 74HC164 means A1/A2 interconnected
#define EEEE   4   // violett  : on the display
#define RS     5   // rosa     : on the display

#define BUTA  6  // braun
#define BUTB  7  // grün

#define PADL  8  // schwarz
#define PADU  9  // rot
#define PADR  10 // orange
#define PADD  11 // gelb

#define FOCUS   13
#define EXPOSE  12

// Buffer for text
byte line[80];

// cursor position
byte cx = 0;
byte cy = 0;

unsigned long time;
unsigned long interval=5000;

boolean exlock;
unsigned int taken;

unsigned long wait;
unsigned long next;

boolean automode = false;  // Exposure running
boolean apress;

int animnr=0;
char autoanim[5] = " .*A";

void setup()
{
  pinMode(CLOCK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(FOCUS, OUTPUT);
  pinMode(EXPOSE, OUTPUT);
  pinMode(EEEE, OUTPUT);
  pinMode(RS, OUTPUT);

  pinMode(BUTA, INPUT);
  pinMode(BUTB, INPUT);
  pinMode(PADR, INPUT);
  pinMode(PADL, INPUT);
  pinMode(PADU, INPUT);
  pinMode(PADD, INPUT);
  initLCD();
  Serial.begin(38400);  //Only for debugging atm, can be removed
  wait=millis(); // Init the refresh delay
}


// Send a byte
void sendByte(byte pattern)
{
  shiftOut(DATA, CLOCK, MSBFIRST, pattern);
  digitalWrite(EEEE, LOW);    
  delayMicroseconds(700); //600 min?
  digitalWrite(EEEE, HIGH);    
}

// Send a byte COMMAND
void sendCMD(byte pattern)
{
  digitalWrite(RS, LOW);    
  shiftOut(DATA, CLOCK, MSBFIRST, pattern);
  digitalWrite(EEEE, LOW);    
  delayMicroseconds(700); //600 min?
  digitalWrite(EEEE, HIGH);    
  digitalWrite(RS, HIGH);    
}


void initLCD()
{
  delay(105);
  digitalWrite(RS, LOW);  
  delay(5);  
  sendByte(B00110000);
  delay(60);
  sendByte(B00110000);
  delay(60);
  sendByte(B00110000);
  delay(60);
  sendByte(B00110000);
  delay(60);
  sendByte(B00111000); //2 Lines 5x7pixel
  sendByte(B00001000);   
  sendByte(B00000001); 
  sendByte(B00000110);  //Decrement  Display Shift 
  sendByte(B00001110);  // Cursor  D C B
  delay(60);
  delay(5);
  sendByte(B0000001);
  delay(60);
  digitalWrite(RS, HIGH);   
  sendCMD(0x03);   // HOME  

  // Init the line buffer
  for (int i=0;i < 80;i++){
    line[i] = 48+16;
  }

}

void printIn(char msg[]) {
  unsigned int i;
  for (i=0;i < strlen(msg);i++){
    sendByte(msg[i]);
  }
}

// not used here
int smod(int z1, int z2) {
  int ze;
  ze=z1 % z2;
  if (ze>=0)  {
    return(ze);
  }
  else{
    return(z2+ze);
  }
}



void printTime( int px, int py, char label[], unsigned long milli){
  unsigned long h,m,s;
  char timestr[3] = "  "; 
  s = milli/1000;
  m = s/60;
  h = m/60;
  sendCMD(0x0C);
  sendCMD(0x80+px+(0x40*py));   // Cursor
  printIn(label);
  itoa(h,timestr,10); 
  if (strlen(timestr)<2){
    sendByte(48);
  }
  printIn(timestr);
  printIn(":");
  itoa(m%60,timestr,10); 
  if (strlen(timestr)<2){
    sendByte(48);
  }
  printIn(timestr);
  printIn(":");
  itoa(s%60,timestr,10); 
  if (strlen(timestr)<2){
    sendByte(48);
  }
  printIn(timestr);
  //  printIn("s");
  sendCMD(0x80+cx+(0x40*cy));   // Cursor 
  sendCMD(0x0E);
}

void expose()
{
  taken++;
  digitalWrite(EXPOSE,HIGH);
  delay(200);
  digitalWrite(EXPOSE,LOW);
}

void focus()
{
  digitalWrite(FOCUS,HIGH);
  delay(2500);
  digitalWrite(FOCUS,LOW);
}


void setCursor(int px, int py)
{
  //  sendCMD(0x0C); // Cursor invisible
  sendCMD(0x80+px+(0x40*py));   // position Cursor
  //  sendCMD(0x0E); // Line Cursor on
}

void gui()
{
  char timestr[3] = ""; 
  sendCMD(0x0C); // Cursor invisible
  setCursor(0,0);
  printIn("E:000");
  itoa(taken,timestr,10); 
  for(int i=0; i<strlen(timestr);i++)
  {    
    sendCMD(0x10); // Cursor invisible
  }
  printIn(timestr);
  setCursor(0,1);
  if (automode)
  {    
    printIn("F L ");
    sendByte(autoanim[animnr]);
    animnr = (animnr + 1) % 4;  
  }
  else
  {
    printIn("F L a");      
  }
  setCursor(cx,cy);   // position Cursor
  sendCMD(0x0E); // Line Cursor on
}

void loop()
{  

  // Switch on Auto-Mode when on "a" and A-Button
  if (cx==4 && cy==1)
  {
    if  (digitalRead(BUTA)  == LOW && !apress) 
    {
      apress = true;
    }
    if (digitalRead(BUTA)  == HIGH && apress) 
    {
      automode = automode^1;
      apress=false;
      gui();
      if (automode){  //take first picture immediately
        expose();
      } 
    }
  }

// Manually take a picture  when on "E" and A-Button
  if (cx==0 && cy==0)
  {
    if  (digitalRead(BUTA)  == LOW && !apress) 
    {
      apress = true;
    }
    if (digitalRead(BUTA)  == HIGH && apress) 
    {
      apress=false;
      gui();
        expose();
    }
  }

// Manually Focus On "F" and A Button
  if (cx==0 && cy==1)
  {
    if  (digitalRead(BUTA)  == LOW && !apress) 
    {
      apress = true;
    }
    if (digitalRead(BUTA)  == HIGH && apress) 
    {
      apress=false;
      gui();
      focus();
    }
  }


  if (automode)
  {
    if (long(next-millis())<=0)
    {
      expose();
      next=millis()+interval-200;
    }
  }
  else
  {
    next=millis()+interval-200;    
  }

  // Refresh cycle
  if (millis()-wait>=300)  //Wait a second
  {
    wait=millis();   
    printTime(6,0,"I=",interval);
    printTime(6,1,"N=",next-millis()+1000);
    gui();
  }


  // Cursor right
  if (digitalRead(PADR)  == LOW) {     
    cx = (cx + 1) & 15 ;// & 1 means x modulo 16
    sendCMD(0x80+cx+(0x40*cy));   // Cursor 
    delay(200);
  } 
  // Cursor left
  if (digitalRead(PADL)  == LOW) {     
    cx = (cx - 1) & 15; // & 1 means x modulo 16
    sendCMD(0x80+cx+(0x40*cy));   // Cursor 
    delay(200);
  } 

  // Pad Up
  if (digitalRead(PADU)  == LOW) {
    if (cy==0)
    {   
      switch (cx) {
      case 8:
        interval=interval+36000000;
        break;
      case 9:
        interval=interval+3600000;
        break;
      case 11:
        interval=interval+600000;
        break;
      case 12:
        interval=interval+60000;
        break;
      case 14:
        interval=interval+10000;
        break;
      case 15:
        interval=interval+1000;
        break;
      }
      next=millis()+interval;
      printTime(6,0,"I=",interval);
      //Serial.println(interval);
    }
    if (cx<8){
      cy = 0;
      sendCMD(0x80+cx+(0x40*cy));   // Cursor
    }
    delay(150);

  } 
  // Pad Down
  if (digitalRead(PADD)  == LOW) {
    if (cy==0)
    {   
      switch (cx) {
      case 8:
        interval=interval-36000000;
        break;
      case 9:
        interval=interval-3600000;
        break;
      case 11:
        interval=interval-600000;
        break;
      case 12:
        interval=interval-60000;
        break;
      case 14:
        interval=interval-10000;
        break;
      case 15:
        interval=interval-1000;
        break;
      }
      next=millis()+interval;
      printTime(6,0,"I=",interval);
      //Serial.println(interval);
    }
    if (cx<8){
      cy =  1;  
      sendCMD(0x80+cx+(0x40*cy));   // Cursor
    }
    delay(150);

  } 

}

You will have to change it anyhow to fit your hardware, so use with care.

Carsten

Thanks! I can't wait to try this out.

This looks very professional. I am searching for a case like yours for weeks by now. Where did you get such a nice box for your project?

Udo:

I grabbed it out of the trash... Have a look here:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236549392/0#0

In my last post there is a hint what kind of device it it. MAYBE you can get one at ebay.

Carsten

Great. So I will try my luck at *bay. The only other case I found so far is not close as cool.