Help needed with Accelstepper + Big Easy driver + Serial inputs.

Hello ,

I am new to this Arduino forum. I am working on a project which has the following parts,

  1. NEMA 17 stepper motor [3 motors]
  2. Big Easy Driver [3 drivers]
  3. Arduino UNO
  4. AccelStepper library
    I am looking to do something like this. The code should input the number from the user to the Arduino Serially. Based on the number entered, I should turn three of my stepper motors.

If the serial input is 1, the 1st motor turns 200 steps then the 2nd motor should turn 300 steps and then the 3rd motor should turn 800 steps. After the 3rd motor has turned there should be a delay for 15 seconds and then 3rd motor should turn -800 steps, 2nd motor should turn 300 steps and 1st should turn 200 steps.

Similarly if the serial input is 2, it should turn the 1st motor turns 1200 steps then the 2nd motor should turn 600 steps and then the 3rd motor should turn 800 steps. After the 3rd motor has turned there should be a delay for 15 seconds and then 3rd motor should turn -800 steps, 2nd motor should turn 600 steps and 1st should turn 1200 steps.

I have 3 more serial inputs which does the same thing basically.

With my current code, I can serially input a number and based on that number, all the motors move simultaneously, but I want them to move one after other and stop for 15 seconds and then move back. Can someone help me to write a code to do the above.

Thanks

#include <AccelStepper.h>

AccelStepper stepper1(1, 9, 8);
AccelStepper stepper2(1, 7, 6);
AccelStepper stepper3(1, 3, 2);


void setup() {
   pinMode(13, OUTPUT);
   digitalWrite(13,LOW);
   Serial.begin(9600);
   stepper1.setMaxSpeed(40000);
   stepper2.setMaxSpeed(40000);
   stepper3.setMaxSpeed(40000);
   stepper1.setSpeed(8000);
   stepper2.setSpeed(7000);
   stepper3.setSpeed(5000);   
   stepper1.setAcceleration(30000.0);
   stepper2.setAcceleration(20000.0);   
   stepper3.setAcceleration(10000.0);
   }

void loop() {
    if (Serial.available() > 0)
   {
      char input =  Serial.read();
      if (input=='1')
      {
         digitalWrite(13,HIGH);
         stepper1.moveTo(200);
         stepper2.moveTo(300);
         stepper3.moveTo(800);
      }
      else if (input=='2')
      {
         digitalWrite(13,LOW);
         stepper1.moveTo(1200);
         stepper2.moveTo(600);
         stepper3.moveTo(800);
      }
    }

    if (stepper1.distanceToGo() != 0 || stepper2.distanceToGo() != 0 || stepper3.distanceToGo() != 0)
    {
      stepper1.runSpeedToPosition();
      stepper2.runSpeedToPosition();
      stepper3.runSpeedToPosition();
      }
}

If you don't need to do anything else while a motor is moving the use of runSpeedToPosition() should be suitable. It should complete all the steps before returning control to the Arduino.

Note that that function does NOT use acceleration.

I'm not sure if this line does anything useful

if (stepper1.distanceToGo() != 0 || stepper2.distanceToGo() != 0 || stepper3.distanceToGo() != 0)

Wouldn't it be better to set the destination for stepper2 after stepper 1 has finished its move etc/

You seem to be using very high values for speed (and acceleration). I don't know that the AccelStepper library is capable of such high step rates.

...R

Thanks for the response Robin.

Robin2:
If you don't need to do anything else while a motor is moving the use of runSpeedToPosition() should be suitable. It should complete all the steps before returning control to the Arduino.

Note that that function does NOT use acceleration.

I didn't know that this function does not use acceleration, this makes sense now because, I tried with different accelerations but there wasn't any acceleration or deceleration when the motor moved. I will use the stepper.run function.

Robin2:
I'm not sure if this line does anything useful

 if (stepper1.distanceToGo() != 0 || stepper2.distanceToGo() != 0 || stepper3.distanceToGo() != 0)

At this point, this line doesn't do anything useful. Reading few examples what I found was, after this line I should give something like stepper1.moveTo(0), stepper2.moveTo(0), stepper3.moveTo(0), , so that they can return to their position. But before doing this step I want a delay for 15 seconds. I am not sure of how/where to use the delay command here.

Robin2:
Wouldn't it be better to set the destination for stepper2 after stepper 1 has finished its move etc/

I have thought about it. I wanted to measure the time it takes for stepper1[using mills() function] to turn then after that time my second motor should turn and so for the third motor, but I do not know how to do that in terms of code. Or is there any other way to implement this?

Robin2:
You seem to be using very high values for speed (and acceleration). I don't know that the AccelStepper library is capable of such high step rates.

I saw these numbers in a post so I thought it works. I can change them to something lower and use single steps instead of 1/16th of step.

Any help would be appreciated. Thanks again Robin.

There is a function runToPosition() that does use acceleration and also blocks until the destination is reached.

My guess is that your code needs to be something like this pseudo code.

stepperA.moveTo(xxxx);
stepperA.runToPosition();
delay(yy);
stepperB.moveTo(aaaa);
stepperB.runToPosition();
// etc

It's not very elegant but I think it will do what you want.

...R

Funny, usually the problem is the opposite: doing something useful while the stepper is moving, so requiring non blocking.

I would still suggest doing it the "proper" way, using non blocking calls in a loop moving the stepper one step at the time, and checking if they reached their target with distanceToGo.

The code may become more complicated, but you'll be able to use acceleration (and thus have faster and smoother movement), you can still read the serial port while the motors are moving, and potentially later do other things in the main loop as well, without being blocked by the moving steppers.

vertigo72:
I would still suggest doing it the "proper" way, using non blocking calls in a loop moving the stepper one step at the time, and checking if they reached their target with distanceToGo.

The code may become more complicated, but you'll be able to use acceleration (and thus have faster and smoother movement), you can still read the serial port while the motors are moving, and potentially later do other things in the main loop as well, without being blocked by the moving steppers.

Can you refer/post some code which does that? I am still learning how to do these stuff. Thanks for your reply.

The basic example of the library works that way:

http://www.airspayce.com/mikem/arduino/AccelStepper/AFMotor_MultiStepper_8pde-example.html

Every time the main loop is executed, each stepper moves just 1 step (and they reverse motor one after a full "turn"). But rather than stepping each motor on every cycle through the loop, you will have to check in the loop for each motor to see if its time for it to move or not, by storing the state of the motor in a variable or checking distanceToGo() to go for the previous motor. Something like this:

void loop()
{

 doserial stuff
 set stepper targets
 
   if (stepper1.distanceToGo() != 0)  stepper1.run();
   else if ( stepper2.distanceToGo() !=0)  stepper2.run();
   else if  (stepper3.distanceToGo() !=0)  stepper3.run();

}

If you want a delay between the movement of each motor, you'll need an additional check and with a timer.

Hello Vertigo72,
Thanks for your reply.

vertigo72:

void loop()

{

doserial stuff
set stepper targets

if (stepper1.distanceToGo() != 0)  stepper1.run();
  else if ( stepper2.distanceToGo() !=0)  stepper2.run();
  else if  (stepper3.distanceToGo() !=0)  stepper3.run();

}




If you want a delay between the movement of each motor, you'll need an additional check and with a timer.

I am not sure if I should program it this way. The code will be a bit complex. I feel like it could be done with running these many loops.

Hello Robin,
Thanks for your reply.

Robin2:
There is a function runToPosition() that does use acceleration and also blocks until the destination is reached.

My guess is that your code needs to be something like this pseudo code.

stepperA.moveTo(xxxx);

stepperA.runToPosition();
delay(yy);
stepperB.moveTo(aaaa);
stepperB.runToPosition();
// etc

I have modified my code to this after going through your pseudo code.

#include <AccelStepper.h>

// Define two steppers and the pins they will use
AccelStepper stepper1(1, 9, 8);
AccelStepper stepper2(1, 7, 6);
AccelStepper stepper2(1, 3, 2);

void setup() {
   pinMode(13, OUTPUT);
   digitalWrite(13,LOW);
   Serial.begin(9600);
   stepper1.setMaxSpeed(4000);
   stepper2.setMaxSpeed(4000);
//   stepper1.setSpeed(2000);
//   stepper2.setSpeed(2000);
   stepper1.setAcceleration(3000.0);
   stepper2.setAcceleration(2000.0);   
}

void loop()
{

     
    if (Serial.available() > 0)
   {
      char input =  Serial.read();
      if (input=='1')
      {
         digitalWrite(13,HIGH);
         stepper1.moveTo(200);
         stepper2.moveTo(800);
         
      }
      else if (input=='2')
      {
         digitalWrite(13,LOW);
         stepper1.moveTo(1200);
         stepper2.moveTo(800);
         
      }
    
      else if (input=='2')
      {
         digitalWrite(13,LOW);
         stepper1.moveTo(600);
         stepper2.moveTo(800);
         
      }
      
      else if (input=='2')
      {
         digitalWrite(13,LOW);
         stepper1.moveTo(2400);
         stepper2.moveTo(800);
         
      }
    }
    

  if (stepper1.distanceToGo() == 0)
  {
         delay(1000);
         stepper1.moveTo(0);
         stepper2.moveTo(0);
         
         
  }
         stepper1.runToPosition();
         stepper2.runToPosition();
         
 }

I want the motors to run at their max speed. I tried with some higher numbers randomly but it is not reflecting in the rotations. I changed my stepper motor1 from 1/16th step to 1/4th by pulling MS1 and MS3 then the first motor shaft didn't move at all. I am not sure of the issue. But I can feel that the rotor is moving. Do you know what's causing this. Thanks

checking distanceToGo() makes no sense when using blocking moves like runToPosition, as the program will halt until the steppers have reached their target, so distance to go will always be zero when you check it.

So your loop will always wait 1 second, set the target to zero, then instruct the motors to go there. ie, nothing will move.

AKT:
I want the motors to run at their max speed. I tried with some higher numbers randomly but it is not reflecting in the rotations. I changed my stepper motor1 from 1/16th step to 1/4th by pulling MS1 and MS3 then the first motor shaft didn't move at all. I am not sure of the issue. But I can feel that the rotor is moving. Do you know what's causing this. Thanks

If you have problems like that write a very short program that just uses one motor and stick with that until you have it figured out. I have not use a BigEasydriver, only a Pololu A4988.

Have a look at this Simple Stepper Code

If you want to be able to receive data while the motors are moving you will not be able to use blocking code for your motors and you will probably need code similar to what @vertigo72 has suggested. His idea in Reply #6 looks good.

You may also want to look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R
Stepper Motor Basics

AKT:
Can you refer/post some code which does that? I am still learning how to do these stuff. Thanks for your reply.

Yes, the examples that come with the library...