Time Lapse Camera Robot
This is one of my old class projects that I never got around to adding here because I did not like the results. However, the pictures look cool and the code works well so someone will probably like this project.
At the very least this project will be a warning to others about what they should take into consideration when starting their time lapse project.
Features:
- Arduino power
- 2 Axis servo motors
- Programmable motion
- Back lit LCD display
- SolidWorks modeled
- Laser Cut
- Heat shaped acrylic
- Cannon Rebel Intervalometer
Problems
I should start by listing what I did not like.
First, the motors were to week to move the camera properly. If I had the mount on the tripod then attached the camera it would work good and point the camera where it should, but if the camera had a telescope lenses on it, the balance was off. If I was not careful when manually moving the whole setup the motors would turn. Lastly I did not like the noises the motors made the whole time they were running.
The next problem was programming where the camera was suppose to aim. I thought I had an efficient, easy to visualize, programming system for aiming. The camera always spun 180 degrees, left to right. I figured if I wanted less than 180 degrees it was easy to crop afterwards. My two user options were to set the time it took for the camera to move the horizontal 180 degrees, and the vertical angle it started at. The programming system worked well but never had the finesse I needed. Sure I knew the start, and end points but it really needed something like key frames, and the ability to speed up or slow down at different spots. If I was panning across a lake the vertical servo was useless and there wasn’t much that I could do with my two servos that I could not also do with one.
Third, having the camera take a bunch of pictures then editing them together afterwards is easy but it needs a lot of pictures to look good. I was setting it up so that when the video was compiled it would be about 11 pictures a second, and it looked jumpy. Normal videos are about 30 pictures a second, but being able to take, and store enough pictures to make a 30 picture a second video was overwhelming for my SD card and camera. I didn’t want the camera taking that many pictures or my computer to stall trying to compile them. Next time I would just get a camera that could take video and avoid the intervalometer all together. Oh and the camera I used was a Cannon Rebel, I don’t know where my pictures with the proper camera went.
The last problem was keeping the whole thing powered. The servos use a lot of power and especially during time lapse sessions I never liked having to worry about my batteries dying. I am currently working on a panning slider design that will solve my battery problem.
Build Process
Here is a quick rundown of how I did this project. I included the SolidWorks models and the DWG files. Even though I started by listing everything I would change next time, this project was fun and a good stepping stone for future projects. The final product looked cleaner than many of my projects and I think I learned a lot doing this.
- Model the 3D assembly in SolidWorks.
- Convert the measurements from the 3D SolidWorks model into a 2D DWG that can be cut with the laser.
- Code the Arduno
- Assemble the unit, I used a heat gun to make the fancy rounded corners. Hot glue worked good to hold everything together and was easy to disassemble but looked ugly. Acrylic welding glue looked cleaner but harder to remove.
- Test
- Play
Downloads
Code
/* Try 1 of camera mount
use 2 servos,
2 buttens that have 2 functions for increasing/decreasing time
2 buttons with single functions for adjusting the vertical angles
Lcd to display time and angle
*/
// include the library code:
#include
#include
#include "RTClib.h"
#include
Servo myservoV; // create servo object to control a servo
Servo myservoH; // create servo object to control a servo
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 2, 0, 4, 1, 6);
#define ledRed 3 // input pin for led backlight
#define ledGreen 5 // input pin for led backlight
//Define the Button pins
#define UpBtnbuttonPin A1 // analog input pin to use as a digital input
#define DnBtnbuttonPin A2 // analog input pin to use as a digital input
#define VerbuttonPin A3 // analog input pin to use as a digital input
//#define DnVerbuttonPin A4 // analog input pin to use as a digital input
#define StartbuttonPin A4 // analog input pin to use as a digital input
#define trigger 12 //trigger of camera seems to auto focus
#define focus 9 // cammera focus, keeps it awake between pictures and focusses
//Time Counter Variables
unsigned long buttonPushCounter = 0; // counter for the number of button presses
int buttonPushDisplayHr = 0;
int buttonPushDisplayMin = 0;
int buttonPushCounterMin = 0;
// UpBtn varables
int UpBtnbuttonState = 0; // current state of the button
int UpBtnlastButtonState = 0; // previous state of the button
// DnBtn varables
int DnBtnbuttonState = 0; // current state of the button
int DnBtnlastButtonState = 0; // previous state of the button
//start button variables
int StartbuttonPushCounter = 0; // counter for the number of button presses
int StartbuttonState = 0; // current state of the button
int StartlastButtonState = 0; // previous state of the button
unsigned long Starttime = 0;
//int buttonPushCounterStop = 0;
int startVal = 0;
// UpVer varables
int VerbuttonState = 0; // current state of the button
int VerlastButtonState = 0; // previous state of the button
int VerbuttonPushCounter = 0;
int DispAngV = 0;
float DispAngVa = 0;
float AngFloat = 0;
//float valV = 0;
//servo variables
int valH = 0; // servo position 1 to 180
float valV = 0; // servo position 1 to 180
unsigned long del = 0; // pause between positions
int angV = 0; //angle for vertical servo
//========================================================
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16,2);
//Serial.begin(9600);
lcd.setCursor(0, 0);
lcd.print("TIME"); //display temp on the lcd
lcd.setCursor(0, 1);
lcd.print("00:00 00");
// Set button input pin
pinMode(UpBtnbuttonPin, INPUT);
pinMode(DnBtnbuttonPin, INPUT);
pinMode(StartbuttonPin, INPUT);
pinMode(ledRed, INPUT);
pinMode(ledGreen, INPUT);
digitalWrite(UpBtnbuttonPin, HIGH );
digitalWrite(DnBtnbuttonPin, HIGH );
digitalWrite(StartbuttonPin, HIGH );
//Start servos
myservoV.attach(11); // attaches the servo on pin 9 to the servo object
myservoH.attach(10); // attaches the servo on pin 9 to the servo object
//zero servos to start
myservoV.write(95);
myservoH.write(90);
StartbuttonPushCounter = 0;
// camera attached stuff
pinMode(trigger, OUTPUT); //set the trger pin to start he relay
digitalWrite(trigger, LOW); //set the trigger relay to of
pinMode(focus, OUTPUT); //set the trger pin to start he relay
digitalWrite(focus, LOW); //set the trigger relay to of
}
//========================================================================== LOOP
void loop() {
digitalWrite(ledGreen, 255);
//check start button------------------------ START BUTTON
//for next time through the loop
// StartlastButtonState = StartbuttonState;
// read the pushbutton input pin:
StartbuttonState = digitalRead(StartbuttonPin);
// compare the buttonState to its previous state
if (StartbuttonState != StartlastButtonState) {
// if the state has changed, increment the counter
//
if (StartbuttonState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
if (StartbuttonPushCounter < 2){
StartbuttonPushCounter++;
//Starttime = millis(); //to complicated but works better
}
}
}
// read the pushbutton input pin:
UpBtnbuttonState = digitalRead(UpBtnbuttonPin);
// compare the buttonState to its previous state ---- UP Button
if (UpBtnbuttonState != UpBtnlastButtonState) {
// if the state has changed, increment the counter
if (UpBtnbuttonState == HIGH) {
//if (buttonPushCounter <= 40)
//if (startVal>2)
if (StartbuttonPushCounter != 2){
buttonPushCounter = buttonPushCounter + 2;
}
}
}
//check down button------------------------ DOWN BUTTON
//for next time through the loop
// DnBtnlastButtonState = DnBtnbuttonState;
// read the pushbutton input pin:
DnBtnbuttonState = digitalRead(DnBtnbuttonPin);
// compare the buttonState to its previous state
if (DnBtnbuttonState != DnBtnlastButtonState) {
// if the state has changed, increment the counter
if (DnBtnbuttonState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
if (buttonPushCounter >= 1) {
//if (startVal=0)
if (StartbuttonPushCounter != 2){
buttonPushCounter = buttonPushCounter - 2;
}
}
}
}
// BUTTENS FOR VERTICAL ANGLE ----------------------------------------------------- VER ANG BUTTON
// read the pushbutton input pin:
VerbuttonState = digitalRead(VerbuttonPin);
// compare the buttonState to its previous state ---- SERVO UP
if (VerbuttonState != VerlastButtonState) {
// if the state has changed, increment the counter
if (VerbuttonState == HIGH) {
//if (buttonPushCounter <= 40)
//if (startVal>2)
if (VerbuttonPushCounter != 4){
VerbuttonPushCounter = VerbuttonPushCounter + 1;
DispAngV = (VerbuttonPushCounter - 1) * 30;
lcd.setCursor(14, 1);
lcd.print (DispAngV);
}
else {
VerbuttonPushCounter = 1;
DispAngV = (VerbuttonPushCounter - 1) * 30;
lcd.setCursor(14, 1);
lcd.print (DispAngV);
}
}
}
//fix start button starting at vlue of 1----- ---start bnt actions
if (StartbuttonPushCounter != 2) {
(StartbuttonPushCounter = StartbuttonPushCounter);
}
else{
//(StartbuttonPushCounter = 5)
//calculate delays for horzontal servo loop
//del = 200;
del = buttonPushCounter * 1500;
//calculate angle per pix for vertical servo
//angV = 1; // start at 60 degrees go to 0
//start servo loop
//servo();
//startVal++;
//StartbuttonPushCounter = 2;
}
//---------------------------------------------------------
//save button states
UpBtnlastButtonState = UpBtnbuttonState;
DnBtnlastButtonState = DnBtnbuttonState;
StartlastButtonState = StartbuttonState;
VerlastButtonState = VerbuttonState;
// display time---------------------------------------------TIME DISPLAY
buttonPushDisplayHr = (buttonPushCounter) / 4;
buttonPushCounterMin = buttonPushCounter - (buttonPushDisplayHr * 4);
buttonPushDisplayMin = buttonPushCounterMin * 15;
//calculate angle for vertical-------------------------------
DispAngVa = VerbuttonPushCounter -1;
AngFloat = DispAngVa / 2;
//truble shoot=======================================================================trouble shoot
//Serial.println(Starttime);
//lcd.setCursor(13, 1);
//lcd.print (StartbuttonPushCounter);
//lcd.setCursor(9, 1);
// lcd.print (Starttime);
//--go to servo after start btn--------------------------go to servo
if (StartbuttonPushCounter != 1) {
lcd.setCursor(0, 0);
lcd.print (" RUNNING ");
servo();
}
else {
//Show how many mins
lcd.setCursor(3, 1);
lcd.print (buttonPushDisplayMin);
//Show how many hours
if (buttonPushDisplayHr < 10) {
lcd.setCursor(1, 1);
lcd.print (buttonPushDisplayHr);
lcd.setCursor(0, 1);
lcd.print ("0");
}
else {
lcd.setCursor(0, 1);
lcd.print (buttonPushCounter);
}
//Show seperator
lcd.setCursor(2, 1);
lcd.print (":");
// show counts
lcd.setCursor(11, 0);
lcd.print ("ANGLE");
}
}
//end of loop=============================================LOOP ENDS
//servo loop----------------------------------------------SERVO LOOP
void servo() // servo movements
{
//move servo to next position
if (valH >=174){
lcd.setCursor(0, 1);
lcd.print (" All DONE ");}
else{
if (valH < 3) {
valV = 90 - DispAngV;
}
valH = valH + 3;
valV = valV + AngFloat;
//val = map(val, 50, 300, 0, 179); // scale it to use it with the servo (value between 0 and 180)
myservoH.write(valH); // sets the servo position according to the scaled value
myservoV.write(valV); // sets the servo position according to the scaled value
// camera trigger---------------------------------CAMMERA STUFF
digitalWrite(focus, HIGH);
delay (1000);
digitalWrite(focus, LOW);
digitalWrite(trigger, HIGH);
delay (1000);
digitalWrite(trigger, LOW);
// delay until it is time for next position, using clock times would be better
// need 10 dels because arduino is messing up the large numbers even with an unsinged long variable
delay(del);
lcd.setCursor(6, 1);
lcd.print (valV);
}
}