
Adding steady motion to a time lapse is not easy
This not-so-simple contraption adds motion to time lapse photography. Not a Rube Goldberg machine by any means, but the design is somewhat convoluted. However, the concept is simple: move a small amount, take a pic, move a small amount, take a pic. A platter spins to pan the camera, and a strip of plywood leans to tilt the camera.
Here’s a time lapse of it in operation (that’s right, a time lapse of a time lapse):
The camera’s shutter release is wired to an Arduino thru a 1N4148 diode.

The Arduino controls two stepper motors – one for pan, one for tilt. Each motor is connected to a gear, which is connected to a cylinder (pill container!). Each cylinder has sandpaper on its sides to better grip a length of string. The ‘pan’ string is wrapped around the circumference of the platter, and the ‘tilt’ string is fed around a skateboard wheel to complete its loop. This loop means that the unit can move both directions i.e. up or down.
The stepper motors cannot pull too much, so less friction (via graphite) while panning is necessary. And balancing the tilt arm helps it function with less effort.
A Nintendo D-pad controls the pan (left/right), tilt (up/down), and also the camera’s shutter release (button A). In fact, once the whole contraption is ready to start moving and taking pics, the ‘Start’ button is pressed to initiate the sequence.

Here is an example of what it can capture.
All parameters are adjustable in the code: the exposure time, amount of pan or tilt movement, interval between pictures, number of pictures, etc.
CODE:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
/* panomaticTiltatron http://creativetechnical.ca/panomatictiltatron/ Adds motion to timelapse photgraphy. */ #include <NESpad.h> #define REVIEW_PICTURE 100 #define INTERVAL 100 #define EXPOSURE 200 //If using 'bulb', change to desired exposure (ie 5000 is a 5 second shutter) //other than 'bulb': use 100 (Canon will not see value <90mS). #define RESPONSE 300 //controller response delay NESpad nintendo = NESpad(4,5,3); //strobe, clock, data byte state = 0; int shutter_pin = 1; //shutter: pin1 LOW will open shutter; pin1 HIGH will close shutter (gnd=sleeve, pin 1=tip) /////////////////////////////////////////////////////////////////////////////////////////////// int panLED = 6; int tiltLED = 7; //motor 1:PAN///////////////////////////////// int pan_dir = A2; // connect pin A2 to dir int pan_step = A3; // connect pin A3 to step //motor 2:TILT//////////////////////////////// int tilt_dir = A4; // connect pin A4 to dir int tilt_step = A5; //connect pin A5 to step ////////////////////////////////////////////////////////////////////////////////////////////////// void pauseMotor() { digitalWrite(pan_step, LOW); delay(10); digitalWrite(tilt_step, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void panMotorLeft() { digitalWrite(panLED, HIGH); //light yellow LED digitalWrite(pan_dir, HIGH); //left digitalWrite(pan_step, HIGH); //high moves the motor delay(10); digitalWrite(pan_step, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void panMotorRight() { digitalWrite(panLED, LOW); //light red LED digitalWrite(pan_dir, LOW); //right digitalWrite(pan_step, HIGH); //high moves the motor delay(10); digitalWrite(pan_step, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void tiltMotorUp() { digitalWrite(tiltLED, HIGH); //light yellow LED digitalWrite(tilt_dir, HIGH); //up digitalWrite(tilt_step, HIGH); //high moves the motor delay(10); digitalWrite(tilt_step, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void tiltMotorDown() { digitalWrite(tiltLED, LOW); //light red LED digitalWrite(tilt_dir, LOW); //down digitalWrite(tilt_step, HIGH); //high moves the motor delay(10); digitalWrite(tilt_step, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void picture() { delay(2500); digitalWrite(shutter_pin, LOW); //opens shutter delay(EXPOSURE); digitalWrite(shutter_pin, HIGH); //closes shutter delay(REVIEW_PICTURE); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { pinMode(shutter_pin, OUTPUT); pinMode(pan_dir, OUTPUT); pinMode(pan_step, OUTPUT); pinMode(tilt_dir, OUTPUT); pinMode(tilt_step, OUTPUT); pinMode(panLED, OUTPUT); pinMode(tiltLED, OUTPUT); pinMode(13, OUTPUT); digitalWrite(shutter_pin, HIGH); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { state = nintendo.buttons(); while((state & NES_LEFT)) //||(state & NES_DOWN)||(state & NES_LEFT)||(state & NES_RIGHT)) //||(state & NES_START)||(state & NES_SELECT)) { state = nintendo.buttons(); if (!((state & NES_RIGHT)||(state & NES_UP)||(state & NES_DOWN)||(state & NES_SELECT))) { state = NES_LEFT; panMotorLeft(); delay(RESPONSE); } } while((state & NES_RIGHT)) { state = nintendo.buttons(); if (!((state & NES_LEFT)||(state & NES_UP)||(state & NES_DOWN)||(state & NES_SELECT))) { state = NES_RIGHT; panMotorRight(); delay(RESPONSE); } } while((state & NES_UP)) { state = nintendo.buttons(); if (!((state & NES_LEFT)||(state & NES_RIGHT)||(state & NES_DOWN)||(state & NES_SELECT))) { state = NES_UP; tiltMotorUp(); delay(RESPONSE); } } while((state & NES_DOWN)) { state = nintendo.buttons(); if (!((state & NES_LEFT)||(state & NES_RIGHT)||(state & NES_UP)||(state & NES_SELECT))) { state = NES_DOWN; tiltMotorDown(); delay(RESPONSE); } } if ((state & NES_SELECT)) { pauseMotor(); } if (state & NES_A) { picture(); delay(RESPONSE); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// while((state & NES_START)) //3:3; 3:2; 3:1; 3:0; 3:1; 3:2; 3:3 { state = NES_START; for(int tilt=3; tilt>0; tilt--) //loop will happen 3 times { for(int i=0; i<150; i++) //107 { state = nintendo.buttons(); if (!(state & NES_DOWN)) { for(int p=0; p<2; p++) //always do this 2 times { panMotorRight(); } for(int t=0; t<tilt; t++) //do this 3 times; then 2; then 1 { tiltMotorUp(); } picture(); delay(INTERVAL); } } } for(int tilt=0; tilt<=3; tilt++) //loop will happen 4 times { for(int i=0; i<150; i++) //107 { state = nintendo.buttons(); if (!(state & NES_UP)) { for(int p=0; p<2; p++) { panMotorRight(); } for(int t=0; t<tilt; t++) //do this 0 times; then 1; then 2; then 3 { tiltMotorDown(); } picture(); delay(INTERVAL); } } } } } ////////////////////////////////////////////////////////////////////////////// /* // a way to test if a button is pressed: if (state & NES_A) ... // a way to test if a button is not pressed: if !(state & NES_A) ... // and a way to check for diagonal directions: // (ie: the UP button is pressed AND/&& the LEFT button is also pressed) if ( (state & NES_UP) && (state & NES_LEFT) ) ... digitalWrite(5, state & NES_A ); // state & SNES_A is equal to true/HIGH if the A button is pressed digitalWrite(6, state & NES_B ); // ditto for the B button ... digitalWrite(7, state & NES_SELECT ); digitalWrite(8, state & NES_START ); digitalWrite(9, state & NES_UP ); digitalWrite(10, state & NES_DOWN ); digitalWrite(11, state & NES_LEFT ); digitalWrite(12, state & NES_RIGHT ); */ |