Nov 032014
 

Code updated: 11/28 for bug fixes.

DIYTP_Finished

I needed to create a panner that would make 1 rotation over 5 minutes.

I discovered two other projects to base mine on. Construction is pretty much the same as the source projects below.

I rewrote some of the code. My TimeLapse Panner prompts for # of Rotations and Duration in minutes

Project Sources
Time_Lapse_Panner
Time_Lapse_Panner_PUBLIC_v2


Here are a list of Parts from V2.

Servocity

1 (SG804A – 4 inch Gearbox Arm
3 (535044 – .250 inch ID x .500 inch OD Flanged Ball Bearing
* I found this at SparkFun
1 (634074) 1/4 inch x 2.500 inch D-Shaft
1 (545588) (06.11.03) 1/4 inch Bore Clamping Hub
1 (RHA32-36-84) 84 Tooth, 32 Pitch Hub Gear (3/16 inch Face)
1 (585484) (03.11.03) 90 Degree Channel Bracket A
1 (585400) (09.12.02) Attachment Blocks (12 pack)
* I did not use these.
1 (585468) (04.11.01) Flat Single Channel Bracket
* I did not use this.
1 (ABS250-625-725) 6.25 inch x 7.25 inch ABS Sheet (1/4 inch Thick)
* I used .220 thick Acrylic sheet from HomeDepot.
4 (534-1857) 6-32x 2.50 inch Aluminum Standoffs (Round)
* I did not use these. I used 4 x 6-32 3-inch bolts.

EBAY
1 ULN2003 5v stepper motor
1 Axial Pinion Gear 32P 12T Steel 5mm Motor Shaft AX30838 NIB

HomeDepot
Misc 6-32 flat head screws and bolts (I used 1/2 lengths)

Amazon
1 SainSmart LCD 1602 Keypad Shield with Mega 2560 Arduino board
* The Mega board is probably overkill for this project.

Video

Wiring Diagram

Wiring

Sketch Code

// http://markwheeler.com/wordpress/?p=381

#include <LiquidCrystal.h>
#include <Stepper.h>
#include <Time.h>
#define STEPS 2048 //Number of steps per revolution

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Stepper small_stepper(STEPS, 1, 3, 2, 12);
int lcd_key = 0;
int adc_key_in = 0;
int endStep = 1;
int startPos = 0;
int curPos = 0;
float endPos = 14333;
int minutes = 0; // Duration
int endtime = 0;
int timeNow = 0;
float rotations = 0; // How many rotations?
float runtime = 0;
float span = 0;
float stepDelay = 0;
float spanRemain = 0;
int motorPWR = 15; // was 13
int time = 0; // clock holder
int runlength = 0;
int countdown = 10; // Seconds until program runs

#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5

int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
// For V1.1 us this threshold
if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 250) return btnUP; if (adc_key_in < 450) return btnDOWN; if (adc_key_in < 650) return btnLEFT; if (adc_key_in < 850) return btnSELECT; return btnNONE; // when all others fail, return this... } void setup(){ lcd.begin (16,2); pinMode(motorPWR, OUTPUT); } void loop(){ digitalWrite(motorPWR, HIGH); while(endStep){ // I do this for no reason. lcd.setCursor(0,0); lcd.print("TimeLapse Panner"); lcd.setCursor(0,1); lcd.print("v3.11282014"); delay(2000); time_t timeNow = now(); // What time is it right now? endStep = 0; } endStep = 1; // Ask for Rotations lcd.setCursor(0,0); lcd.print("Rotations: "); lcd.setCursor(0,1); lcd.print("(L/R) then SEL"); while(endStep){ lcd_key = read_LCD_buttons(); // read the buttons switch (lcd_key) // depending on which button was pushed, we perform an action { case btnRIGHT: { rotations = rotations + 1; lcd.setCursor(0,1); lcd.print("Rotations: "); lcd.setCursor(11,1); lcd.print(rotations); delay(175); break; } case btnLEFT: { rotations = rotations - 1; lcd.setCursor(0,1); lcd.print("Rotations: "); lcd.setCursor(11,1); lcd.print(rotations); delay(175); break; } case btnSELECT: { endStep = 0; delay(175); break; } case btnNONE: { break; } } } endStep = 1; // Ask for Duration lcd.setCursor(0,0); lcd.print("Duration: "); lcd.setCursor(0,1); lcd.print("(L/R) then SEL"); while(endStep){ lcd_key = read_LCD_buttons(); // read the buttons switch (lcd_key) // depending on which button was pushed, we perform an action { case btnRIGHT: { minutes = minutes + 1; lcd.setCursor(0,1); lcd.print("Minutes: "); lcd.setCursor(11,1); lcd.print(minutes); delay(175); break; } case btnLEFT: { minutes = minutes - 1; lcd.setCursor(0,1); lcd.print("Minutes: "); lcd.setCursor(11,1); lcd.print(minutes); delay(175); break; } case btnSELECT: { endStep = 0; // Countdown while (countdown) { lcd.clear(); lcd.setCursor(0,1); lcd.print("Countdown: "); lcd.setCursor(12,1); lcd.print(countdown); delay (1000); countdown = countdown - 1; } delay(150); break; } case btnNONE: { break; } } } runtime = (minutes * 60000); lcd.setCursor(0,0); lcd.print("Rot "); lcd.print(rotations); lcd.print("x - "); lcd.print(minutes); lcd.print("mins"); lcd.setCursor(0,1); lcd.print(" secs left"); if (rotations > 0) {
span = (endPos * rotations) - curPos;
spanRemain = span;
stepDelay = (runtime / span);
// small_stepper.step(span * -1);
while (spanRemain) {
// small_stepper.step(1); // Counterclockwise
small_stepper.step(-1); // Clockwise

runtime = (runtime - stepDelay);
// test for seconds left length
runlength = ((runtime / 1000) + 1);
if (runlength >= 100) {
lcd.setCursor(0,1);
} if (runlength >= 10 and runlength <= 99) { lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(1,1); } else { lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(2,1); } lcd.print((runtime / 1000) + 1 ); // time = millis(); // lcd.print( ( (minutes*60000) - (time) ) / 1000); // Not totally accurate. Fix me. // lcd.print(endtime - second(now())); spanRemain--; // curPos = curPos + 1; delay(stepDelay); } rotations = rotations - 1; } endStep = 0; while(1){ lcd.setCursor(0,0); lcd.print(" "); lcd.setCursor(0,1); lcd.print("Program Complete"); delay(500); lcd.setCursor(0,0); lcd.print("Program Complete"); lcd.setCursor(0,1); lcd.print(" "); delay(500); } }

Download Time_Lapse_Panner_v3.zip