Accel Stepper Acceleration Not Working

Using the following code causes the steppers to accelerate before cruising at max speed when the button is first pressed; however all subsequent presses it will rapidly vibrate or not spin at all, I think it starts running at max speed instead of accelerating again.

Driver is EasyDriver HW-135, Stepper is NEMA17

The circuitry works, it is only after the second press that the steppers stop working.

#include <AccelStepper.h>
#include <MultiStepper.h>

#define stp 3
#define stp2 4
#define stp3 5
#define dir 6
#define dir2 7
#define dir3 8

AccelStepper stepper1(AccelStepper::DRIVER, stp, dir);
AccelStepper stepper2(AccelStepper::DRIVER, stp2, dir2);
AccelStepper stepper3(AccelStepper::DRIVER, stp3, dir3);

int button = 9;
int buttonVal, lastButtonVal, counter;
int speed = 2000;
int accel = 300;
void setup() {
  stepper1.setMaxSpeed(speed);
  stepper2.setMaxSpeed(speed);
  stepper3.setMaxSpeed(speed);

  stepper1.setAcceleration(accel);
  stepper2.setAcceleration(accel);
  stepper3.setAcceleration(accel);

  pinMode(button, INPUT);

  Serial.begin(9600);

  stepper1.moveTo(1e9);
  stepper2.moveTo(1e9);
  stepper3.moveTo(1e9);
}

void loop() {
   buttonVal = digitalRead(button);
  if (buttonVal && lastButtonVal != buttonVal){
    counter++;
  }
  lastButtonVal = buttonVal;
  if (counter % 2 == 1) {
    stepper1.setCurrentPosition(0); 
    stepper2.setCurrentPosition(0);
    stepper3.setCurrentPosition(0);
  } else {
    stepper1.setCurrentPosition(1e9);
    stepper2.setCurrentPosition(1e9);
    stepper3.setCurrentPosition(1e9);
  }
  stepper1.run();
  stepper2.run();
  stepper3.run();
}

I have tried swapping out setCurrentPosition() with moveTo(), or putting run() in the if statement and stop() in the else, all have the exact same result described above.

How do you have the button wired?

1 Like

The button works, it's with one to signal one to GND and one to 5V

The way you describe it is wrong wired.
Make a diagram (you can do it on paper and upload a photo).

1 Like

Any resistors involved? Otherwise it sounds like you are making a short circuit when the button is pressed.

2 Likes

Please explain what your sketch is intended to do.
What should happen when you start the Arduino, what should happen when pressing the button.

This?

1 Like

On first button press -> accelerate steppers to max speed, the continue running for essentially infinite time
Second press -> Stop steppers
Then it just repeats

Yes, that's most likely the issue. I'll report back tomorrow

I added a 10kΩ resistor in between the ground pin, but it still doesn't work. The issue has changed to now it just doesn't spin at all, only the first time spinning for a little bit before stopping, which is worse than before.

That's not what your sketch does.
To get the stepper moving with acceleration/deceleration you must use .move() or .moveto().
.setCurrentPosition() is completely wrong for this purpose.
To stop the stepper with deceleration use the .stop() method.

And you must not call these functions with every loop cycle, but only once when you press the button. Only .run() must be called in every loop cycle.

The next point: If you are using an AVR (UNO/Nano..) then speed=2000 is too much for 3 steppers with AccelStepper.

You may consider using MobaTools instead:

#include <MobaTools.h>

#define stp 3
#define stp2 4
#define stp3 5
#define dir 6
#define dir2 7
#define dir3 8

const int stepsPerRev = 200;    // without microstepping
MoToStepper stepper1(stepsPerRev, STEPDIR);
MoToStepper stepper2(stepsPerRev, STEPDIR);
MoToStepper stepper3(stepsPerRev, STEPDIR);

int button = 9;
int buttonVal, lastButtonVal;
bool stepperRunning = false;
int speed = 2000;
void setup() {
    stepper1.attach(stp, dir);
    stepper2.attach(stp2, dir2);
    stepper3.attach(stp3, dir3);

    stepper1.setSpeedSteps(speed * 10, 2000); // set speed and ramp length
    stepper2.setSpeedSteps(speed * 10, 2000);
    stepper3.setSpeedSteps(speed * 10, 2000);

    pinMode(button, INPUT);

    Serial.begin(115200);

}

void loop() {
    buttonVal = digitalRead(button);
    if (buttonVal && (lastButtonVal != buttonVal)) {
        if (stepperRunning) {
            Serial.println("stepper stops" );
            stepperRunning = false;
            stepper1.rotate(0);
            stepper2.rotate(0);
            stepper3.rotate(0);
        } else {
            Serial.println("stepper starts" );
            stepperRunning = true;
            stepper1.rotate(1);
            stepper2.rotate(1);
            stepper3.rotate(1);
        }
    }
    lastButtonVal = buttonVal;
    delay(20);    // poor man's debouncing ;-)

}

MobaTools can create up to 2500 steps/sec for up to 6 steppers ( on AVR with 16MHz).

[edit] Depending on your switch debouncing may be needed ...

2 Likes

I will try this, although like I said I tried moveTo (I did it as a one time thing as you stated) and the issue persisted, but maybe with the resistor it will be different. What I tried today was the following code:

#include <AccelStepper.h>
#include <MultiStepper.h>

#define stp 3
#define stp2 4
#define stp3 5
#define dir 6
#define dir2 7
#define dir3 8

AccelStepper stepper1(AccelStepper::DRIVER, stp, dir);
AccelStepper stepper2(AccelStepper::DRIVER, stp2, dir2);
AccelStepper stepper3(AccelStepper::DRIVER, stp3, dir3);

int button = 9;
int buttonVal, lastButtonVal, counter;
int speed = 2000;
int accel = 300;

bool firstPress = true; 

void setup() {
  // put your setup code here, to run once:
  stepper1.setMaxSpeed(speed);
  stepper2.setMaxSpeed(speed);
  stepper3.setMaxSpeed(speed);

  stepper1.setAcceleration(accel);
  stepper2.setAcceleration(accel);
  stepper3.setAcceleration(accel);

  pinMode(button, INPUT_PULLUP);

  Serial.begin(9600);

  stepper1.moveTo(1e9);
  stepper2.moveTo(1e9);
  stepper3.moveTo(1e9);
}

void loop() {
  // put your main code here, to run repeatedly:
   buttonVal = digitalRead(button);
  if (buttonVal && lastButtonVal != buttonVal){
    counter++;
  }
  lastButtonVal = buttonVal;

  if (counter % 2 == 1) {
  stepper1.run();
  stepper2.run();
  stepper3.run();
  } else {
  stepper1.stop();
  stepper2.stop();
  stepper3.stop();
  }
}

Also I tried

#include <AccelStepper.h>
#include <MultiStepper.h>

#define stp 3
#define stp2 4
#define stp3 5
#define dir 6
#define dir2 7
#define dir3 8

AccelStepper stepper1(AccelStepper::DRIVER, stp, dir);
AccelStepper stepper2(AccelStepper::DRIVER, stp2, dir2);
AccelStepper stepper3(AccelStepper::DRIVER, stp3, dir3);

int button = 9;
int buttonVal, lastButtonVal, counter;
int speed = 2000;
int accel = 300;
void setup() {
  stepper1.setMaxSpeed(speed);
  stepper2.setMaxSpeed(speed);
  stepper3.setMaxSpeed(speed);

  stepper1.setAcceleration(accel);
  stepper2.setAcceleration(accel);
  stepper3.setAcceleration(accel);

  pinMode(button, INPUT);

  Serial.begin(9600);

  stepper1.moveTo(1e9);
  stepper2.moveTo(1e9);
  stepper3.moveTo(1e9);
}

void loop() {
   buttonVal = digitalRead(button);
  if (buttonVal && lastButtonVal != buttonVal){
    counter++;
  }
  lastButtonVal = buttonVal;

  if (counter % 2 == 1 && firstPress) {
  stepper1.moveTo(stepper1.currentPosition() + 1e9);
  stepper2.moveTo(stepper2.currentPosition() + 1e9);
  stepper3.moveTo(stepper3.currentPosition() + 1e9);

  firstPress = false;
  } else if (counter % 2 == 0) {
  stepper1.moveTo(stepper1.currentPosition());
  stepper2.moveTo(stepper2.currentPosition());
  stepper3.moveTo(stepper3.currentPosition());

  firstPress = true;
  }
  stepper1.run();
  stepper2.run();
  stepper3.run();
}

.run() must be called allways! ,run() 'knows' whether pulses have to be created or not. Without callung run(), the steppers does not receive any steppulses and so there will be no deceleration - it stops immediately.
Trial and error is not a good strategy when programming - you should learn how Accelstepper works if you want to use it.

If you still want to use Accelstepper you can try this:

#include <AccelStepper.h>
// #include <MultiStepper.h>  // not needed here
#define stp 3
#define stp2 4
#define stp3 5
#define dir 6
#define dir2 7
#define dir3 8

AccelStepper stepper1(AccelStepper::DRIVER, stp, dir);
AccelStepper stepper2(AccelStepper::DRIVER, stp2, dir2);
AccelStepper stepper3(AccelStepper::DRIVER, stp3, dir3);

int button = 9;
int buttonVal, lastButtonVal, counter;
int speed = 1000;
int accel = 300;
void setup() {
    stepper1.setMaxSpeed(speed);
    stepper2.setMaxSpeed(speed);
    stepper3.setMaxSpeed(speed);

    stepper1.setAcceleration(accel);
    stepper2.setAcceleration(accel);
    stepper3.setAcceleration(accel);

    pinMode(button, INPUT);

    Serial.begin(115200);

    /*  stepper1.moveTo(1e9);
        stepper2.moveTo(1e9);
        stepper3.moveTo(1e9);*/
}

void loop() {
    buttonVal = digitalRead(button);
    if (buttonVal && (lastButtonVal != buttonVal)) {
        Serial.print("Button!, cnt=");
        counter++;
        Serial.println(counter % 2 );
        if (counter % 2 == 1) {
            stepper1.stop();
            stepper2.stop();
            stepper3.stop();
        } else {
            stepper1.moveTo(1e9);
            stepper2.moveTo(1e9);
            stepper3.moveTo(1e9);
        }
    }
    lastButtonVal = buttonVal;
    stepper1.run();
    stepper2.run();
    stepper3.run();

}
2 Likes

Thanks so much this fixed it!

You're welcome.
.. and I hope you see the difference and understand why it works now :wink:

2 Likes

The wrong way of doing it. The pin will be "floating" during switchover, which could be problematic.
Connect the button only to pin and ground.
And use internal pull up on the pin with pinMode, like this

pinMode(button, INPUT_PULLUP); // enable internal pull up on the pin

Note that the pin will now idle HIGH, and is LOW when the button is pushed.

if (buttonVal && ...
becomes now inverted
if (!buttonVal && ...
Leo..

1 Like