AccelStepper library, stepper motor speed problem

I am using the AccelStepper library with an Uno, a 28BYJ-48 stepper motor and the driver card that came with it. My problem is that using the stepper.moveTo, stepper.setSpeed, stepper.run functions give inconsistent motor speed but using the stepper.runToNewPosition gives consistent results.

If I go to position 1026 and then go to position 0, using runToNewPosition the motor runs at the same speed in both directions. However if I use the moveTo, setSpeed, run combination of functions the motor runs at the expected speed going to position 1026 but going back to 0 it moves very slowly for the first 200 steps or so and then completes the rest of the move at expected speed. My code is attached.

The purpose of this code (it is test code for a larger function) is to read a heading in decimal degrees and move a pointer on the stepper motor to the degree position on a compass rose. I want to use the function combination so I do not have any blocking code in my main loop.

Can you please shed some light on what I may have done wrong?

Dale Gloer

/*
 This test is for one decimal place inputs and sends fractional steps to the
 stepper motor operating in half step  mode.  Input is nnn.n
*/
#include <AccelStepper.h>
#define HALFSTEP 8

// Motor pin definitions
#define motorPin1  3     // IN1 on the ULN2003 driver 1
#define motorPin2  4     // IN2 on the ULN2003 driver 1
#define motorPin3  5     // IN3 on the ULN2003 driver 1
#define motorPin4  6     // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);

String heading;
int headingi;
int steps;
int stepsOld(000);
float stepsf, headingf, stepsfOld(0.0);

void setup() {
  stepper1.setMaxSpeed(1000.0);
  stepper1.setAcceleration(100.0);
  stepper1.setSpeed(200);

  Serial.begin(115200);      // turn on Serial Port
Serial.println("Enter heading in decimal degrees, eg 123.5 ");   
}           //--(end setup )---

void loop() {

   if(Serial.available() != 0)   {
// Read serial input:
  heading = "";
  heading += getChar();
  heading += getChar();
  heading += getChar();
  heading += getChar();
  heading += getChar();
  heading += getChar(); 

 headingf = heading.toFloat();
Serial.print("heading: ");
Serial.println(heading);
Serial.print("  headingf  ");
Serial.println(headingf);
  stepsf=headingf*11.4;   
Serial.print("  stepsf  ");
Serial.println(stepsf);  

  if(stepsf!=stepsfOld) {
//   call a functiion to move the stepper
      RunStepper(stepsf);    

Serial.println("  did it  ");
   stepsfOld=stepsf;
Serial.println("Enter heading in decimal degrees, eg 123.5 ");    
  }
 } 
// Serial.println("  In main loop  ");
  
   stepper1.run(); 
}

 char getChar()    // Function to get a character from the serial buffer
  {
Serial.println("  in getChar");    
  while(Serial.available() == 0);   // wait for data
  return((char)Serial.read());   // Thanks Doug
  }

  void RunStepper(float s)   // Function to move the stepper motor
  {
    //  stepper1.runToNewPosition(s);
    stepper1.moveTo(s);
    stepper1.setSpeed(200);
  }

I suspect that the way you have written your Serial code it is preventing the stepper.run() function from being called often enough.

This line is probably the biggest culprit

while(Serial.available() == 0);   // wait for data

You should NOT be waiting for data. Just check if there is data and if there is none get back to controlling the stepper motor

Also, try commenting out all the Serial.print() statements and see if that gives an improvement.

If you use the AutoFormat tool it will make your code much easier to read.

...R
Serial Input Basics - simple reliable ways to receive data.

The while function is within an if decision block that is only true if there is data available in the serial buffer so that is not the problem.

Also, the motor runs at the expected speed if it is "going forward" to larger position numbers and is only slow if it is asked to "go backward" to a a smaller position number. So I don't see the way I have coded it as a problem. I have tried some extra code - not in what I uploaded here - to ensure that the main loop is running all the time, and it is.

I will say that I am new to coding in this environment so there may be better ways of doing this. And thank you for the suggestion to use the AutoFormat tool - I will check it out. Still, there is something amiss here that I cannot find.

Dale Gloer

selkirk5934:
The while function is within an if decision block that is only true if there is data available in the serial buffer so that is not the problem.

Not true, it is the problem. Trust me. You try to read many characters when all you know is there is one or more available. That hangs waiting.

No while loops, call stepper's run() function often.

I am not trying to start a bun fight, but if you are correct, why does it run in the "forward" direction as expected but not when asked to go "backward? It is all the same code - the only thing different is the position that the motor is asked to run to. Further more, when asked to go "backward" it runs very slowly for a couple of hundred steps and then accelerates and runs at the expected speed for the remainder of the move. On closer inspection of the motor action, on the slow portion of the "backward" move request the motor actually moves forward slowly, stops and then runs as expected to the requested position.

I have also verified that the main loop continues to run at speed during all the move requests.

Dale Gloer

I found a way around the problem. I removed the call to function setSpeed after the call to moveTo and now it works correctly. This in spite of how I understood the advice in the Accelstepper Class description for moveTo.

I still think this is a problem in the Accelstepper library but I am moving on.

Dale Gloer

AFAIK the function stepper.setSpeed() is not used when acceleration is used. Instead stepper.setMaxSpeed() is used.

Also the function moveTo() takes a long integer, not a float.

...R