This is a my current code for a camera motion control unit (previously posted in Arduino section) I'm trying to work out how to add another motor (can do that physically to the shield i know) and another menu setting to control it in the one that already exists. The extra setting would be to control the second stepper by moving it a certain amount (maybe the menu setting in steps similar to the other) and when the program ends, both steppers stop as per the current sketch. Make sense?! :)
Code: Select all
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#define LCD_BACKLIGHT_OFF() digitalWrite( LCD_BACKLIGHT_PIN, LOW )
#define LCD_BACKLIGHT_ON() digitalWrite( LCD_BACKLIGHT_PIN, HIGH )
#define LCD_BACKLIGHT(state) { if( state ){digitalWrite( LCD_BACKLIGHT_PIN, HIGH );}else{digitalWrite( LCD_BACKLIGHT_PIN, LOW );} }
#define LCD_BACKLIGHT_PIN 10 // D10 controls LCD backlight
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myStepper1 = AFMS.getStepper(200, 2);
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
void forwardstep1()
{
myStepper1->onestep(FORWARD, DOUBLE);
}
void backwardstep1()
{
myStepper1->onestep(BACKWARD, DOUBLE);
myStepper1->setSpeed(12); // 12 rpm
}
AccelStepper Astepper1(forwardstep1, backwardstep1); // use functions to step
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7); //set LCD output pins
//define trigger pin
const int trig = 3;
// define limit switches
const int limitSwitchA = 2;
const int limitSwitchB = 1;
//BUTTONS
//define button values
const int btnUp = 0;
const int btnDn = 1;
const int btnL = 2;
const int btnR = 3;
const int btnSel = 4;
const int btnNone = 5;
//define button-reading variables
int btnVal = 5;
int adcIn = 0;
//declare button poll function
int readLcdButtons() {
delay(65); //debounce delay, tuned experimentally. delay is fine as program shouldn't be doing anything else
//at this point anyway
adcIn = analogRead(0); //read value from pin A0
/*threshold values confirmed by experimentation with button calibration sketch returning the following ADC read values:
right: 0
up: 144
down: 327
left: 508
select: 742
*/
if (adcIn > 1000) return btnNone;
if (adcIn < 25) return btnR;
if (adcIn < 170) return btnUp;
if (adcIn < 350) return btnDn;
if (adcIn < 550) return btnL;
if (adcIn < 750) return btnSel;
return btnNone; //if it can't detect anything, return no button pressed
}
//MENU GUI
//define top-level menu item strings for numerical navigation
char* menuItemsTop[] = {
" 01 Distance >", "< 02 Duration >", "< 03 Steps > ", "< 04 Direction >", "< 05 Pause > ", "< 06 Start > "};
int currentMenuLevel = 0; //top menu or submenu
int currentMenuItem = 0; //x-axis position of menu selection
int currentCursorPos = 0; //current lcd cursor position
int currentDistance[4] = {
0, 0, 0, 0};
int currentDuration[6] = {
0, 0, 0, 0, 0, 0};
int currentSteps[4] = {
0, 0, 0, 1};
int currentShutter[6] = {
0, 0, 0, 0, 0, 0};
//MENU FUNCTIONALITY
int currentChar = 0; //global declarations of array-parsing variables
int update = 0;
double ThtuArr[] = {
0000, 000, 00, 0};
double HTThtuArr[] = {
000000, 00000, 0000, 000, 00, 0};
double currentDistanceInt = 0000;
double currentDurationInt = 000000;
double currentStepsInt = 0001;
double currentShutterInt = 000000;
int travelDir = 0;
int adjustDigit(int x, int dir){ //digit adjust function
if (dir == 0 && x > 0) x--; //subtract from digit on btnDn
if (dir == 1 && x < 9) x++; // add to digit on btnUp
lcd.setCursor(currentCursorPos, 1);
lcd.print(x);
currentChar = x;
return currentChar; //return new digit
}
int parseArrayDistance(){
for (int i = 0; i < 4; i++) {
ThtuArr[i] = currentDistance[i] * (pow (10, (3-i))); //pow() returns a DOUBLE so ensure relevant vars are also double before passing off!
}
currentDistanceInt = ThtuArr[0] + ThtuArr[1] + ThtuArr[2] + ThtuArr[3];
update = currentDistanceInt;
return update;
}
int parseArrayDuration(){
for (int i = 0; i < 6; i++) {
currentChar = currentDuration[i];
HTThtuArr[i] = currentChar * pow (10, (5-i));
}
currentDurationInt = HTThtuArr[0] + HTThtuArr[1] + HTThtuArr[2] + HTThtuArr[3] + HTThtuArr[4] + HTThtuArr[5];
update = currentDurationInt;
return update;
}
int parseArraySteps(){
for (int i = 0; i < 4; i++) {
currentChar = currentSteps[i];
ThtuArr[i] = currentChar * pow (10, (3-i));
}
currentStepsInt = ThtuArr[0] + ThtuArr[1] + ThtuArr[2] + ThtuArr[3];
update = currentStepsInt;
return update;
}
int parseArrayShutter(){
Serial.begin(9600); // set up Serial library at 9600 bps
for (int i = 0; i < 6; i++) {
currentChar = currentShutter[i];
HTThtuArr[i] = currentChar * pow (10, (5-i));
}
currentShutterInt = HTThtuArr[0] + HTThtuArr[1] + HTThtuArr[2] + HTThtuArr[3] + HTThtuArr[4] + HTThtuArr[5];
update = currentShutterInt;
Serial.println(currentShutterInt);
return update;
}
//MOTION CONTROL
double totalMotorSteps = 0;
double pulseDelay = 0;
int intervalDistance = 0; //number of motor steps contained within a camera step
int currentStep = 0; //number of motor steps thus far
int motion = 0; // motion = 1 if stop hasn't been pressed
int shutterDuration = 5; //length of time for the camera to stop at shot steps in seconds
int motionControl() {
Serial.begin(9600); // set up Serial library at 9600 bps
totalMotorSteps = currentDistanceInt * 5 //calculate total steps (16-tooth gear on 2mm pitch belt; 200 steps, ergo 1/16th mm per step)
;pulseDelay = (1000L * (currentDurationInt - (currentStepsInt * shutterDuration))) / totalMotorSteps; //how long to pause in ms between STP pulses to the motor driver
intervalDistance = totalMotorSteps / currentStepsInt;
//once per overall run
if (travelDir == FORWARD) myStepper1->onestep(FORWARD, DOUBLE);
else if (travelDir == BACKWARD) myStepper1->onestep(BACKWARD, DOUBLE);
//step loop
do {
myStepper1->onestep(travelDir, DOUBLE);//fire motor driver step
Serial.println(pulseDelay);
delay(pulseDelay);
//btnVal = readLcdButtons(); //check there's no stoppage - this takes too long and significantly slows motor; use reset for stop!
currentStep++;
//at end of each step
if (currentStep % intervalDistance == 0) { //if current number of motor steps is divisible by the number of motor steps in a camera step, fire the camera
Serial.println(trig, HIGH);
delay(750);
digitalWrite(trig, HIGH); //trigger camera shutter
delay(500);
digitalWrite(trig, LOW); //reset trigger pin
delay((shutterDuration * 1000)-80); //delay needs changing to timer so stop button can be polled
}
}
while ((currentStep < totalMotorSteps) && (digitalRead(limitSwitchA) == HIGH) && (digitalRead(limitSwitchB) == HIGH));
} //end motion control
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode (limitSwitchA, INPUT_PULLUP);
pinMode (limitSwitchB, INPUT_PULLUP);
lcd.begin(16, 2); // initialise LCD lib full-screen
lcd.setCursor(0,0); // set cursor position
digitalWrite( LCD_BACKLIGHT_PIN, HIGH );
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1600); // OR with a different frequency, say 1KHz
myStepper1->setSpeed(12); // 12 rpm
pinMode(trig, OUTPUT); //initialise trigger pin
digitalWrite(trig, LOW); //ensure trigger is turned off
lcd.print("ISO 100"); //welcome screen
lcd.setCursor(0,1);
lcd.print("MOTION CONTROL");
delay(1000);
lcd.clear();
lcd.print(menuItemsTop[0]);
delay(100);
lcd.setCursor(0,1);
for (int i = 0; i < 4; i++) {
lcd.setCursor(i, 1);
lcd.print(currentDistance[i]);
}
lcd.setCursor(4,1);
lcd.print("mm(max 1300)");
}
//MAIN LOOP
void loop() {
do {
btnVal = readLcdButtons(); //continually read the buttons...
}
while (btnVal==5); //...until something is pressed
if (currentMenuLevel==0) {
switch (btnVal){
case btnL:
{
if (currentMenuItem == 0) break; //can't go left from here
else currentMenuItem--;
break;
}
case btnR:
{
if (currentMenuItem == 5) break; //can't go right from here
else currentMenuItem++;
break;
}
case btnSel:
{
currentMenuLevel++;
if (currentCursorPos > 3 && (currentMenuItem == 0 || currentMenuItem == 2)) currentCursorPos = 3; //don't go off the end of the numbers for the 4-digit numbers
if (currentCursorPos > 0 && (currentMenuItem > 2)) currentCursorPos = 0; // set blinking cursor to left for text-based options
if (currentMenuItem == 5) {
motion = 1;
motionControl();
break;
}
}
} //end of switch
} //end of level 0
else { // i.e. "else if currentMenuLevel = 1"
if (currentMenuItem == 0) { //01 DISTANCE
switch (btnVal) {
case btnUp:
{
currentChar = currentDistance[currentCursorPos];
adjustDigit(currentChar, 1);
currentDistance[currentCursorPos] = currentChar;
break;
}
case btnDn:
{
currentChar = currentDistance[currentCursorPos];
adjustDigit(currentChar, 0);
currentDistance[currentCursorPos] = currentChar;
break;
}
case btnL:
{
if (currentCursorPos == 0) break; //can't go left from here
else currentCursorPos--;
break;
}
case btnR:
{
if (currentCursorPos == 3) break; //can't go left from here
else currentCursorPos++;
break;
}
case btnSel:
{
parseArrayDistance();
currentMenuLevel--;
}
} //end switch
} //end DISTANCE
else if (currentMenuItem == 1) { //02 DURATION
switch (btnVal) {
case btnUp:
{
currentChar = currentDuration[currentCursorPos];
adjustDigit(currentChar, 1);
currentDuration[currentCursorPos] = currentChar;
break;
}
case btnDn:
{
currentChar = currentDuration[currentCursorPos];
adjustDigit(currentChar, 0);
currentDuration[currentCursorPos] = currentChar;
break;
}
case btnL:
{
if (currentCursorPos == 0) break; //can't go left from here
else currentCursorPos--;
break;
}
case btnR:
{
if (currentCursorPos == 5) break; //can't go left from here
else currentCursorPos++;
break;
}
case btnSel:
{
parseArrayDuration();
currentMenuLevel--;
}
} //end switch
} //end 02 DURATION
else if (currentMenuItem == 2) { //03 STEPS
switch (btnVal) {
case btnUp:
{
currentChar = currentSteps[currentCursorPos];
adjustDigit(currentChar, 1);
currentSteps[currentCursorPos] = currentChar;
break;
}
case btnDn:
{
currentChar = currentSteps[currentCursorPos];
adjustDigit(currentChar, 0);
currentSteps[currentCursorPos] = currentChar;
break;
}
case btnL:
{
if (currentCursorPos == 0) break; //can't go left from here
else currentCursorPos--;
break;
}
case btnR:
{
if (currentCursorPos == 3) break; //can't go left from here
else currentCursorPos++;
break;
}
case btnSel:
{
parseArraySteps();
currentMenuLevel--;
}
} //end switch
} //end 03 STEPS
else if (currentMenuItem == 3) { //04 DIRECTION
Serial.begin(9600); // set up Serial library at 9600 bps
switch (btnVal) {
case btnUp:
{
travelDir = FORWARD;
break;
}
case btnDn:
{
travelDir = BACKWARD;
break;
}
case btnSel:
{
currentMenuLevel--;
}
} //end switch
} //end 04 DIRECTION
else if (currentMenuItem == 4) { //05 PAUSE
switch (btnVal) {
case btnUp:
{
currentChar = currentShutter[currentCursorPos];
adjustDigit(currentChar, 1);
currentShutter[currentCursorPos] = currentChar;
break;
}
case btnDn:
{
currentChar = currentShutter[currentCursorPos];
adjustDigit(currentChar, 0);
currentShutter[currentCursorPos] = currentChar;
break;
}
case btnL:
{
if (currentCursorPos == 0) break; //can't go left from here
else currentCursorPos--;
break;
}
case btnR:
{
if (currentCursorPos == 5) break; //can't go left from here
else currentCursorPos++;
break;
}
case btnSel:
{
shutterDuration = parseArrayShutter();
currentMenuLevel--;
}
} //end switch
} //end 05 PAUSE
else if (currentMenuItem == 5) { // 06 GO
switch (btnVal) {
case btnUp:
{
break;
}
case btnDn:
{
break;
}
case btnL:
{
break;
}
case btnR:
{
break;
}
case btnSel:
{
currentMenuLevel--;
break;
}
} //end switch
} //end 06 GO
} //end of level 1
//PRINT NEW SCREEN VALUES
btnVal=btnNone;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(menuItemsTop[currentMenuItem]); //print top level menu item
lcd.setCursor(0,1);
switch (currentMenuItem) {
case 0:
{
for (int i = 0; i < 4; i++) {
lcd.setCursor(i, 1);
lcd.print(currentDistance[i]);
}
break;
}
case 1:
{
for (int i = 0; i < 6; i++) {
lcd.setCursor(i, 1);
lcd.print(currentDuration[i]);
}
break;
}
case 2:
{
for (int i = 0; i < 4; i++) {
lcd.setCursor(i, 1);
lcd.print(currentSteps[i]);
}
break;
}
case 3:
{
if (travelDir == 0) lcd.print("AWAY FROM MOTOR");
else lcd.print("TOWARDS MOTOR");
break;
}
case 4:
{
for (int i = 0; i < 6; i++) {
lcd.setCursor(i, 1);
lcd.print(currentShutter[i]);
}
break;
}
case 5:
{
lcd.print("END PROGRAM");
break;
}
} //end switch
if (currentMenuItem==0){
lcd.setCursor(4,1);
lcd.print("mm(max 1300)"); //insert max carriage travel on slider used
}
if (currentMenuItem==1){
lcd.setCursor(6,1);
lcd.print("s(3600/hr)");
}
if (currentMenuLevel == 1) {
lcd.setCursor(currentCursorPos, 1);
lcd.blink();
}
else lcd.noBlink();
} //END OF PROGRAM