-
-
Save paschmann/cd9ef9464c15bd87c5750c834675660e to your computer and use it in GitHub Desktop.
A Small Arduino Project for a Slider/Pulley with a LCD, to control a stepper motor and fire a DSLR on set intervals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SoftwareSerial.h> | |
#include <AFMotor.h> | |
const int menubuttonPin = 16; // the pin that the menu pushbutton is attached to | |
const int selectbuttonPin = 15; // the pin that the pushbutton is attached to | |
const int optoPin = 17; | |
int menubuttonState = 0; // current state of the menu button | |
int selectbuttonState = 0; // current state of the select button | |
long motorSpeed = 10; // 1 rpm | |
int mode = 1; // 1 = movie (continuous), 2 = stop motion (stop and go), 3 = simple time lapse | |
int motorStep = 200; // divide 360 by the the stepper degrees ... 200 = default (1.8 degrees per step) | |
int maxRevs = 20; //default number of revolutions to make | |
int newMaxRevs = 0; //temp var to start at 0 for simplicity; | |
int remoteFire = 1; // If Stop Motion is enabled and remote fire, then the board will send a photo commmand when stopped | |
unsigned long timeDelay = 1000; // default time delay for stop motion 1000ms = 1s | |
int totalStops = 960; //default total stops for stop motion and time lapse | |
int countMaxRevs = 0; // set default for counting the max revs | |
int menuDelay = 300; //default refresh rate for program | |
int camDelay = 1000; // default amount of time for the camera to register the optocoupler (ensure the camera is pre-focused) | |
int stepType = 1; // Default step type = SINGLE (1), DOUBLE (2), MICROSTEP (3), INTERLEAVE (4) | |
int startDelay = 0; // Default ... delays the start of motion for ALL modes! | |
int newMotorStep = 0; // temp value to start at 1 for the count | |
int newMotorSpeed = 0; // temp value to start at 1 for the speed | |
int menuitem = 0; //default menu item | |
void(* resetFunc) (void) = 0; //declare reset function @ address 0 | |
//Setup LCD | |
#define txPin 14 | |
SoftwareSerial LCD = SoftwareSerial(0, txPin); | |
//Setup Stepper | |
AF_Stepper motor(motorStep, 2); | |
void setup() { | |
pinMode(menubuttonPin, INPUT); // initialize the button pin as a input: | |
pinMode(selectbuttonPin, INPUT); // initialize the button pin as a input: | |
pinMode(txPin, OUTPUT); // initialize the LCD screen | |
pinMode(optoPin, OUTPUT); // sets the digital pin as output for optocoupler | |
LCD.begin(9600); // Setup baud for LCD | |
motor.setSpeed(motorSpeed); // setup motor | |
backlightON(); | |
} | |
void loop() { | |
int totalRevs = 0; | |
// read the pushbutton input pin: | |
delay(menuDelay); | |
menubuttonState = digitalRead(menubuttonPin); | |
selectbuttonState = digitalRead(selectbuttonPin); | |
//Serial.print(menubuttonState); | |
// show menu | |
if (menubuttonState == 1){ | |
menuitem++; | |
} | |
if (menuitem == 21){ | |
//reinitialize menu item to go back to 0 | |
menuitem = 0; | |
} | |
switch (menuitem) | |
{ | |
case 0: | |
// This is the run & main menu. .... press select to start motion | |
clearLCD(); | |
writeStatus(0,0); | |
//LCD.print("test"); | |
//Calculate the total revolutions to make | |
totalRevs = motorStep * maxRevs; | |
//This is movie mode, do continuous motion | |
if (mode == 1){ | |
if (selectbuttonState == 1){ | |
for (int i = 1; i <= maxRevs; i++) | |
{ | |
//writeStatus(1,i); | |
motorGO(motorStep); | |
menubuttonState = digitalRead(menubuttonPin); | |
if (menubuttonState == 1){ | |
i = maxRevs; | |
} | |
} | |
} | |
} | |
if (mode == 2){ | |
if (selectbuttonState == 1){ | |
for (int i = 1; i <= totalStops; i++){ | |
int val = 0; | |
val = totalRevs/totalStops; | |
writeStatus(1,i); | |
motorGO(val); | |
//Short delay to stabilize before firing | |
delay(1000); | |
shootPIC(); | |
delay(timeDelay); | |
} | |
} | |
} | |
if (mode == 3){ | |
if (selectbuttonState == 1){ | |
for (int i = 1; i <= totalStops; i++){ | |
shootPIC(); | |
delay(timeDelay); | |
} | |
} | |
} | |
//Manual Mode - only move while select button is being pressed | |
if (mode == 4){ | |
menuDelay = 100; | |
while (selectbuttonState == 1){ | |
selectbuttonState = digitalRead(selectbuttonPin); | |
motorGO(motorStep); | |
} | |
menuDelay = 300; | |
} | |
motorSTOP(); | |
break; | |
case 1: | |
// Inform user of menu selection | |
clearLCD(); | |
LCD.print("Setup Menu ..."); | |
break; | |
case 2: | |
clearLCD(); | |
LCD.print("Mode: "); | |
if (selectbuttonState == 1){ | |
selectbuttonState = digitalRead(selectbuttonPin); | |
if (mode == 1){ | |
mode = 2; | |
}else if (mode == 2){ | |
mode = 3; | |
}else if (mode == 3){ | |
mode = 4; | |
}else{ | |
//reset to 0 | |
mode = 1; | |
} | |
} | |
if (mode == 1){ | |
LCD.print("1. Movie"); | |
}else if (mode == 2){ | |
LCD.print("2. Moving Intervalometer"); | |
}else if (mode == 3){ | |
LCD.print("3. Intervalometer"); | |
}else if (mode == 4){ | |
LCD.print("4. Manual"); | |
} | |
break; | |
case 3: | |
clearLCD(); | |
LCD.print("Speed: "); | |
if (selectbuttonState == 1){ | |
if (newMotorSpeed <= 24){ | |
newMotorSpeed = newMotorSpeed + 1; | |
}else if (newMotorSpeed <= 49){ | |
newMotorSpeed = newMotorSpeed + 5; | |
}else{ | |
newMotorSpeed = newMotorSpeed + 10; | |
} | |
motor.setSpeed(newMotorSpeed); | |
motorSpeed = newMotorSpeed; | |
} | |
LCD.print(motorSpeed); | |
break; | |
case 4: | |
clearLCD(); | |
LCD.print("Steps per Rev: "); | |
if (motorStep > 360){ | |
newMotorStep = 0; | |
} | |
if (selectbuttonState == 1){ | |
newMotorStep++; | |
//Update stepper setup to show new values | |
setupMotor(newMotorStep); | |
motorStep = newMotorStep; | |
} | |
LCD.print(motorStep); | |
break; | |
case 5: | |
clearLCD(); | |
LCD.print("Max Revs: "); | |
if (selectbuttonState == 1){ | |
newMaxRevs++; | |
maxRevs = newMaxRevs; | |
} | |
if (newMaxRevs > 1000){ | |
newMaxRevs = 0; | |
} | |
LCD.print(maxRevs); | |
break; | |
case 6: | |
clearLCD(); | |
LCD.print("Count Revs > "); | |
LCD.print(countMaxRevs); | |
if (selectbuttonState == 1){ | |
motorGO(motorStep); | |
countMaxRevs++; | |
} | |
motorSTOP(); | |
break; | |
case 7: | |
clearLCD(); | |
LCD.print("Step Type: "); | |
if (selectbuttonState == 1){ | |
if (stepType == 1){ | |
stepType = 2; | |
}else if (stepType == 2){ | |
stepType = 3; | |
}else if (stepType == 3){ | |
stepType = 4; | |
}else{ | |
//reset to 0 | |
stepType = 1; | |
} | |
} | |
if (stepType == 1){ | |
LCD.print("1. Single"); | |
}else if (stepType == 2){ | |
LCD.print("2. Double"); | |
}else if (stepType == 3){ | |
LCD.print("3. Microstep"); | |
}else if (stepType == 4){ | |
LCD.print("4. Interleave"); | |
} | |
break; | |
case 8: | |
clearLCD(); | |
LCD.print("Start Delay: "); | |
if (selectbuttonState == 1){ | |
if (startDelay <= 60000){ // 60 Seconds | |
// Add 1 second | |
startDelay = startDelay + 1000; | |
}else{ | |
// Add 60000 millieconds at a time (1 minute) | |
startDelay = startDelay + 60000; | |
} | |
} | |
if (startDelay <= 59999){ | |
LCD.print(startDelay/1000); | |
LCD.print(" sec"); | |
}else{ | |
LCD.print(startDelay/60000); | |
LCD.print(" min"); | |
} | |
break; | |
case 9: | |
clearLCD(); | |
LCD.print("Reset > "); | |
if (selectbuttonState == 1){ | |
resetFunc(); //call reset | |
} | |
break; | |
case 10: | |
clearLCD(); | |
LCD.print("Load Preset 1 "); | |
LCD.print("M:1 R:20 S:1000"); | |
if (selectbuttonState == 1){ | |
maxRevs = 20; | |
motorSpeed = 1000; | |
motor.setSpeed(motorSpeed); | |
mode = 1; | |
LCD.print("*"); | |
delay(1000); | |
} | |
break; | |
case 11: | |
clearLCD(); | |
LCD.print("Load Preset 2 "); | |
LCD.print("M:1 R:5 S:1000"); | |
if (selectbuttonState == 1){ | |
maxRevs = 5; | |
motorSpeed = 1000; | |
motor.setSpeed(motorSpeed); | |
mode = 1; | |
LCD.print("*"); | |
delay(1000); | |
} | |
break; | |
case 12: | |
clearLCD(); | |
LCD.print("Ld Preset 3 M:2 "); | |
LCD.print("R:20 P:1340 D:1s"); | |
if (selectbuttonState == 1){ | |
maxRevs = 20; | |
motorSpeed = 1; | |
motor.setSpeed(motorSpeed); | |
mode = 2; | |
timeDelay = 1; | |
totalStops = 1340; | |
LCD.print("*"); | |
delay(1000); | |
} | |
break; | |
case 13: | |
clearLCD(); | |
LCD.print("Ld Preset 4 M:2 "); | |
LCD.print("R:20 P:480 D:2s"); | |
if (selectbuttonState == 1){ | |
maxRevs = 20; | |
motorSpeed = 1; | |
motor.setSpeed(motorSpeed); | |
mode = 2; | |
//1 minute time delay | |
timeDelay = 2000; | |
totalStops = 480; | |
LCD.print("*"); | |
delay(1000); | |
} | |
break; | |
case 14: | |
clearLCD(); | |
LCD.print("Load Preset 5 "); | |
LCD.print("M:1 R:20 S:1"); | |
if (selectbuttonState == 1){ | |
maxRevs = 20; | |
motorSpeed = 1; | |
motor.setSpeed(motorSpeed); | |
mode = 1; | |
LCD.print("*"); | |
delay(1000); | |
} | |
break; | |
case 15: | |
// The following menus will only be displayed if mode 2, or 3 are active | |
if (mode == 2 || mode == 3){ | |
clearLCD(); | |
LCD.print("Inter. Menu..."); | |
}else{ | |
menuitem = 0; | |
} // end mode selection | |
break; | |
case 16: | |
clearLCD(); | |
LCD.print("Use remote fire?"); | |
if (selectbuttonState == 1){ | |
if (remoteFire == 0){ | |
remoteFire = 1; | |
}else{ | |
remoteFire = 0; | |
} | |
} | |
if (remoteFire == 0){ | |
LCD.print("Off"); | |
}else{ | |
LCD.print("On"); | |
} | |
break; | |
case 17: | |
clearLCD(); | |
LCD.print("Time Delay: "); | |
if (selectbuttonState == 1){ | |
if (timeDelay <= 60000){ // 60 Seconds | |
// Add 1 second | |
timeDelay = timeDelay + 1000; | |
}else{ | |
// Add 60000 millieconds at a time (1 minute) | |
timeDelay = timeDelay + 60000; | |
} | |
} | |
if (timeDelay <= 59999){ | |
LCD.print(timeDelay/1000); | |
LCD.print(" sec"); | |
}else{ | |
LCD.print(timeDelay/60000); | |
LCD.print(" min"); | |
} | |
break; | |
case 18: | |
clearLCD(); | |
LCD.print("Total Stops: "); | |
if (selectbuttonState == 1){ | |
if (totalStops <= 29) | |
{ | |
totalStops++; | |
}else{ | |
totalStops = totalStops + 10; | |
} | |
} | |
LCD.print(totalStops); | |
break; | |
case 19: | |
clearLCD(); | |
LCD.print("Cam Fire Delay: "); | |
if (selectbuttonState == 1){ | |
camDelay++; | |
} | |
LCD.print(camDelay); | |
break; | |
case 20: | |
clearLCD(); | |
LCD.print("Test Cam Fire > "); | |
if (selectbuttonState == 1){ | |
shootPIC(); | |
LCD.print("Fired"); | |
} | |
break; | |
} // Close case statement | |
} // Close loop statement | |
void setupMotor(int val){ | |
motor.release(); | |
AF_Stepper motor(val, 2); | |
motor.setSpeed(motorSpeed); | |
} | |
void clearLCD(){ | |
LCD.print(0xFE, BYTE); //command flag | |
LCD.print(0x01, BYTE); //clear command. | |
} | |
void writeStatus(int running,int i){ | |
clearLCD(); | |
if (running == 0) | |
{ | |
LCD.print("Run M:"); | |
}else{ | |
LCD.print("M:"); | |
} | |
LCD.print(mode); | |
LCD.print("S:"); | |
LCD.print(motorSpeed); | |
LCD.print(" R:"); | |
LCD.print(maxRevs); | |
LCD.print(" D:"); | |
LCD.print(startDelay); | |
//print the progress details | |
if (running == 1) | |
{ | |
LCD.print(" R="); | |
LCD.print(i); | |
LCD.print("/"); | |
if (mode == 1){ | |
LCD.print(maxRevs); | |
}else{ | |
LCD.print(totalStops); | |
} | |
} | |
} | |
void motorGO(int totalRevs){ | |
//LCD.print("*"); | |
if (stepType == 1){ | |
motor.step(totalRevs, FORWARD, SINGLE); | |
}else if (stepType == 2){ | |
motor.step(totalRevs, FORWARD, DOUBLE); | |
}else if (stepType == 3){ | |
motor.step(totalRevs, FORWARD, MICROSTEP); | |
}else{ | |
//reset to 0 | |
motor.step(totalRevs, FORWARD, INTERLEAVE); | |
} | |
} | |
void motorSTOP(){ | |
motor.release(); | |
} | |
void shootPIC(){ | |
if (remoteFire == 1){ | |
//LCD.print("*"); | |
digitalWrite(optoPin, HIGH); // sets the OPTO on | |
delay(camDelay); | |
digitalWrite(optoPin, LOW); // sets the OPTP to off | |
//delay | |
}else{ | |
clearLCD(); | |
LCD.print("Remote Fire Off"); | |
delay(2000); | |
} | |
} | |
// Turns the backlight on | |
void backlightON() { | |
LCD.print(0x7C, BYTE); //command flag for backlight stuff | |
LCD.print(157, BYTE); //light level. | |
} | |
// Turns the backlight off | |
void backlightOFF() { | |
LCD.print(0xFE, BYTE); | |
LCD.print(128, BYTE); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment