Controlling stepper motors via serial monitor - AccelStepper library

Hey all,

Am trying to control two separate stepper motors via commands from the serial monitor. Am keeping it simple at the start and just try to send one of two commands, either make stepper 1 turn, or make stepper 2 turn. Have butchered the multiple stepper example with some bits to add serial communication.

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(360);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(360);
}
   
    String inBuffer = "";

void loop()
{
    while (Serial.available())
    {
      char c = Serial.read();
      inBuffer += c;
    }
    
    //byte incomingByte = Serial.read();
   
    if (inBuffer == "servo1")
    {
      Serial.println("test point 1");
      //if (stepper1.distanceToGo() == 0)
      Serial.println("test point 2");
      stepper1.moveTo(-stepper1.currentPosition());
      stepper1.run();
    }
    
    else if (inBuffer == "servo2")
    {
       Serial.println("test point 3");      
       //if (stepper2.distanceToGo() == 0)
       Serial.println("test point 4");
       stepper2.moveTo(-stepper2.currentPosition());
       stepper2.run();
    }
    
    inBuffer = "";
}

If for example, I send "servo1", I will get both test point checks being sent back, however, I am getting zero movement from the steppers. Have had a look at some other examples online of people doing similar, but wasnt able to find one with the same Accellibrary being used.

Thanks for the help, all the best!

Have you been able to get the motor to move with one of the examples from the AccelStepper library?

If not, do that first so you are just focused on a single problem.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

When using Cstrings you must use strcmp() to compare values rather than ==

And have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

You will make your Arduino program much easier to develop if you just send single character commands. Using the alphanumeric characters you can have 62 separate single character commands. If you need to send a command and a value (such as the number of steps) I recommend using the technique in the 3rd example in Serial Input Basics.

...R
Stepper Motor Basics
Simple Stepper Code

Cheers for the reply Robin2, I had managed to get the example working before I started trying to make adjustments.

Took out the strings and have made the checks just look for single character commands, also have tried implementing string compares, but I think I may be screwing up the syntax of them a little bit. I haven't done a lot of work with sending data via serial monitor before, but will read the sites and threads you sent over, thanks for that.

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(360);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(360);
}
   
    char inBuffer = "";

void loop()
{
    while (Serial.available())
    {
      inBuffer = Serial.read();
    }
    
    //byte incomingByte = Serial.read();
       
    if (strcmp(inBuffer,"a")==0)
    {
      Serial.println("test point 1");
      //if (stepper1.distanceToGo() == 0)
      stepper1.moveTo(-stepper1.currentPosition());
      stepper1.run();
    }
    
    else if (strcmp(inBuffer,"b")==0)
    {
       Serial.println("test point 2");      
       //if (stepper2.distanceToGo() == 0)
       stepper2.moveTo(-stepper2.currentPosition());
       stepper2.run();
    }
    
    //inBuffer = "";
}

Is this the correct way of doing the strcmp or does it need to be done this way?

result = strcmp(example1, example2);

    if (result == 0)

For the moment, I just want to get to the point where sending "a" makes stepper one move, and sending "b", makes stepper two move. Although, in the future I will need to be able to send the number of steps so will give example 3 a look.

Thanks for the help!

If you are just using single character commands you can use == For example

if (inBuffer == 'a') {

Note, especially, the use of single quotes for single characters.

For future reference the cstring "a" would be comprised of the characters 'a' and '\0'

And this

char inBuffer = "";

should just be

char inBuffer;

and then this

    while (Serial.available())

should be

    if (Serial.available())

because you just want to read a single character

You should not have the line

stepper1.run();

inside any IF statement. It should just be called directly from loop()

...R

Thanks again for the help, in its current state, each time I send an 'a' or a 'b', it moves the respective stepper motor by one step. Although, as you can probably tell from the code, I am trying to get them to do full rotations not just single steps.

I am guessing the issue is due to the stepper1.run() and stepper2.run() being inside an IF statement, so only incrementing by a single step each time. I am unsure of how to rectify this though, how can I take them out of the IF and still keep the check in place?

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(360);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(360);
}
   
    char inBuffer = "";

void loop()
{
    if(Serial.available()>0)
    {
      inBuffer = Serial.read();
    }
    
    //byte incomingByte = Serial.read();
       
    if (inBuffer == 'a')
    {
      Serial.println("test point 1");
      if (stepper1.distanceToGo() == 0)
      stepper1.moveTo(-stepper1.currentPosition());
      stepper1.run();
    }
    
    else if (inBuffer == 'b')
    {
       Serial.println("test point 2");      
       if (stepper2.distanceToGo() == 0)
       stepper2.moveTo(-stepper2.currentPosition());
       stepper2.run();
    }
    
    inBuffer = "";
}

chickwolf:
I am unsure of how to rectify this though, how can I take them out of the IF and still keep the check in place?

Keep what check in place?

What happened when you moved stepper1.run() so it is in loop() and then tried the program?

The Arduino is a great system for learning-by-doing.

...R

Stuck the stepper.run in the main code, it is responding to the serial monitor and doing what I want now. However, every time the code is loaded onto the Arduino, both steppers do a half turn in the same direction?

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

int movement = 360;

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(movement);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(movement);
}
   
    char inBuffer = "";

void loop()
{
    if(Serial.available()>0)
    {
      inBuffer = Serial.read();
    }
       
    if (inBuffer == 'a')
    {
      Serial.println("test point 1");
      if (stepper1.distanceToGo() == 0)
      stepper1.moveTo(-stepper1.currentPosition());
    }
    
    
    if (inBuffer == 'b')
    {
       Serial.println("test point 2");      
       if (stepper2.distanceToGo() == 0)
       stepper2.moveTo(-stepper2.currentPosition());
    }
    
    stepper1.run();
    stepper2.run();
    inBuffer = "";
}

How would you recommend getting around this issue?

Robin2:
The Arduino is a great system for learning-by-doing.

Incredible!

chickwolf:
How would you recommend getting around this issue?

Think about what is causing that to happen.

I suspect if you remove the lines

stepper1.moveTo(movement);

from setup() there will be no movement

...R

Tried removing the

stepper.1moveTo(movement)

from the code and it ddn't work at all. Also tried adding a small one time only delay at the start but that did nothing either. If it helps, this is the library I am using.

chickwolf:
Tried removing the

stepper.1moveTo(movement)

from the code and it ddn't work at all. Also tried adding a small one time only delay at the start but that did nothing either.

When you make changes to a program you need to include the latest version of the program with your comments - otherwise we have no idea what you have done. My guess is that you removed the code from the wrong place.

...R

My apologies

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

int movement = 360;
int start_var = 0;

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(movement);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(movement);
}
   
    char inBuffer = "";

void loop()
{
   
    if(Serial.available()>0)
    {
      inBuffer = Serial.read();
    }
       
    if (inBuffer == 'a')
    {
      Serial.println("test point 1");
      if (stepper1.distanceToGo() == 0)
      stepper1.moveTo(-stepper1.currentPosition());
    }
    
    
    if (inBuffer == 'b')
    {
       Serial.println("test point 2");      
       if (stepper2.distanceToGo() == 0)
       stepper2.moveTo(-stepper2.currentPosition());
    }
    
    stepper1.run();
    stepper2.run();
    inBuffer = "";
}

Tried removing the stepper1.moveTo(movement), steppers didn't move at all

chickwolf:
Tried removing the stepper1.moveTo(movement), steppers didn't move at all

You did not post the code in which you removed that line.

I don't like this style of code

stepper1.moveTo(-stepper1.currentPosition());

because you can't see the actual value that is being passed to moveTo()

If this was my project I would calculate the new moveTo value in a variable so I could print it if I needed to. Something like

newStepperPos = -stepper1.currentPosition;
stepper1.moveTo(newStepperPos);

...R

Robin2:
You did not post the code in which you removed that line.

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12);

int movement = 360;
int start_var = 0;

void setup()
{  
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    //stepper1.moveTo(movement);
    
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(100.0);
    //stepper2.moveTo(movement);
}
   
    char inBuffer = "";

void loop()
{
   
    if(Serial.available()>0)
    {
      inBuffer = Serial.read();
    }
       
    if (inBuffer == 'a')
    {
      Serial.println("test point 1");
      if (stepper1.distanceToGo() == 0)
      stepper1.moveTo(-stepper1.currentPosition());
    }
    
    
    if (inBuffer == 'b')
    {
       Serial.println("test point 2");      
       if (stepper2.distanceToGo() == 0)
       stepper2.moveTo(-stepper2.currentPosition());
    }
    
    stepper1.run();
    stepper2.run();
    inBuffer = "";
}

Commented them out from setup.

Robin2:
I don't like this style of code

stepper1.moveTo(-stepper1.currentPosition());

because you can't see the actual value that is being passed to moveTo()

If this was my project I would calculate the new moveTo value in a variable so I could print it if I needed to. Something like

newStepperPos = -stepper1.currentPosition;

stepper1.moveTo(newStepperPos);

That was how it came in the example program, am gonna leave it as it is for the moment. Thanks for the help!

chickwolf:
That was how it came in the example program, am gonna leave it as it is for the moment. Thanks for the help!

Actually the way those lines are written is hiding the problem when you comment out the lines in setup().

If you could see the values used in loop() you would see that it is actually saying

stepper1.moveTo(-0);

because the motor has never moved off the zero position

I leave it as an exercise to figure out the solution. Let me know if you get stuck

...R

Cheers for the guidance, have been trying today to implement your suggestions and this is what I have changed it to.

#include <AccelStepper.h>

AccelStepper stepper1(AccelStepper::FULL4WIRE, 5, 6, 7, 8); //Sets up the pins for stepper one
AccelStepper stepper2(AccelStepper::FULL4WIRE, 9, 10, 11, 12); //Sets up the pins for stepper two

int start_var = 0;
int movement = 360;
long newStepper1Pos = 0; // varialbe for the new stepper position for variable 1
long newStepper2Pos = 0; // variable for the new stepper position for variable 2

void setup()
{  
    
    Serial.begin(9600);
    
    stepper1.setMaxSpeed(200.0); //Sets the max speed for stepper 1
    stepper1.setAcceleration(100.0); //Sets the acceleration for stepper 1
    stepper1.moveTo(movement);
    
    stepper2.setMaxSpeed(200.0); //Sets the max speed for stepper 2
    stepper2.setAcceleration(100.0); //Sets the acceleration for stepper 2
    stepper2.moveTo(movement);

}
   
    char inBuffer = "";

void loop()
{
      
    if(Serial.available()>0) // If any information is avaiable coming from the serial monitor
    {
      inBuffer = Serial.read(); // Puts the information coming from the serial monitor in the input buffer
    }
       
    if (inBuffer == 'a') // If the command sent is an 'a'
    {
      Serial.println("test point 1"); //Serial print for test point 1
      
      if (stepper1.distanceToGo() == 0)
      newStepper1Pos = -stepper1.currentPosition;
      stepper1.moveTo(newStepperPos);
      
      if (stepper2.distanceToGo() == 0)
      newStepper2Pos = -stepper2.currentPosition;
      stepper2.moveTo(newStepperPos);
    }

    stepper1.run();
    stepper2.run();
    inBuffer = ""; //Sets the input buffer back to nothing as to not create a loop

}

I am getting an interesting error message in the form of "wrong type argument to unary minus" which I don't really know what it means.

I tried setting the moveTo() equal to zero so that maybe when the program moved, it wouldn't move until a command was sent, however this just resulted in no movement what so ever.

    stepper1.setMaxSpeed(200.0); //Sets the max speed for stepper 1
    stepper1.setAcceleration(100.0); //Sets the acceleration for stepper 1
    stepper1.moveTo(0);
    
    stepper2.setMaxSpeed(200.0); //Sets the max speed for stepper 2
    stepper2.setAcceleration(100.0); //Sets the acceleration for stepper 2
    stepper2.moveTo(0);

I am looking through the functions that come with this library to see if there is a way of just setting an initial start point for the servo motors so that they can always start from the same position. Thanks again for the help!

-stepper2.currentPosition is trying to calculate the negative of the pointer to the function.

-stepper2.currentPosition() calls the function to get the value and then calculates the negative of that value.

MorganS:
-stepper2.currentPosition is trying to calculate the negative of the pointer to the function.

-stepper2.currentPosition() calls the function to get the value and then calculates the negative of that value.

Thanks for the clarifcation!

Why not do something simple and obvious like this

void loop()
{
     
    if(Serial.available()>0) // If any information is avaiable coming from the serial monitor
    {
        inBuffer = Serial.read(); // Puts the information coming from the serial monitor in the input buffer
    }
        
    if (inBuffer == 'a') // If the command sent is an 'a'
    {
        Serial.println("test point 1"); //Serial print for test point 1
        
     
        if (stepper1.distanceToGo() == 0) {
            if (stepper1.currentPosition() == 0) {
                stepper1.moveTo(movement);
            }
            else {
                stepper1.moveTo(0);
            }
        }
        
        if (stepper2.distanceToGo() == 0) {
            if (stepper2.currentPosition() == 0) {
                stepper2.moveTo(movement);
            }
            else {
                stepper2.moveTo(0);
            }
        }
        inBuffer = ""; // clear this immediately the 'a' has been used

    }

    stepper1.run();
    stepper2.run();

}

...R