James Cripps
Published

Arduino HackHD Time-Lapse Dolly

Watch in high-definition as several hours or even an entire day fly by in seconds. Get lost in the dream as the camera pans & rotates.

IntermediateFull instructions provided9,998
Arduino HackHD Time-Lapse Dolly

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
28BYJ-48 5V Stepper Motor
×2
1602 LCD Display
×1
4 x 3 Matrix Keypad
×1
HackHD 1080p Camera
×1
2 USB Port Power Bank
×1

Story

Read more

Code

Time-lapse dolly

C/C++
/Time-lapse dolly/

#include <Keypad.h>
#define STEPS 4096

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
const byte LCDpin = 13;
const byte camTX = 18, camRX = 19; //pins to communicate with the camera
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

//variables to store and verify user input 
String filmDur = 0, sbf = 0, deg = 0;
boolean answerGiven = 0, userVerified = 0, inputValid = 0;

//stepper motors setup
const byte stepperSpeed = 10; //the higher the number the slower the stepper
const byte translate[4] = {9,10,11,12}; // pins for the translating stepper
const byte rotate[4] = {14,15,16,17}; // pins for rotating stepper
const boolean stepperSeq[8][4] = { //step sequence to move the motors

  {1,0,0,1},
  {1,0,0,0},
  {1,1,0,0},
  {0,1,0,0},
  {0,1,1,0},
  {0,0,1,0},
  {0,0,1,1},
  {0,0,0,1}
};

void setup(){
  pinMode(camTX, OUTPUT);
  digitalWrite(camTX, HIGH); //Make sure the camera button is not grounded
  pinMode(camRX, INPUT);  
  
  //set up stepper motors for translation and rotation 
  setupStepper(translate);
  setupStepper(rotate);
 
     
 
  pinMode(LCDpin,OUTPUT); 
  Serial.begin(19200);
  resetLCD(LCDpin); //power on LCD   
    
  Serial.println("Welcome to the  time-lapse dolly");
  delay(2000);
  standbyMode(camTX); //i only had to power on the camera here because 
                    //otherwise the battery turned itself off due to lack of current being drawn
  while(digitalRead(camRX) == LOW){
    ; //wait until camera verifies it is in standby mode
  }
}
  
void loop(){
  do  {     
      Serial.println("                                \n\n");
      Serial.print("Duration of filming in hours: ");
      filmDur = getData(2); //wait for input of 2 chars in length
      do {
        Serial.println("                                \n\n");
        Serial.print("How many secondsbetween shots:");
        sbf = getData(2);
        if(sbf.toInt() < 10){
          Serial.println("                                \n\n");
          Serial.print("Minimum 15 seconds between shots");
          delay(3000);
        }
        else {
          inputValid = 1;
        } 
      } while(inputValid == 0); 
      
      Serial.println("                                  \n\n");
      Serial.print("How many degreesof rotation:");
      deg = getData(3);
      Serial.println("                                  \n\n");
      Serial.print("OK! the sequencewill go for.... ");
      delay(2000);
      Serial.println("                                \n\n");
      Serial.print(filmDur);
      Serial.print(" hours");
      delay(2000);
      Serial.println("                                \n\n");
      Serial.print("There will  be  ...             ");
      delay(2000);
      Serial.println("                                \n\n\n\n");
      Serial.print(sbf);
      Serial.print(" seconds      between frames");
      delay(2000);
      Serial.println("                                \n");
      Serial.print("And the camera  will rotate ");
      delay(2000);
      Serial.println("                                \n\n\n");
      Serial.print(deg);
      Serial.print(" degrees");
      delay(2000);
      Serial.println("                                \n\n");
      Serial.print("Is this OK?     * = YES # = NO  ");
    
      answerGiven = 0; //reset boolean in case it isn't the first time through
      do {
        char key = keypad.getKey();
        if(key == '*'){ //if YES, mark input as verified by the user
        userVerified = 1;
        answerGiven = 1;
        }
        if(key == '#'){ //if NO, clear entries and start from the top
          filmDur = 0; 
          sbf = 0; 
          deg = 0;
          inputValid = 0;
          answerGiven = 1;
        }
      } while(answerGiven == 0); //wait for a valid answer
    
      
      
  } while (userVerified == 0); //if input is verified then continue
  
  //begin time-lapse photography
    Serial.println("                                \n\n");
    Serial.print("Initiating      sequence...\n");
    //calculate total frames in sequence
    int totalFrames =  filmDur.toInt() * 60 * 60  / sbf.toInt(); 
    //calculate increment for the translation stepper
    int incrementT = round(5 * STEPS / (float)totalFrames); 
   
    //calculate increment for the rotation stepper
    float ratio = (float) deg.toInt() / 360;
    int incrementR = round(STEPS * ratio / totalFrames);

    //get out of standby mode before actually beginning photography
    standbyMode(camTX);
    while(digitalRead(camRX) == HIGH){
      ;
    }
    
    int i, nextStepT = 0, nextStepR = 0;
    for(i = 1; i <= totalFrames; i++){
      
      unsigned long time = millis(); //get time at beggining of iteration
      shoot(camTX); //take a picture
      Serial.println("                                \n\n");
      //calculate and display the percentage completion and hours remaining
      int percentage = i / (float)totalFrames * 100;
      Serial.print(percentage);
      Serial.print("% complete");
      Serial.println("\n");
      int hrsLeft = round( (float)filmDur.toInt() * ( (100 - (float)percentage) / 100 ));
      Serial.print( hrsLeft );
      Serial.print(" hours left");  
      nextStepT = stepper(translate, incrementT, 1, nextStepT); //translate
      nextStepR = stepper(rotate, incrementR, 1, nextStepR);  //rotate
      //subtract the time elapsed since the beggining of the iteration from 
      //the desired delay between frames, and then delay that resulting time
      while(digitalRead(camRX) == HIGH){
        ; //wait for picture to save before moving on
      }
      while( ( millis() - time ) < ( sbf.toInt() * 1000 ) ){
        ;
      }
    }  
    Serial.print("done");
    while(1){
      ;
    }

}

void resetLCD(byte pin) {
  
  digitalWrite(pin,LOW);
  delay(500);
  digitalWrite(pin,HIGH);
  delay(2000); //LCD needs time to self-test
}

void standbyMode(byte pin){
  digitalWrite(pin, LOW);
  delay(2000);
  digitalWrite(pin, HIGH); 
}

void shoot(byte pin){
  digitalWrite(pin, LOW);
  delay(200);
  digitalWrite(pin, HIGH); 
}

String getData(int len){
  //function that returns a string entered on the keypad of max length "len" 
  String data = 0;
  while(data.length() < len) {
     char key = keypad.getKey();  
     if (key){
        if(key == '#' || key == '*'){
          ; //do not accept non-numeric characters
        } else {
            data += key; //concatenate character to input string
            Serial.print(key); //print character
        }
     }
   }
   delay(500); //allow time so user can actually see his/her input before moving on
  return data;  
}

void setupStepper(const byte type[]){
  //set all stepper pins to output
  int i = 0;
  for(i=0; i<4; i++){
      pinMode(type[i], OUTPUT);
  }
}
 

int stepper (const byte type[], int iterations, boolean dir, int lastStep){
  int d = 0;
  if(dir){ //dir = 1 means clockwise
   while(iterations){ 
     for(d = 0; d < 4; d ++){
      digitalWrite(type[d], stepperSeq[lastStep][d]);
     }
     lastStep++;
     if(lastStep > 7){
       lastStep = 0;
     }
     
     iterations--;
     delay(stepperSpeed);
   }
  }

  else { //dir = 0 means counterclockwise
   while(iterations){
    for(d = 0; d < 4; d++){  
      digitalWrite(type[d], stepperSeq[lastStep][d]);
    }
    lastStep--;
    if( lastStep < 0 ){
     lastStep = 7;
    } 
    iterations--;
    delay(stepperSpeed);
   }
  }
  
  return lastStep;
}

Credits

James Cripps

James Cripps

2 projects • 5 followers
Avid hardwarian and wantrepreneur. Been tinkering with Arduino since 2011. Born in Hong Kong, raised in Shanghai, now living in Sydney.

Comments