Hello,
I'm working on a project that controls 2 steppers in parallel (same exact movement for each), that will be controlled using serial commands from Python via a Python GUI to control a linear stage. It is mostly working very well - however, I am running into 2 issues:
1 (most important): The Home position for the steppers resets when I close/open a serial connection via either Arduino IDE or using python serial module. That is to say, every time I open a serial connection, it says that the current location is the home position. I then effectively lose the positional encoding of my linear stages. If this home position is being stored by the accelstepper library, why would simply opening/closing serial connection change that?
2 (less important): I initially setup the code for 1 stepper, and then duplicated the commands to deal with the 2nd stepper as well. However, with both steppers running, they run significantly more slowly than when I just run 1 stepper. I've ensured that it is not a power supply issue, so I'm not really sure why this is happening.
Below is my code:
//Transforming the motor's rotary motion into linear motion by using a threaded rod:
//Threaded rod's pitch = 2 mm. This means that one revolution will move the nut 2 mm.
//Default stepping = 200 step/revolution.
// 20000 step = 1 revolution = 8 mm linear motion. (4 start 2 mm pitch screw, with 100:1 gearbox)
// 1 cm = 10 mm =>> 10/8 * 20000 = 25000 steps are needed to move the nut by 1 cm.
//character for commands
/*
'C' : Prints all the commands and their functions.
'P' : Rotates the motor in positive (CW) direction, relative.
'N' : Rotates the motor in negative (CCW) direction, relative.
'R' : Rotates the motor to an absolute positive position (+).
'r' : Rotates the motor to an absolute negative position (-).
'S' : Stops the motor immediately.
'A' : Sets an acceleration value.
'L' : Prints the current position/location of the motor.
'H' : Goes back to 0 position from the current position (homing).
'U' : Updates the position current position and makes it as the new 0 position.
'T' : Checks to see if the motor is running (to know if new commands can be sent
*/
#include <AccelStepper.h>
#include <MultiStepper.h>
//User-defined values
long receivedSteps = 0; //Number of steps
long receivedSpeed = 0; //Steps / second
long receivedAcceleration = 0; //Steps / second^2
char receivedCommand;
bool isrunning1 = false;
bool isrunning2 = false;
bool bool_out = false;
//-------------------------------------------------------------------------------
int directionMultiplier = 1; // = 1: positive direction, = -1: negative direction
bool newData, runallowed = true; // booleans for new data from serial, and runallowed flag
AccelStepper stepper1(1, 9, 8);//
AccelStepper stepper2(1, 6, 7);//
MultiStepper steppers;
void setup()
{
Serial.begin(9600); //define baud rate
//Serial.println("Demonstration of AccelStepper Library"); //print a messages
//Serial.println("Send 'C' for printing the commands.");
//setting up some default values for maximum speed and maximum acceleration
//Serial.println("Default speed: 400 steps/s, default acceleration: 800 steps/s^2.");
stepper1.setMaxSpeed(10000); //SPEED = Steps / second
stepper1.setAcceleration(10000); //ACCELERATION = Steps /(second)^2
stepper2.setMaxSpeed(10000); //SPEED = Steps / second
stepper2.setAcceleration(10000); //ACCELERATION = Steps /(second)^2
}
void loop()
{
//Constantly looping through these 2 functions.
//We only use non-blocking commands, so something else (should also be non-blocking) can be done during the movement of the motor
checkSerial(); //check serial port for new commands
stepper1.run();
stepper2.run();
}
void checkSerial() //function for receiving the commands
{
if (Serial.available() > 0) //if something comes from the computer
{
receivedCommand = Serial.read(); // pass the value to the receivedCommad variable
newData = true; //indicate that there is a new data by setting this bool to true
if (newData == true) //we only enter this long switch-case statement if there is a new command from the computer
{
switch (receivedCommand) //we check what is the command
{
case 'P': //P uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
directionMultiplier = 1; //We define the direction
RotateRelative(); //Run the function
//example: P2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 400 steps/s speed
//In theory, this movement should take 5 seconds
break;
case 'N': //N uses the move() function of the AccelStepper library, which means that it moves relatively to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
directionMultiplier = -1; //We define the direction
RotateRelative(); //Run the function
//example: N2000 400 - 2000 steps (5 revolution with 400 step/rev microstepping) and 500 steps/s speed; will rotate in the other direction
//In theory, this movement should take 5 seconds
break;
case 'R': //R uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
directionMultiplier = 1; //We define the direction
RotateAbsolute(); //Run the function
//example: R800 400 - It moves to the position which is located at +800 steps away from 0.
break;
case 'r': //r uses the moveTo() function of the AccelStepper library, which means that it moves absolutely to the current position.
receivedSteps = Serial.parseFloat(); //value for the steps
directionMultiplier = -1; //We define the direction
RotateAbsolute(); //Run the function
//example: r800 400 - It moves to the position which is located at -800 steps away from 0.
break;
case 'S': // Stops the motor
stepper1.stop(); //stop motor
stepper2.stop(); //stop motor
Serial.println("Stopped."); //print action
break;
case 'A': // Updates acceleration
receivedAcceleration = Serial.parseFloat(); //receive the acceleration from serial
stepper1.setAcceleration(receivedAcceleration); //update the value of the variable
stepper2.setAcceleration(receivedAcceleration); //update the value of the variable
break;
case 'L': //L: Location
Serial.println(stepper1.currentPosition()); //Printing the current position in steps.
break;
case 'H': //H: Homing
GoHome();// Run the function
break;
case 'U':
stepper1.setCurrentPosition(0); //Reset current position. "new home"
stepper2.setCurrentPosition(0); //Reset current position. "new home"
Serial.println("New Home Position Set");
break;
case 'T':
isrunning1 = stepper1.isRunning();
isrunning2 = stepper2.isRunning();
bool_out = (isrunning1 || isrunning2);
Serial.println(bool_out);
break;
case 'C':
PrintCommands(); //Print the commands for controlling the motor
break;
default:
break;
}
}
//after we went through the above tasks, newData is set to false again, so we are ready to receive new commands again.
newData = false;
}
}
void GoHome()
{
if (stepper1.currentPosition() == 0)
{
Serial.println("We are at the home position.");
}
else
{
stepper1.moveTo(0);
stepper2.moveTo(0);
}
}
void RotateRelative()
{
//We move X steps from the current position of the stepper motor in a given direction.
//The direction is determined by the multiplier (+1 or -1)
stepper1.move(directionMultiplier * receivedSteps); //set relative distance and direction
stepper2.move(directionMultiplier * receivedSteps); //set relative distance and direction
}
void RotateAbsolute()
{
//We move to an absolute position.
//The AccelStepper library keeps track of the position.
//The direction is determined by the multiplier (+1 or -1)
//Why do we need negative numbers? - If you drive a threaded rod and the zero position is in the middle of the rod...
stepper1.moveTo(directionMultiplier * receivedSteps);
stepper2.moveTo(directionMultiplier * receivedSteps);
}
void PrintCommands()
{
//Printing the commands
Serial.println(" 'C' : Prints all the commands and their functions.");
Serial.println(" 'P' : Rotates the motor in positive (CW) direction, relative.");
Serial.println(" 'N' : Rotates the motor in negative (CCW) direction, relative.");
Serial.println(" 'R' : Rotates the motor to an absolute positive position (+).");
Serial.println(" 'r' : Rotates the motor to an absolute negative position (-).");
Serial.println(" 'S' : Stops the motor immediately.");
Serial.println(" 'A' : Sets an acceleration value.");
Serial.println(" 'L' : Prints the current position/location of the motor.");
Serial.println(" 'H' : Goes back to 0 position from the current position (homing).");
Serial.println(" 'U' : Updates the position current position and makes it as the new 0 position. ");
I am using the following stepper driver (x2):
The following stepper motor (x2):
With a 48V, 20A power supply.
Thank you for your help!