Hi everyone! I've been doing a lot of experimenting with the AccelStepper library, and I'm finally at a point where I can pretty reliably control my motors and tell them where to go.
The problem: If I want to program a sequence of movements, it is very cumbersome to write the code.
For example, if I want motorX to move to a position, when it's done, then motorY move to a position, then when it's done, do something else, etc....
I have to do something like
int phase = 0;
if(phase == 0)
{
//motor X do your thing
//when motorX is done...increment the phase
phase++;
}
else if(phase == 1)
{
//motor Y do your thing
//maybe activate a relay or turn on an LED light
//when motorY is done...increment the phase
phase++;
}
else if(phase == 2)
{
//do something else
//when you're done, increment the phase
phase++;
}
The above works fine (actual code example below). However,
- It is annoying to keep writing "else if(phase == 3), else if(phase == 4)....etc.
- If I later decide I want to edit my program and add a few steps somewhere in between, I have to re-number all the phases because I have changed how many phases there are!
The Question: is there a more efficient way to write this code and increment through phases/steps, so that once a particular phase is done, the code knows not to re-execute the already executed commands?
Code example:
//Read the potentiometer, map it to a program value between 1 and 5, and run that program using the Switch statement in the loop
//------PINOUT CONFIGURATION---------------
#define MOTOR_X_STEP_PIN 2 //2 on CNC shield v3
#define MOTOR_X_DIR_PIN 5 //5 on CNC shield v3
#define MOTOR_Y_STEP_PIN 3 //3 on CNC shield v3
#define MOTOR_Y_DIR_PIN 6 //6 on CNC shield v3
#define MOTOR_Z_STEP_PIN 4 //4 on CNC shield v3
#define MOTOR_Z_DIR_PIN 7 //7 on CNC shield v3
#define ENABLE_PIN 8 //enable pin to enable CNC shield v3 motors
int potentiometerPin = A0;
//-----STEPPER MOTOR SETUP-----
#include <AccelStepper.h>
AccelStepper motorX(1,MOTOR_X_STEP_PIN,MOTOR_X_DIR_PIN); // first argument "1" sets this as a "DRIVER", second argument is "step pin", third is "direction pin"
AccelStepper motorY(1,MOTOR_Y_STEP_PIN,MOTOR_Y_DIR_PIN);
AccelStepper motorZ(1,MOTOR_Z_STEP_PIN,MOTOR_Z_DIR_PIN);
int MAX_SPEED_X = 4000;
int MAX_SPEED_Y = 4000;
int MAX_SPEED_Z = 4000;
#define ACCELERATION_X 10000
#define ACCELERATION_Y 10000
#define ACCELERATION_Z 10000
//-----Custom Programs/Functions-----
int phase = 0; //variable to check what phase we are in the overall program, so we can tell the program to move to the next phase as each motor moves into its target position
bool allMovesComplete() //check if all motors have moved to where they should be
{
if(motorX.distanceToGo()== 0 && motorY.distanceToGo() == 0 && motorZ.distanceToGo() == 0)
{
return true;
}
else
{
return false;
}
}
int lastProgram = 0;
int program = 0; //
//program 1 = move the X motor to the right, then move X back to its original position
//program 2 = move X to the right, then move Y forward, then move Z down
//I can have as many programs as I want in the switch statement in the loop function
void setup() {
//Debugging (optional)
Serial.begin(115200);
//Stepper Motors Setup
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN, LOW); // enable "enable" pin
motorX.setMaxSpeed(MAX_SPEED_X);
motorX.setAcceleration(ACCELERATION_X);
motorY.setMaxSpeed(MAX_SPEED_Y);
motorY.setAcceleration(ACCELERATION_Y);
motorZ.setMaxSpeed(MAX_SPEED_Z);
motorZ.setAcceleration(ACCELERATION_Z);
motorX.setSpeed(MAX_SPEED_X);
motorY.setSpeed(MAX_SPEED_Y);
motorZ.setSpeed(MAX_SPEED_Z);
motorX.setCurrentPosition(0);
motorY.setCurrentPosition(0);
motorZ.setCurrentPosition(0);
}
void loop() {
program = map(analogRead(potentiometerPin),0,1023,1,5); //map the potentiometer value between programs 1 and 5 so that I can use my potentiometer to tell the software which program to run in the switch statement below
if(lastProgram != program) //if you change the potentiometer value and therefore the program changes, reset the phase back to 0 so the selected program starts from the beginning
{
lastProgram = program;
//Reset the phase so you can start at the beginning of another program
phase = 0;
//print the current program number in the Serial monitor for informational purposes
Serial.print("Program: ");
Serial.println(program);
}
switch(program)
{
case 1: //move the X motor to the right, then move X back to its original position
if(phase == 0)
{
motorX.moveTo(1000);
if(allMovesComplete())
{
phase++;
}
}
else if(phase == 1)
{
motorX.moveTo(0);
if(allMovesComplete())
{
phase++;
}
}
motorX.run();
break;
case 2: //move X to the right, then move Y forward, then move Z down
if(phase == 0)
{
motorX.moveTo(1000);
if(allMovesComplete())
{
phase++;
}
}
else if(phase == 1)
{
motorY.moveTo(500);
if(allMovesComplete())
{
phase++;
}
}
else if(phase == 2)
{
motorZ.moveTo(-500);
if(allMovesComplete())
{
phase++;
}
}
motorX.run();
motorY.run();
motorZ.run();
break;
case 3: //move all three motors to a location, and once they have all arrived, move them somewhere else
if(phase == 0)
{
motorX.moveTo(1000);
motorY.moveTo(500);
motorZ.moveTo(-50);
if(allMovesComplete())
{
phase++;
}
}
else if(phase == 1)
{
delay(1000); // wait 1 second before doing moving to the next phase
}
else if(phase == 2)
{
motorX.moveTo(0);
motorY.moveTo(0);
motorZ.moveTo(0);
if(allMovesComplete())
{
phase++;
}
}
motorX.run();
motorY.run();
motorZ.run();
break;
case 4:
//room for another program
break;
case 5:
//room for another program
break;
} //end of switch
} // end of main loop
Side note 1: moving motors may not be the only thing I'm doing in each "phase", maybe I want to turn on a relay, turn on an LED light, etc...so I need to be able to run several lines of code in each "phase".
Side note 2: I am intentionally NOT using any sort of blocking moves. (e.g. the AccelStepper runToNewPosition() function). For functional and for safety reasons, I should be able to perform other commands and/or change the program value at any time. If that wasn't a constraint, then it would be super simple to write something like:
case 2:
motorX.runToNewPosition(1000);
motorY.runToNewPosition(500);
motorZ.runToNewPosition(-500);
break;
..but unfortunately the above statements will block all other functions (since they cause each motor to run in a "while" loop), which is not acceptable for my application.
Any advice is appreciated!