accelstepp performance

Hello.
I’m new to Arduino and C/C++, and last coded in BASIC about 25 years ago :fearful: , so I will probably ask some very stupid questions and make some very stupid mistakes. Here goes…

I am trying to control a single stepper motor (28BYJ-48 via ULN2003 on pins 3-6) using AccelStepper ( to take advantage of it’s acceleration/deceleration feature for better load handling) with six switches (on pins 7-12) and a pot (on A0). The board and motor are powered through the jack with 9v.

Two of the switches must make the motor run to defined positions (cw & ccw) at a speed set by the pot (this is the primary function of the device).
Two of the switches must make the motor run to defined positions (cw & ccw) at a different speed (return to base fast while preserving speed set by pot).
The last two are limit switches intended to deal with accidental overruns, and disable motor pins to save power (batteries).

Here is some code I wrote to test performance at different speeds and acceleration:

#include <AccelStepper.h>
#define HALFSTEP 8

// define motor pins
#define motorPin1  3     // IN1 on ULN2003
#define motorPin2  4     // IN2 on ULN2003
#define motorPin3  5     // IN3 on ULN2003
#define motorPin4  6     // IN4 on ULN2003


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


void setup() {

  // set baud rate
  Serial.begin(9600);


  // set motion properties
  stepper1.setMaxSpeed(2000.0);
  stepper1.setAcceleration(1000.0);
  stepper1.setSpeed(2000); //return speed

}//--(end setup )---

void loop() {


    stepper1.moveTo (120000);
    stepper1.run();
    if (stepper1.distanceToGo()<(1))
       stepper1.disableOutputs();
  }

This works exactly as expected - smooth acceleration and movement, reliable up to about 2000 steps/second.

I then wrote the following:

#include <AccelStepper.h>
#define HALFSTEP 8

// define motor pins
#define motorPin1  3     // IN1 on ULN2003
#define motorPin2  4     // IN2 on ULN2003
#define motorPin3  5     // IN3 on ULN2003
#define motorPin4  6     // IN4 on ULN2003

//define switch pins
#define returnright 7
#define returnleft 8
#define goright 9
#define goleft 10
#define limitright 11
#define limitleft 12

// create variables

// speeds
int potread;
int potspeed;

//switch states
int rr;
int rl;
int gr;
int gl;
int l1;
int l2;

//timer
int t;

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48 - i don't understand why this order is appropriate, but it seems to work with accelstepper
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);


void setup() {

  // set baud rate for serial monitoring
  Serial.begin(9600);

  //define switch pin types
  pinMode (returnright, INPUT);
  pinMode (returnleft, INPUT);
  pinMode (goright, INPUT);
  pinMode (goleft, INPUT);
  pinMode (limitright, INPUT);
  pinMode (limitleft, INPUT);

  // set motion properties
  stepper1.setMaxSpeed(2000.0);
  stepper1.setAcceleration(1000.0);
  

}

void loop() {
  
  // loop time monitoring
  Serial.println ("one loop");
  t = millis();
  Serial.println(t);



  // check state of six switches, and set motion accordingly
  rr = digitalRead(returnright);
  if (rr == HIGH) {
    Serial.println("returnright");
    stepper1.stop();
    stepper1.setSpeed(2000);
    stepper1.moveTo(2000);
  }
  rl = digitalRead(returnleft);
  if (rl == HIGH) {
    Serial.println("returnleft");
    stepper1.stop();
    stepper1.setSpeed(2000);
    stepper1.moveTo(0);
  }

  gr = digitalRead(goright);
  if (gr == HIGH) {
    Serial.println("goright");
    stepper1.stop();
    potspeed = (analogRead(A0));
    stepper1.setSpeed(potspeed * 2);
    stepper1.moveTo(2000);
  }

  gl = digitalRead(goleft);
  if (gl == HIGH) {
    Serial.println("goleft");
    stepper1.stop();
    potspeed = (analogRead(A0));
    stepper1.setSpeed(potspeed * 2);
    stepper1.moveTo(0);
  }

  l1 = digitalRead(limitright);
  if (l1 == HIGH) {
    Serial.println("limitright");
    stepper1.disableOutputs();
    stepper1.setCurrentPosition(2000);
  }

  l2 = digitalRead(limitleft);
  if (l2 == HIGH) {
    Serial.println("limitleft");
    stepper1.disableOutputs();

  }

  stepper1.run();


}

Now the motor runs slowly and jerkily, with a small section of smooth motion at the very end and I have no discernable speed control from the pot. The button presses are logged, so I’m confident that everything is wired correctly.
The time per loop is usually about 15 millis. i guess this means that speeds higher than about 66 steps/second would not be called frequently enough.
If I add the serial.Print bit into the performance test code it perform badly (same as the main code), but if I remove them from the main code it remains the same.

My questions are;

1 - From what I’ve read it seems that reading the switches and performing the ifs should add up to less than 15 millis - what is taking the time?
2 - How can I call the run command frequently enough (? 2000/s) while monitoring six switches?
3 - I would expect new button presses to override older ones since moveTo is non-blocking - is this right?
4 - How would I go about debugging, since the serial monitor seems to change the way the sketch operates?

Any help greatly appreciated. :slight_smile:

The board and motor are powered through the jack with 9v.

What kind of 9V supply? How much current is it capable of supplying?

Two of the switches must make the motor run to defined positions (cw & ccw) at a different speed (return to base fast while preserving speed set by pot).

Does that make sense to you? If the pot controls the speed, how can the motors run at two different maximum speeds?

The time per loop is usually about 15 millis.

The time that the Serial.print() statements spend waiting for there to be room in the outgoing buffer would be greatly improved by:

  • printing less useless stuff. lowerleft conveys no more information than LL, but takes 4.5 times as long to send
  • picking up the pace. The stone ages, where 9600 was a good speed, ended a LONG time ago.

1 - From what I’ve read it seems that reading the switches and performing the ifs should add up to less than 15 millis - what is taking the time?

Serial printing at a snails pace.

2 - How can I call the run command frequently enough (? 2000/s) while monitoring six switches?

The answer is above.

3 - I would expect new button presses to override older ones since moveTo is non-blocking - is this right?

The question doesn’t really make sense. On every pass through loop() you read the current state of the switches, and act on them with no regard to the previous state of any switch, so there is nothing to “override”.

4 - How would I go about debugging, since the serial monitor seems to change the way the sketch operates?

The serial monitor has NO impact on the program. The fact that you send it lots of data very slowly does.

Thanks for the reply - very helpful!

What kind of 9V supply? How much current is it capable of supplying?

Currently on a 1A supply, so should be ample. Will be batteries - not yet clear what type.

Does that make sense to you? If the pot controls the speed, how can the motors run at two different maximum speeds?

I just mean there are two different speeds 2000 for rr and rl, and (potspeed*2) for gr and gl.

The time that the Serial.print() statements spend waiting for there to be room in the outgoing buffer would be greatly improved by:

  • printing less useless stuff. lowerleft conveys no more information than LL, but takes 4.5 times as long to send
  • picking up the pace. The stone ages, where 9600 was a good speed, ended a LONG time ago.

This is interesting - my ignorance, obviously.
If I remove all serial related lines from the code it works a lot better, but not quite as expected (by me at least...).
BTW what might be a sensible rate to try to monitor at?

Quote

3 - I would expect new button presses to override older ones since moveTo is non-blocking - is this right?

The question doesn't really make sense. On every pass through loop() you read the current state of the switches, and act on them with no regard to the previous state of any switch, so there is nothing to "override".

Yeah, that was a bit unclear.

What I meant was "If I press a button to go right while it's travelling left, should it forget about going left, and start going right?". My understanding is that it should (but if I used runToPosition it should complete the left movement before accepting further instructions).

If i do press while it's moving, I get unpredictable motion instead.

Thanks again for your help. :slight_smile:

Currently on a 1A supply, so should be ample.

Maybe. Barely.

Will be batteries - not yet clear what type.

Damned big ones. Steppers and batteries are not a good combination.

BTW what might be a sensible rate to try to monitor at?

115200

What I meant was "If I press a button to go right while it's travelling left, should it forget about going left, and start going right?".

That depends on whether you read the switches while the motor is "travelling left", or not. If you do, you could change the "where the hell should I be" value. If you don't, then the fact that you keep pounding on the switch is irrelevant.

How are your switches wired? I much prefer INPUT_PULLUP because that does not require external resistors and prevents floating pins.

It's a small motor - I believe it should draw 0.2A at 9V. I'm imagining it may be a 9.6V 1.3Ah cordless drill battery to get what I need from a single charge.

It's currently on external pull down resistors. I've read a little about using the board's internal resitors, but haven't tried it out yet.

115200 - a LOT higher!

Thanks for your help - almost working now.