Understanding AccelStepper's Speed Control

Hi all,

I’m a newcomer to posting on the forum, although I’ve been lurking for quite a while. Programming is not new to me but C++ definitely is. I’ve been struggling through and am making headway.

OK, I’m working with an Arduino Mega 2560 and putting together a dosing device for my reef tank. The doser makes use of NEMA 17 stepper motors (4) and requires that the output of the motors be calibrated. In effect, so that it knows how long to run to dose a certain number of milliliters into the tank. This is where my problems lie.

I’m using the AccelStepper library along with DRV8825 drivers to control the motors. Here is a sample of the code in my sketch.

#include <AccelStepper.h>

void setup() {

  AccelStepper stepper1(1,7,48); 
  
  pinMode(7, OUTPUT); // pump
  pinMode(48, OUTPUT); // direction
  pinMode(34, OUTPUT); // microstep
  
  initSteppers();
    
  // use timer3 to trigger calling the pump

  Timer3.initialize(5000);
  Timer3.attachInterrupt(movePump);

}

void loop() {
}

// set up some things

void initSteppers() {

  digitalWrite(48, HIGH);  //direction pin
  digitalWrite(7, HIGH); // pump pin
  digitalWrite(34, HIGH); //set pin HIGH for 16X microstepping
    
  stepper1.setMaxSpeed(500);
  stepper1.setSpeed(300);        
  
}

// run pump

void movePump(){
    stepper1.runSpeed();
}

It all works perfectly - EXCEPT - the speed. Let’s say a pump delivers 5ml at a “setSpeed” of 300. If I change the speed to 301 (not while the sketch is running) it may double the output of the pump - and I can see that the pump is running twice as fast after a change from 300 to 301. The whole thing makes it impossible to calibrate the pumps.

Testing today I found that speeds from 140 to 199 all delivered 6ml. When I raised the speed to 200, output jumped to 11ml. ???

Makes no sense to me. Can’t figure it out. Maybe something to do with the 16x microstepping? Any help or insight would be appreciated.

Thanks,

Tom

I don't immediately see any reason for the behaviour you describe. Have you checked that the motor is running at the correct (expected) speed.

I find it strange that you are using speed to determine quantity. I imagine that counting the number of steps would be more appropriate.

By the way your code would be much easier to read if you give names to the pins. For example

byte pumpPin = 7;
byte directionPin = 48;
byte microstepPin = 34;

and then you could have

  pinMode(pumpPin, OUTPUT);
  pinMode(directionPin, OUTPUT);
  pinMode(microstepPin, OUTPUT);

without the need for any comments

...R

You need to call run or runSpeed as often as possible - I don't know the Timer3 library but I suspect you are setting it up to run every 5ms? Far too slow. Just put a call to runSpeed () in loop ().

Robin2 - Thanks for your critique. I really like the idea of using a number of steps instead of time. I'll have to do a rewrite as the sketch was originally intended for brushless motors but, I'm sure it would be worth it.

MarkT - I guess my lack of experience with micros made me assume that 5ms was a pretty short slice of time. Mind commenting on how short you feel one can go? BTW: I have a lot going on in the main loop, so it might slow things down a little to put the code there.

I had missed the point @MarkT has brought up and I agree with him. If you are going to use the AccelStepper library you MUST use it the way it is intended to be used.

For all sorts of reasons you should arrange all of your program so that loop() can repeat hundreds or thousands of times per second. Then you can call run() often enough for the stepper to perform properly.

Of course you could write your own motor control code and not use the AccelStepper library - but I suspect that would be more complicated.

...R PS I think the strange problem with your Timer system is due to its granularity. With a more frequent call to run() the AccelStepper library can calculate when a step is needed. When you made a small change to the speed you pushed things just enough so that every time that run() was called it was already too late and the library lost control of the timing.

Put a call to run() in loop(), never call delay(), that’s normally the way.

Did you start from one of the many AccelStepper example sketches such as the ConstantSpeed one? Its super-clear:

#include <AccelStepper.h>

AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

void setup()
{  
   stepper.setMaxSpeed(1000);
   stepper.setSpeed(50); 
}

void loop()
{  
   stepper.runSpeed();
}