NEMA 17 Stepper with A4988 Driver Rotating Randomly on Startup

I've got a NEMA17 stepper motor, which I'm controlling with an A4988 driver and this stepper motor library: GitHub - laurb9/StepperDriver: Arduino library for A4988, DRV8825, DRV8834, DRV8880 and generic two-pin (DIR/STEP) stepper motor drivers. It's working alright, but I've noticed an odd behaviour. When the Arduino Uno is going through its setup routine, the stepper motor will rotate through about 1/3 of its rotation, making an uneven sound as it does so. The arduino then kicks in and runs it as per the main program loop.

I noticed that the same effect was obtained when I disconnected the step and direction wires from the Arduino while it was powered on. My question is, is there a way to prevent this behaviour on startup?

The A4988 is wired as per the instructions here: https://howtomechatronics.com/tutorials/arduino/how-to-control-stepper-motor-with-a4988-driver-and-arduino/

You need to post your program.

My wild guess is that you have some floating input pins.

I have no experience of the library you are using. Have you tried the AccelStepper library

The Pololu A4988 web page has a good wiring diagram and other useful info.

...R
Stepper Motor Basics
Simple Stepper Code

when I disconnected the step and direction wires from the Arduino while it was powered on

One rather quick way of destroying equipment is to change wiring while the equipment is powered.

Robin2,

Thank-you for the link. From what I can see, the only pin on the A4988 that isn't attached to something is the 'EN' pin on the top-left.

Further to my previous post, I think I may have found a solution. I found this thread, which suggested putting an LED between the step pin and ground to see if there were spurious signals on startup. I did, and that solved the problem. The motor did not spin randomly, and worked perfectly when the main body of the program started.

I suspect that the LED is holding the step input low until it gets a signal from the Arduino, and that's the pin that was floating.

1 Like

Tbdanny:
I suspect that the LED is holding the step input low until it gets a signal from the Arduino, and that's the pin that was floating.

That was the sort of floating that I had in mind - though I was thinking of inputs to the Arduino rather than outputs. But as you did not post your program ...

Writing the step pin LOW early in setup() may be equally effective. Or just using a resistor (perhaps 4k7) to pull the pin to GND.

...R

The A4988's step and direction inputs do not have internal pull-down resistors, so you should
add external pull-downs (10k or so). Better designed driver chips have internal pull-downs on
all the "dangerous" inputs for precisely this reason - runaway motors during microcontroller
reset/initialization time. (For instance the DRV8825 has pull-downs on step and direction)

BTW Disconnecting logic signals when powered up is not endangering a circuit (other than by static
electricity), but disconnecting stepper motor wires can destroy stepper drivers, due to arcing
from the highly inductive load.

I'm working on automating my model railroad turntable with a NEMA17 stepper motor and an Arduino Uno. Over the last couple of weeks, I've built and tested the various subassemblies, and got them working in isolation. However, I've just having them work together, and they're not working at all.

The turntable has a hall effect sensor mounted on the outside, to detect a magnet mounted on the end of the turntable bridge. This is to be used for calibration, and the turntable is supposed to stop when it the magnet is detected. There's also a 4-digit 7-segment LED display on the control panel, driven by a MAX7219 chip, which will display the DCC address of the selected locomotive.

After putting everything together, I tested it with the following code:

#include <Arduino.h>
#include "BasicStepperDriver.h"
#include <LedControl.h>

#define SENSOR_PIN 10 //For hall effect sensor

//LED output pins
#define GR_LED_PIN 4
#define RD_LED_PIN 5

//Motor control pins
#define MT_STEP 2
#define MT_DIR 3
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM 3 //2 is the lowest at 16 microsteps for smooth movement. 1 is too jerky.
// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 16
//For motor direction, positive is clockwise and negative is anticlockwise

//LED Display Pins
#define RO_CLK 7
#define RO_DIN 8
#define RO_LOAD 9

//Occupancy Sensor
#define OCC_PIN A0

//Below defines and creates the LED controller object
LedControl dispLED = LedControl(RO_DIN,RO_CLK,RO_LOAD,1);

//Create the Stepper Motor object.
BasicStepperDriver step_motor(MOTOR_STEPS, MT_DIR, MT_STEP);

void setup() {

  //Set up the LED pins:
  pinMode(GR_LED_PIN, OUTPUT);
  pinMode(RD_LED_PIN, OUTPUT);

  //Set up the hall effect sensor
  pinMode(SENSOR_PIN, INPUT);

  // put your setup code here, to run once:
  //Initialise the LED controller
  dispLED.shutdown(0,false);
  /* Set the brightness to a medium values */
  dispLED.setIntensity(0,12);
  /* and clear the display */
  dispLED.clearDisplay(0);
  disNumLed (1234);
  delay(1000);
  dispLED.clearDisplay(0);

  //Initialise the stepper motor
  step_motor.begin(RPM, MICROSTEPS);
  step_motor.enable();
}

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

}

void calibrateTurntable(){
  /*Below boolean acts as a flag as to 
   * whether the turntable should be
   * calibrating or not.
   */
  boolean turning = true;

  while (turning){
    step_motor.move(-1);
    delay(10);
    if (digitalRead(SENSOR_PIN) == HIGH){
      turning = false;
    }
  }
}

void disNumLed (int disNum){
  //Takes an integer and displays it on the 4-digit LED display
  int firstDigit;
  int secondDigit;
  int thirdDigit;
  int fourthDigit;

  /*The 4-digit single module has digit 1 on left and 4 on the right.  Hence,
   * it needs to be added in reverse order.  firstDigit to position 3, through
   * to fourthDigit in position 0.
   */
  
  dispLED.clearDisplay(0);
  firstDigit = disNum % 10; //Return remainder of division operation (modulus)
  dispLED.setDigit(0,3,firstDigit,false);
  
  if (disNum > 9){
    //If int is still greater than 9, then there should be another digit (base 10)
    disNum /= 10; //Move to next digit
    secondDigit = disNum % 10;
    dispLED.setDigit(0,2,secondDigit,false);
  }
  if (disNum > 9){
    disNum /= 10; //Move to next digit
    thirdDigit = disNum % 10;
    dispLED.setDigit(0,1,thirdDigit,false);
  }
  if (disNum > 9){
    //Remainder would be above 10
    disNum /= 10; //Move to next digit
    fourthDigit = disNum; //As it's the only digit left
    dispLED.setDigit(0,0,fourthDigit,false);
  }
}

However, this didn't give the intended results. The turntable bridge only moved a handful of steps the first couple of times. After resetting the arduino 3 times, it started moving in a full circle. However, the LED display on the control panel went haywire while it was doing so. Furthermore, the arduino seemed to ignore the hall effect sensor completely. I know that it works, as I tested it with the turntable bridge and a sketch that lit up an LED just a few minutes before testing this one.

I suspect that the magnetic field of the stepper motor is interfering with the other components and causing false signals. The hall effect sensor is about 4.5" away, and the MAX7219 chip about 1' away. Am I correct? If so, how do I go about shielding the stepper motor so things work the way they're supposed to?

Update:

I've just realised where the problem is in my code. The calibrateTurntable() function is never called. But that doesn't explain why the motor was turning, or why the LED display keeps misbehaving.

Further update: I tried it with calling the calibrateTurntable() function in the setup section, and no good. The turntable continues to rotate in the same direction and ignore the hall effect sensor. I also had to reset the Arduino a couple of times to get it to actually work, just like before. One point of note is that between the two tries, the direction of the rotation in the calibrateTurntable() function was reversed, but the turntable rotated the same direction (clockwise instead of counter-clockwise).

Any help would be appreciated.

I am not familiar with the stepper library you are using. Please post a link to its documentation.

What stepper motor driver are you using?

A Nema17 motor seems large for a model train turntable. I did try one a couple of years ago but found it was too noisy due in part to the way it was mounted.

At the moment I have a small train (not loco) turntable driven by a small 28BYJ-48 stepper motor. I am using locator pins extended by a servo to guarantee correct track alignment.

...R
Stepper Motor Basics
Simple Stepper Code

Here's the documentation for the library: GitHub - laurb9/StepperDriver: Arduino library for A4988, DRV8825, DRV8834, DRV8880 and generic two-pin (DIR/STEP) stepper motor drivers. I'm using an A4988 chip, set to 16-microsteps. I've got the NEMA17 mounted directly beneath the turntable, with the turntable bridge directly on top of it.

As far as I can see that library uses delayMicros() to manage the timing and the Arduino can't do other things during that period.

My suggestion is to use the non-blocking functions in the widely used AccelStepper library or simply write your own code like in the second (non-blocking) example in this Simple Stepper Code

...R
Stepper Motor Basics

One reason for the stepper causing other components to act up is power. What do you have powering the stepper? Hopefully not the Arduino.

Robin2, thank-you. I'll give it a go with the other libraries.

WildBill, I have a voltage regulator board powering everything. The input for this is from a 12v plugpack, which has two leads going off to the motor power input of the A4988 chip. Everything else is powered from the 5v output of this board.

Should the 12v supply to the motor be completely separate? I can do this if needed.

5V is not enough for a typical stepper driver. Use the 12V directly to the A4988 module.
The A4988 requires a minimum motor supply of 8V, and will perform better with higher voltages.

Sharing power with the stepper driver will have been putting loads of noise onto the 5V rail, which
is always going to lead to disaster.

Power motors separately from logic and sensors is always a very good rule to follow.

What is the current rating of your 12V PS? Many HEFs have open collector outputs that must be held HIGH with a pullup resistor and switch LOW when activated, can you post a link to that HEF? If you are powering Arduino with 12V into the barrel jack or Vin pin, how much load is on the output pins and 5V pin?

To clarify, I have a 12v 4A supply going into a standard power jack, on the outside of the case holding the Arduino and other circuitry. Two wires come off the jack to the A4988 motor supply, and another two go to the voltage regulator board. This regulates it down to 5v, which drives everything else, including the 5v supply of the A4988 and the Arduino via the VIN and GND pins.

My next step will be to provide a second, 5v 4A supply to drive the Arduino and sensors, with the 12v supply only powering the motor itself.

It's Boxing Day here in Australia, and I've had another crack at this. I've rigged up a separate 12v power supply, so that I've got 12V 4A going to the motor supply pins of the A4988 from one plugpack. From the other plugpack, I've got 5V 4A going to power the Arduino, hall effect sensor and LED display. I've also changed over to the AccelStepper library. My current code is as per below:

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


#define SENSOR_PIN 10 //For hall effect sensor

//LED output pins
#define GR_LED_PIN 4
#define RD_LED_PIN 5

//Motor control pins
#define MT_STEP 2
#define MT_DIR 3
AccelStepper turnMot(1, MT_STEP,MT_DIR);

//LED Display Pins
#define RO_CLK 7
#define RO_DIN 8
#define RO_LOAD 9

//Occupancy Sensor
#define OCC_PIN A0

//Below defines and creates the LED controller object
LedControl dispLED = LedControl(RO_DIN,RO_CLK,RO_LOAD,1);

void setup() {

  //Set up the LED pins:
  pinMode(GR_LED_PIN, OUTPUT);
  pinMode(RD_LED_PIN, OUTPUT);

  //Set up the hall effect sensor
  pinMode(SENSOR_PIN, INPUT);

  // put your setup code here, to run once:
  //Initialise the LED controller
  dispLED.shutdown(0,false);
  /* Set the brightness to a medium values */
  dispLED.setIntensity(0,12);
  /* and clear the display */
  dispLED.clearDisplay(0);
  disNumLed (1234);
  delay(1000);
  dispLED.clearDisplay(0);

  //Initialise the stepper motor
  turnMot.setMaxSpeed(159);
  turnMot.setSpeed(159);

  //Calibrate the turntable
  calibrateTurntable();
}

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

}

void calibrateTurntable(){
  /*Below boolean acts as a flag as to 
   * whether the turntable should be
   * calibrating or not.
   */
  boolean turning = true;

  while (turning){
    turnMot.move(1);
    delay(10);
    if (digitalRead(SENSOR_PIN) == HIGH){
      turning = false;
    }
  }
}

void disNumLed (int disNum){
  //Takes an integer and displays it on the 4-digit LED display
  int firstDigit;
  int secondDigit;
  int thirdDigit;
  int fourthDigit;

  /*The 4-digit single module has digit 1 on left and 4 on the right.  Hence,
   * it needs to be added in reverse order.  firstDigit to position 3, through
   * to fourthDigit in position 0.
   */
  
  dispLED.clearDisplay(0);
  firstDigit = disNum % 10; //Return remainder of division operation (modulus)
  dispLED.setDigit(0,3,firstDigit,false);
  
  if (disNum > 9){
    //If int is still greater than 9, then there should be another digit (base 10)
    disNum /= 10; //Move to next digit
    secondDigit = disNum % 10;
    dispLED.setDigit(0,2,secondDigit,false);
  }
  if (disNum > 9){
    disNum /= 10; //Move to next digit
    thirdDigit = disNum % 10;
    dispLED.setDigit(0,1,thirdDigit,false);
  }
  if (disNum > 9){
    //Remainder would be above 10
    disNum /= 10; //Move to next digit
    fourthDigit = disNum; //As it's the only digit left
    dispLED.setDigit(0,0,fourthDigit,false);
  }
}

What happens when I try to run this is interesting. The sequence of events goes as follows:

  1. The LED display will show '8888' and the turntable will rotate a certain amount in the counter-clockwise direction. It appears to be the same amount each time.
  2. The LED will then show '1234' as per the setup() function, then go blank. So that's working as it's meant to.
  3. The stepper motor will not move when it reaches the point where it should be calling the calibrateTurntable() function. Instead, I just hear a faint, high-pitched whine.

As such, could I please get advice on the following:

  1. Why are the stepper and LED display behaving strangely on startup?
  2. Why isn't the turntable moving when it's called in the calibrateTurntable() function?

For what it's worth, I have the A4988 chip set to 1/16 of a step, which is the resolution I need for the track alignment. I'm not sure if the AccelStepper library supports this, but the previous one I was using did. I also tried this with the other library I was using, and got the same results. I've also tried a new A4988 and a new Arduino Uno, with the same results.

This line

   turnMot.move(1);

tells the AccelStepper library how far you want to move but it does NOT tell it to make the move. You need to call run() or runSpeed() for that to happen.

If you just want to move one step at a time for the calibration process then it might make more sense to replace turnMot.move(1) with turnMot.runToNewPosition(1) - which both identifies the position and causes the move to happen.

It's worth spending some time reading the AccelStepper Class Reference to familiarize yourself with the functions available.

...R