Stuttering Stepper Motor

Hello,

I am trying to accomplish the following:
I have a toggle switch, a stepper motor, and a hollow shaft potentiometer that sits on the motor shaft. When the state of the toggle switch changes (e.g. switched from one side to the other), I would like the stepper to move to one of two specific positions, call them "open" and "closed". To move to the open position from the closed position, the motor has to turn CCW and in order to move from the closed position to the open position, the motor has to turn CW.

Here is the picture of my setup:

I am using an Arduino Mega, an A4988 driver, and a NEMA17 stepper motor. I have not included the connections for the motor, the toggle switch, or a blue LED with a resistor that I have connected in the picture because I was afraid it would make it too difficult to see the other connections. The blue LED with a resistor is connected in parallel with the motor power supply, just to make sure I'm actually getting power. The toggle switch is connected to pin 28 and a ground pin.

Initially, I wrote code for this with delays, for example:

void setup() {
  // Sets the two pins as Outputs
  pinMode(stepPin,OUTPUT); 
  pinMode(dirPin,OUTPUT);
}
void loop() {
  digitalWrite(dirPin, HIGH); // Enables the motor to move in a particular direction
  // Makes 200 pulses for making one full cycle rotation
  for(int x = 0; x < 800; x++) {
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(700);    // by changing this time delay between the steps we can change the rotation speed
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(700); 
  }
  delay(1000); // One second delay
  
  digitalWrite(dirPin,LOW); //Changes the rotations direction
  // Makes 400 pulses for making two full cycle rotation
  for(int x = 0; x < 1600; x++) {
    digitalWrite(stepPin,HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin,LOW);
    delayMicroseconds(500);
  }
  delay(1000);
}

However, my motor would stutter when the program started and I read online that using delays and while loops can sometimes cause this, since it stops the Arduino from doing anything else while those are happening. I got rid of the delays and tested it with just the motor stepping, like this:

byte stepPin = 3;
byte dirPin = 2;
bool nextStep = HIGH;
int stepDelay = 700;
unsigned long currentMicros;
unsigned long stepMicros;


void setup() {
  pinMode(stepPin, OUTPUT); 
  pinMode(dirPin, OUTPUT);

}

void loop() {
  digitalWrite(dirPin, HIGH);
  currentMicros = micros();
  if (currentMicros - stepMicros >= stepDelay) 
  {
    nextStep = !nextStep;//swap next step state
    digitalWrite(stepPin, nextStep);
    stepMicros = currentMicros;
  }

}

This got rid of the stuttering. When I started testing with the potentiometer, I kept the while loop because I was ok with the Arduino stopping anything else during the while loop. Here is my first test code with the potentiometer:

int potPin = A3;
byte stepPin = 3;
byte dirPin = 2;
bool nextStep = LOW;
int stepDelay = 500;
unsigned long currentMicros;
unsigned long stepMicros;


void setup() {
  pinMode(stepPin, OUTPUT); 
  pinMode(dirPin, OUTPUT);
  
}

void loop() {
  digitalWrite(dirPin, HIGH);
  while(analogRead(potPin) < 500)
  {
    currentMicros = micros();
    if (currentMicros - stepMicros >= stepDelay) 
    {
      nextStep = !nextStep;//swap next step state
      digitalWrite(stepPin, nextStep);
      stepMicros = currentMicros;
    }
  }

}

When I do this, the motor works perfectly, no stuttering. However, when I went in and added the toggle switch, it stutters at the beginning. After the motor is done stuttering, the toggle and the motor work fine.

Here is my code with the toggle added:

#include <DebouncedSwitch.h>

//Potentiometer Constants
const int potPin = A3;
const byte potValOpen = 0;
const byte potValClosed = 700;
const byte potTolerance = 10;

//Motor Constants
const byte dirPin = 2;
const byte stepPin = 3;

//Toggle Constant
const byte toggleShutter1Pin = 28;

//Variables
bool nextStep = LOW;
int stepDelay = 500;
unsigned long currentMicros;
unsigned long stepMicros;
DebouncedSwitch toggle1(toggleShutter1Pin);

void setup() {
  //Serial.begin(9600);
  pinMode(toggleShutter1Pin, INPUT_PULLUP);
  pinMode(stepPin, OUTPUT); 
  pinMode(dirPin, OUTPUT);
}

void loop() {
  toggle1.update();
  //IF toggle is switched from OPEN -> CLOSE or CLOSE -> OPEN
  if(toggle1.isChanged())
  {
    
      //IF toggle is switched to OPEN
      if(toggle1.isDown())
      {
          digitalWrite(dirPin, HIGH);
          while(!(analogRead(potPin) <= potValOpen + potTolerance and analogRead(potPin) >= potValOpen - potTolerance))
          {
            stepMotor();
          }
      }
      else
      {
          digitalWrite(dirPin, LOW);
          while(!(analogRead(potPin) <= potValClosed + potTolerance && analogRead(potPin) >= potValClosed - potTolerance))
          {
            stepMotor();
          }
      }
    }
  

}

void stepMotor()
{
    currentMicros = micros();
    if (currentMicros - stepMicros >= stepDelay) 
    {
      nextStep = !nextStep;//swap next step state
      digitalWrite(stepPin, nextStep);
      stepMicros = currentMicros;
    }
}

I have tried double checking the motor connections, and checking my driver, but they seem to be working and connected correctly. I'm guessing it's something with my code, since the motor works perfectly with the test program I used when I first connected the potentiometer (see above), but I'm not really sure where to go from here.

Any help would be appreciated! Thanks!

The DebouncedSwitch library may have delays built in. Please post a link to the library source code.

  • Get into the habit of breaking the motor positive line, not the negative.

  • Show us actual images of the wiring.

1 Like

Here is the library information. You have to download the source code as a zip file.

I'd upload it, but it says I can't because I'm a new user

  • For slow switches, simply scan them every 20-50ms looking for a change in state; no debounce library needed.
1 Like

You are right on. That is why we ask for an annotated schematic. Also many of us do not have the parts in question so the frizz stuff is just a colored blob with missing or fuzzy nomenclature.

The library looks OK, but the switch is not shown in the wiring diagram. Please post complete wiring diagrams (images of pencil and paper drawings are preferred).

To debug the stuttering, put in Serial.println((millis()) statements to examine the startup timing. Be sure to use a high serial baud rate, at least 115200.

Also @LarryD suggested, post a close up, focused photo of your wiring. Hopefully you are not using a breadboard, as they cannot support motor currents. The tracks burn and that eventually leads to destruction of the motor driver.

Ok, I will post an annotated picture with everything in it and print the millis, like you suggest.

Currently, the wires are all jumbled together inside a control box with other electronics. I can send you a picture, but it will just look like a box full of wires. Would it be helpful to put the circuit together using a breadboard, just so everyone can see what the circuit looks like neatly?

I just noticed that the only time the stuttering happens is if the motor power supply is on before I connect power to the Arduino. If I download the program while the switch to the motor power supply is off, wait a second, and then turn the motor power supply back on, it doesn't happen. It's almost as if the Arduino is trying to move the motor before the loop starts.

  • Wire management is a huge part of a project.
    Wires should be properly routed: kept away from high current inductive wires, kept as short as reasonable.

  • How can you put 700 into a byte ? :roll_eyes:
    const byte potValClosed = 700;

1 Like
  • If you want, we can discuss this version of the sketch; it probably will need some tweaking.
//
//================================================^================================================
//
#define LEDon                     HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff                    LOW

#define CLOSED                    LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define OPENED                    HIGH

#define ENABLED                   true
#define DISABLED                  false

#define CW                        HIGH
#define CCW                       LOW

#define STOPPED                   0
#define FWD                       1
#define REV                       2

//====================================
//GPIO Constants

const byte potPin               = A3;

const byte dirPin               = 2;
const byte stepPin              = 3;
const byte heartbeatLED         = 13;

const byte toggleShutter1Pin    = 28;
//const byte toggleShutter1Pin    = 8;  //testing

//====================================
//Variables
byte lastToggleShutter1Pin;
byte nextStep                   = LOW;
byte motorFlag                  = STOPPED;

const int potValOpen            = 0;
const int potValClosed          = 700;
const int potTolerance          = 10;

//timing stuff
unsigned long heartbeatTime;
unsigned long checkSwitchTime;
unsigned long motorTime;

unsigned long  stepDelay        = 500ul;
//unsigned long  stepDelay        = 500ul; //testing


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  Serial.begin(115200);

  //=====================================
  pinMode(toggleShutter1Pin, INPUT_PULLUP);

  lastToggleShutter1Pin = digitalRead(toggleShutter1Pin);

  //=====================================
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);

  pinMode(heartbeatLED, OUTPUT);

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  //========================================================================  T I M E R  heartbeatLED
  //heartbeat LED helps to show if there is code blocking
  //is it time to toggle the heartbeat LED ?
  if (millis() - heartbeatTime >= 500ul)
  {
    //restart this TIMER
    heartbeatTime = millis();

    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //========================================================================  T I M E R  switches
  //is it time to scan our switches ?
  if (millis() - checkSwitchTime >= 50ul)
  {
    //restart this TIMER
    checkSwitchTime = millis();

    checkSwitches();
  }

  //========================================================================  T I M E R  motor
  //is it time to try and step the motor ?
  if (motorFlag != STOPPED && micros() - motorTime >= stepDelay)
  {
    //restart this TIMER
    motorTime = micros();

    int reading = analogRead(potPin);

    //=====================================
    if (motorFlag == FWD)
    {
      //====================
      if (!(reading <= (potValOpen + potTolerance) && reading >= (potValOpen - potTolerance)))
      {
        //swap next step state
        nextStep = !nextStep;

        digitalWrite(stepPin, nextStep);
      }

      //====================
      //we are at the destination
      else
      {
        motorFlag = STOPPED;

        //swap next step state
        nextStep = LOW;

        digitalWrite(stepPin, nextStep);
      }
    }

    //=====================================
    else if (motorFlag == REV)
    {
      //====================
      if (!(reading <= (potValClosed + potTolerance) && reading >= (potValClosed - potTolerance)))
      {
        //swap next step state
        nextStep = !nextStep;

        digitalWrite(stepPin, nextStep);
      }

      //====================
      //we are at the destination
      else
      {
        motorFlag = STOPPED;

        //swap next step state
        nextStep = LOW;

        digitalWrite(stepPin, nextStep);
      }
    }
  }


  //========================================================================
  //                     Other non-blocking code goes here
  //========================================================================


} //END of   loop()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//
void checkSwitches()
{
  byte state;

  //========================================================================  toggleShutter1Pin
  state = digitalRead(toggleShutter1Pin);

  //=====================================
  //has this switch changed state ?
  if (lastToggleShutter1Pin != state)
  {
    //update to the new state
    lastToggleShutter1Pin = state;

    //====================
    //did the switch close ?
    if (state == CLOSED)
    {
      digitalWrite(dirPin, CW);

      motorFlag = FWD;
    }

    //====================
    //did the switch open ?
    else if (state == OPENED)
    {
      digitalWrite(dirPin, CCW);

      motorFlag = REV;
    }

  } //END of this switch

  //========================================================================  nextSwitch

} //END of   checkSwitches()



//================================================^================================================