AccelStepper: Stopping and Starting Motors

Hey,

I'm having some trouble with running some 28BYJ-48 stepper motors using the Accelstepper library. I can get the motors to run and go through most of the commands fine, I'm just having trouble with restarting a motor after I've stopped it. What I want to do is (hopefully clearly!) outlined in the code below.

  void setup(){

//delibrately set very high so stepper motor will continue to turn
    stepper1.move(100000);
    stepper1.setMaxSpeed(1000);
    stepper1.setAcceleration(500);
   
  }

void loop(){

//take the reading from the hall effect
    time_now = millis();
    he_11 = digitalRead(HE_11);
   
    //run the run() function in a while loop waiting for HE_11
    while (he_11 == 1){
      stepper1.run();
      he_11 = digitalRead(HE_11);
    }

//motor stops when HE_11 triggered

//run a pre written function to change the output of the stepper and pause
    engageO();
    delay(1000);

time_now = millis();
    he_22 = digitalRead(HE_22);

//run the run() function in a while loop waiting for HE_22
    while (he_22 == 1){
      stepper1.run();
      he_22 = digitalRead(HE_22);
    }

//motor stops when HE_22 triggered

//go back to the original setting and repeat
    engageI();
    delay(1000);
   
  }




}

The motor turns fine the first time after the board has been reset, however after it has stopped and trys to turn the second time, it only vibrates and gets very hot. As it turns fine the first time, I assume it must just be a coding error somewhere - probably to do with my use of functions from Accelstepper. Any help would be really appreaciated.

Luke

This:

stepper1.move(100000);
stepper1.setMaxSpeed(1000);
stepper1.setAcceleration(500);

needs to be in the loop. While it's in the setup, it's only allowed to run once. And will then sit in idle until you reset it, and then it can move again.

You need to post the complete program so we can see how all the variables are defined.

I would not use WHILE in the way you have. The loop() function is designed to repeat continuously and it should be allowed to its job.

Use the switch to set the value of a variable and if then your code can decide to move the motor depending on the value of the variable using IF clause (rather than WHILE).

Also, stepper.run() is intended to move the motor a specific number of steps and then stop. If you want the motor to run continuously you should use stepper.runSpeed(), but that does not use acceleration. Use stepper.setSpeed() to determine the speed.

If you want to use acceleration then you could set the destination to a very high number of steps and use stepper.stop() which decelerates the motor to a stop as quickly as possible.

...R

wildcat99s:
This:

stepper1.move(100000);
stepper1.setMaxSpeed(1000);
stepper1.setAcceleration(500);

needs to be in the loop.

Only the first line needs to be in loop() unless the OP specifically needs to change the speed or acceleration.

...R

So I’ve just tried implementing these two replacement while loops:

while (he_11 == 1){
stepper1.run();
stepper1.move(100000);
he_11 = digitalRead(HE_11);
}

and

stepper1.setSpeed(1000);
while (he_11 == 1){
stepper1.runSpeed();
he_11 = digitalRead(HE_11);
}

I unfortunately get the same problem as before - the stepper turns the first time after being reset, but after the sensor is triggered it will only buzz after that. The second time round it doesn’t sound like the stepper accelerates as before, it just goes straight to the pitch that it normally has at max speed. Do I have to reset the speed to zero?

I’ve written the stepper1.run() functions in while loops as opposed to just the loop function, as the code I sent in is a dummy testing script. The actual program has a loop function of about 200 - 300 lines, and the functions above around around 800 lines. I thought it would be too confusing to include the whole script.

Thanks for the really quick replies btw :slight_smile:

luke_design:
So I've just tried implementing these two replacement while loops:

You need to post the complete program. There just might be a small error somewhere.

...R

So, I’ve just created a stripped down script which only has the stepper and hall effect sensors coded into it. It makes trouble shooting easier and means I know the errors are definitely to do with the stepper functions. I’ve attached it below.

I ran the attached script a few times, and using the Serial monitor was able to work out what it was doing. It turns out that the code moves between the while statements fine. For example, if only one or neither of the hall effect sensors are triggered, then the stepper motor runs fine. However, if both sensors are triggered, meaning the stepper motor comes to a stop (as no stepper1.run() commands are being passed to it as both while loops are bypassed), then it will never restart without resetting the board. It’s almost as though it needs to be reset to zero, so that it can start off in the right place?

I played around with some other scripts and found the same thing, every time the stepper motor is stopped ‘mid-run’ I couldn’t get it going again. Any ideas?

Thanks for the help!

Here’s the code as a quote as well:

//Written for an ARDUINO MEGA 2560

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//This code governs the interaction of a rubix lamp. A interestingly useless gizmo that acts as a standard

//white LED lamp, but only when the user aligns all the pieces correctly. Not only does the lamp have to be

//solved, but it will unsolve and then resolves itself if put in the correct setting.

#include <AccelStepper.h>

#include <MultiStepper.h>

unsigned long time_now = 0;

#define HALFSTEP 4

//Stepper1

#define stepper11 2 // IN1 for stepper 1

#define stepper12 3 // IN2 for stepper 1

#define stepper13 4 // IN3 for stepper 1

#define stepper14 5 // IN4 for stepper 1

AccelStepper stepper1(HALFSTEP, stepper11, stepper12, stepper13, stepper14);

//hall effect sensors

const int HE_11 = 25;

const int HE_12 = 26;

int he_11 = 0;

int he_12 = 0;

//

void setup() {
// put your setup code here, to run once:

stepper1.setMaxSpeed(1000);

stepper1.setAcceleration(500);

stepper1.move(100000);

Serial.begin(9600);

}

void loop() {
// put your main code here, to run repeatedly:

he_11 = digitalRead(HE_11);
Serial.println(“1”);

while (he_11 == 1) {

stepper1.run();

stepper1.move(100000);

he_11 = digitalRead(HE_11);

}

stepper1.stop();

//Function would go in here

he_12 = digitalRead(HE_12);

Serial.println(“2”);

while (he_12 == 1) {

stepper1.run();

stepper1.move(100000);

he_12 = digitalRead(HE_12);

}

stepper1.stop();

//Function would go in here

}

RUBIX_LAMP_SHORT.ino (1.77 KB)

Just something I noticed as I have been using those same steppers in my project. If you're using the ULN2003 stepper controller boards that are often sold with these steppers, the middle 2 pins need swapped. You can see an example of this on this page. Look in his code. Particularly, this line

Stepper(stepsPerRevolution, 8, 10, 9, 11);

Which would correlate with your code

AccelStepper stepper1(HALFSTEP, stepper11, stepper12, stepper13, stepper14);

However, your particular library (which I haven't used) may already take this into account. Just putting it out there for you to look into if the motors don't seem to work as well as you think they should.

luke_design:
Here’s the code as a quote as well:

Use the code button </> for code so it looks like this. It makes it much easier for people reading on tablets and also makes it easy to copy. I have also taken out all the unnecessary white-space to make it easier to read.

//Written for an ARDUINO MEGA 2560

////////////////////////////////////////////////////////

//This code governs the interaction of a rubix lamp. A interestingly useless gizmo that acts as a standard
//white LED lamp, but only when the user aligns all the pieces correctly. Not only does the lamp have to be
//solved, but it will unsolve and then resolves itself if put in the correct setting.


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

unsigned long time_now = 0;

#define HALFSTEP 4

//Stepper1
#define stepper11  2     // IN1 for stepper 1
#define stepper12  3    // IN2 for stepper 1
#define stepper13  4     // IN3 for stepper 1
#define stepper14  5     // IN4 for stepper 1

AccelStepper stepper1(HALFSTEP, stepper11, stepper12, stepper13, stepper14);

//hall effect sensors
const int HE_11 = 25;
const int HE_12 = 26;
int he_11 = 0;
int he_12 = 0;
// 

void setup() {
  // put your setup code here, to run once:
  stepper1.setMaxSpeed(1000);
  stepper1.setAcceleration(500);
  stepper1.move(100000);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  he_11 = digitalRead(HE_11);
  Serial.println("1");
  
  while (he_11 == 1) {
    //Serial.println("1");
    stepper1.run();
    stepper1.move(100000);
    he_11 = digitalRead(HE_11);
  }

  stepper1.stop();
  //Function would go in here
  
  he_12 = digitalRead(HE_12);
  Serial.println("2");
  
  while (he_12 == 1) {
    stepper1.run();
    //Serial.println("2");
    stepper1.move(100000);
    he_12 = digitalRead(HE_12);
  }
 
  stepper1.stop();
  //Function would go in here

}

…R

Have a look at how I have restructured this

void loop() {
  // put your main code here, to run repeatedly:
  he_11 = digitalRead(HE_11);
  he_12 = digitalRead(HE_12);
  
  Serial.println("1");
  
  if(he_11 == 1) {
    stepper1.move(100000);
  }
  else {
     stepper1.stop();
      //Function would go in here
  }

  Serial.println("2");
  
  if (he_12 == 1) {
    stepper1.move(100000);
  }
  else {
      stepper1.stop();
      //Function would go in here
  }
  stepper1.run()
}

I suspect it won't work because I don't properly understand what you want to happen, but the structure better reflects how the AccelStepper library is intended to be used.

If you want the motor only to move while the button is pressed then you need code to detect when the button goes down (to set the distance) and when it goes up (to implement the stop). DON'T use WHILE because it blocks the Arduino from doing other things.

...R

Robin2:
Have a look at how I have restructured this

void loop() {

// put your main code here, to run repeatedly:
  he_11 = digitalRead(HE_11);
  he_12 = digitalRead(HE_12);
 
  Serial.println(“1”);
 
  if(he_11 == 1) {
    stepper1.move(100000);
  }
  else {
    stepper1.stop();
      //Function would go in here
  }

Serial.println(“2”);
 
  if (he_12 == 1) {
    stepper1.move(100000);
  }
  else {
      stepper1.stop();
      //Function would go in here
  }
  stepper1.run()
}



I suspect it won't work because I don't properly understand what you want to happen, but the structure better reflects how the AccelStepper library is intended to be used.

If you want the motor only to move while the button is pressed then you need code to detect when the button goes down (to set the distance) and when it goes up (to implement the stop). DON'T use WHILE because it blocks the Arduino from doing other things.


...R

Thanks for this, works much better than the while loops! Definitely the way forward. The issue now is when I try to implement the functions I want whilst the motor has stopped, the motor won’t restart afterwards.

To help solve this I’ve got back to a breadboard and fully simplified the process. I now have just a stepper motor (and driver), a push button and an LED attached to the Arduino. What I want to happen is:

  • Motor starts turning
  • Once button is pressed, motor stops turning and LED flahes
  • After LED flash function has run, the motor restarts turning and waits for a new button press

What actually happens is:

  • Motor starts turning
  • Once button pressed, motor stops and LED flash function runs
  • Once LED function ends, motor does not restart turning, but just vibrates without turning the shaft
  • If button is pressed again, motor stops buzzing, LED function runs
  • but then motor will start buzzing again, not turning

Here is the code I’ve used:

#include <AccelStepper.h>

#include <MultiStepper.h>

#define HALFSTEP 4

//Stepper1

#define stepper11  2     // IN1 for stepper 1

#define stepper12  3    // IN2 for stepper 1

#define stepper13  4     // IN3 for stepper 1

#define stepper14  5     // IN4 for stepper 1

AccelStepper stepper1(HALFSTEP, stepper11, stepper12, stepper13, stepper14);

//LED and button

const int button = 25;

int state = 0;

const int LED = 45;

//function flashes LED twice
void LEDflash(){
   digitalWrite(LED, HIGH);
   delay(500);
   digitalWrite(LED, LOW);
   delay(500);
   digitalWrite(LED, HIGH);
   delay(500);
   digitalWrite(LED, LOW);
}


void setup() {
  // put your setup code here, to run once:

  stepper1.setMaxSpeed(1000);

  stepper1.setAcceleration(500);

  stepper1.move(100000);

  pinMode(LED, OUTPUT);

  pinMode(button, INPUT);
  
}

void loop() {
  // put your main code here, to run repeatedly:

  //read the hall effect
  state = digitalRead(button);
  
  //if button not pushed, then turn stepper motor
  if(state == 1) {
    stepper1.move(100000);
  }

  //if button pushed, stop stepper motor and flash LED 
  else {
     stepper1.stop();
     LEDflash();
     //once LED has flashed, restart the motor
     stepper1.move(100000);
  }
  
  stepper1.run();
}

Thanks for really good answers so far!! Hopefully will be able to get this sorted haha

I'm finding your logic very confusing

  //if button pushed, stop stepper motor and flash LED 
  else {
     stepper1.stop();
     LEDflash();
     //once LED has flashed, restart the motor
     stepper1.move(100000);
  }

Why are you trying to restart the motor in the section of program that stops the motor?

And you are not testing for changes in the switch position. That can be done like this

previousState = state;
state = digitalRead(statePin);
if (state == 1 and previousState == 0) {
   // do something
}
if (state == 0 and previousState == 1) {
    // do something else
}

...R

Ok, got it!

Turns out the problem wasn't (entirely) with the code. When one of the stepper motors was buzzing, I had a little go at forcing it to turn. When I twisted it a half turn, it seemed to fall into sync with the steps and began turning as normal! What I assumed was happening was that the motor was starting out trying to turn at maxSpeed, but going from zero to maxspeed causes the stepper to become stuck - it needs to be accelerated up to the desired speed.

If you use runSpeed() as the instead of run, and then incremnetally increase the speed value in setSpeed(speed), then the motor should start up better.

luke_design:
If you use runSpeed() as the instead of run, and then incremnetally increase the speed value in setSpeed(speed), then the motor should start up better.

If you use run() the library will do the acceleration for you.

I suspect your code is calling stepper1.move(100000); too often and in doing so it probably confuses the run() function

...R