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 provided10,033
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
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.
Contact

Comments

Please log in or sign up to comment.