
The follow up to the panomaticTiltatron, this enables one to add smooth motion to a time lapse or a video. The concept of adding motion to time lapse photography is simple: take a picture, move slightly. Take another pic, move slightly. Do this about a thousand times, and voila!
This is a motorized slider for a camera.
Consisting of two 3 metre lengths of 20mm electrical conduit (EMT), this slider can travel pretty far (2.85m). The conduit has been cut in half to allow for easier transport, and is rejoined on location with four screws. The sliding sled is salvaged from another slider, and a new heavy duty head is fastened to it to hold the camera.
At each end of the slider is a piece of 20mm plywood which holds the conduit and allows the attachment of the stepper motor and other electronics.

Each end has an attachment for positioning on a tripod. The sled is attached to a 6 metre continuous belt wrapped around a free running pulley and driven by the stepper motor. The belt must be removed for transport, then installed on location. To adjust the belt tension, there is a hinged ‘door’ which is easily positioned with a bolt.


The conduit is evenly spaced throughout its length with the use of flat steel. This allows the correct clearance for the moving parts.

The second stepper motor is attached between the sled and the camera, which provides the panning action of the camera.

All connections – power, communication, motors, shutter release, kill switch – are mounted on the enclosure box, while an Arduino Uno with stepper motor driver shield is contained inside.


The optional LEDs indicate the direction of sliding (up, down) and panning (left, right). The toggle switch turns this indication on/off.
The two rocker switches are connected to the stepper motor drivers. These enable 1/16th microstepping, meaning the stepper motor will turn less with each step (i.e. each picture), giving more precise movements. This is typically engaged when panning, where a large ‘jump’ will be noticeable.
The RCA connector is a disable switch for the motors: when the attached button is pushed, the motors are bypassed and the belt and pan heads are free to be manually positioned (vs controlled with D-pad).

The small momentary buttons on the plywood are automatic kill switches which protect the motors: when pushed (i.e. when the sled presses against them) the routine is paused and the motors will not burn out.

A NES D-pad controls the initial positioning of the sled and the pan. The ‘select’ and ‘start’ buttons are typically assigned to start and interrupt the routine; this is determined in the code.
As this is desirable to use outdoors, the rig is equipped with a 12V LiPo battery which powers the stepper motors. The Arduino is powered by its USB connector, which can be powered by a laptop or other portable USB battery.

Here’s a vid:
To determine the look of the finished product, a spreadsheet was created.

Here’s the basic code which can be manipulated to adjust many parameters: the sled’s travel between pictures, pan amount, shutter release, interval between pics, 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 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
/* slidomaticPanatron http://creativetechnical.ca/slidomaticpanatron/ Adds motion to timelapse photgraphy. motor delays + INTERVAL + pre-pic + EXPOSURE = spreadsheet interval Crescent Heights=840+1956+200+2000+2+2=5000 Waterton Stars 24x30=720+13500+580+200=15000 */ #include <NESpad.h> #define REVIEW_PICTURE 0 //or: use the 'pre-pic' "settling" time to review. #define INTERVAL 1956 //at least 500mS longer than shutter release time #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). Canon will override EXPOSURE when 'bulb' is not used. #define RESPONSE 0 //controller response delay. N/A once 'start' routine starts. NESpad nintendo = NESpad(9,10,11); //strobe, clock, data byte state = 0; #define SHUTTER_PIN 4 //pin4 LOW will open shutter; pin4 HIGH will close shutter (gnd=sleeve, pin 4=tip) #define panLED_PIN 12 #define slideLED_PIN 13 #define LIMIT_PIN 7 //#define panic_LED_PIN 10 //#define enablePAN_PIN 8 bool limitState = 0; /*for determining length/degrees within sequence/////// int steps = 0; int intervals = 0; int panCount = 0; float deg = 0; */ //motor 1:PAN///////////////////////////////// #define PAN_DIR 5 // connect pin D5 to dir #define PAN_STEP 2 // connect pin D2 to step //motor 2:SLIDE//////////////////////////////// #define SLIDE_DIR 6 // connect pin D6 to dir #define SLIDE_STEP 3 //connect pin D3 to step ////////////////////////////////////////////////////////////////////////////////////////////////// void pauseMotor() { digitalWrite(PAN_STEP, LOW); digitalWrite(SLIDE_STEP, LOW); delay(10); } ////////////////////////////////////////////////////////////////////////////////////////////////// void panMotorLeft() { digitalWrite(panLED_PIN, HIGH); //light yellow LED digitalWrite(PAN_DIR, HIGH); //left digitalWrite(PAN_STEP, HIGH); //high moves the motor delay(2); digitalWrite(PAN_STEP, LOW); delay(2); } ////////////////////////////////////////////////////////////////////////////////////////////////// void panMotorRight() { digitalWrite(panLED_PIN, LOW); //light red LED digitalWrite(PAN_DIR, LOW); //right digitalWrite(PAN_STEP, HIGH); //high moves the motor delay(2); digitalWrite(PAN_STEP, LOW); delay(2); } ////////////////////////////////////////////////////////////////////////////////////////////////// void slideMotorUp() { digitalWrite(slideLED_PIN, HIGH); //light blue LED digitalWrite(SLIDE_DIR, LOW); //up limitState = digitalRead(LIMIT_PIN); if(limitState == 1) { digitalWrite(SLIDE_STEP, HIGH); //high moves the motor // delay(1); digitalWrite(SLIDE_STEP, LOW); // delay(1); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void slideMotorDown() { digitalWrite(slideLED_PIN, LOW); //light green LED digitalWrite(SLIDE_DIR, HIGH); //down limitState = digitalRead(LIMIT_PIN); if(limitState == 1) { digitalWrite(SLIDE_STEP, HIGH); //high moves the motor // delay(1); digitalWrite(SLIDE_STEP, LOW); // delay(1); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void picture() { delay(2000); digitalWrite(SHUTTER_PIN, LOW); //opens shutter delay(EXPOSURE); digitalWrite(SHUTTER_PIN, HIGH); //closes shutter delay(REVIEW_PICTURE); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(9600); pinMode(SHUTTER_PIN, OUTPUT); pinMode(PAN_DIR, OUTPUT); pinMode(PAN_STEP, OUTPUT); pinMode(SLIDE_DIR, OUTPUT); pinMode(SLIDE_STEP, OUTPUT); pinMode(panLED_PIN, OUTPUT); pinMode(slideLED_PIN, OUTPUT); digitalWrite(SHUTTER_PIN, HIGH); pinMode(LIMIT_PIN, INPUT_PULLUP); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { state = nintendo.buttons(); while((state & NES_LEFT)) { state = nintendo.buttons(); if (!((state & NES_RIGHT)||(state & NES_UP)||(state & NES_DOWN)||(state & NES_B))) { 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_B))) { 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_B))) { state = NES_UP; slideMotorUp(); delay(RESPONSE); } } while((state & NES_DOWN)) { state = nintendo.buttons(); if (!((state & NES_LEFT)||(state & NES_RIGHT)||(state & NES_UP)||(state & NES_B))) { state = NES_DOWN; slideMotorDown(); delay(RESPONSE); } } if (state & NES_B) { pauseMotor(); } if (state & NES_A) { picture(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// while((state & NES_START)) { state = NES_START; for(int i=0; i<1000; i++) { state = nintendo.buttons(); if (!(state & NES_B)) //B will exit { for(int p=0; p<28; p++) //5 steps = 1mm { slideMotorUp(); delay(30); } picture(); delay(INTERVAL); } } } while((state & NES_SELECT)) //slide opposite direction as NES_START { state = NES_SELECT; for(int i=0; i<1000; i++) //3200steps=360deg { state = nintendo.buttons(); if (!(state & NES_B)) //B will exit { for(int p=0; p<28; p++) { slideMotorDown(); delay(30); } panMotorLeft(); 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 ); */ |