Skip to content

Instantly share code, notes, and snippets.

@paschmann
Created November 10, 2023 17:26
Show Gist options
  • Save paschmann/cd9ef9464c15bd87c5750c834675660e to your computer and use it in GitHub Desktop.
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
#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