Help troubleshooting motor movement issue

TLDR: After a random number of properly executed interval repetitions, my stepper motors keep moving instead of stopping. I suspect it is a coding issue, not a wiring issue, but I could be wrong and I have no idea where to start.

I'm working with an Arduino Mega and the AccelStepper library to help me move a pair of stepper motors in a pattern by pulsing a pair of DM542 microstep drivers. I'm also beeping a piezo and using a button to tell the device to start the run sequence. I've successfully created a program that does everything I want it to do pretty reliably, but now I'm working on creating a variant movement pattern including some additional direction changes and wait periods and no matter what modifications I make to the code, I can't seem to stop the unit from randomly getting stuck moving in one direction when it's supposed to be stopping once it has reached a set travel distance and waiting, then changing direction again. My original code managed this fine... one time. I'm fairly confident that I've got all of the settings on the drivers correct for my motors, I've septuple checked my wiring, so I'm fairly confident that isn't the issue. Here's the original code for reference:

`// Include Accel Stepper library (allows control of various steppers)
#include <AccelStepper.h>

// Define microstep controller connections:
  // Motor 1
#define dirPin1 46
#define stepPin1 48
#define motorInterfaceType 1
AccelStepper stepper1 = AccelStepper(motorInterfaceType, stepPin1, dirPin1);
  // Motor 2 (identical interface)
#define dirPin2 42
#define stepPin2 44
AccelStepper stepper2 = AccelStepper(motorInterfaceType, stepPin2, dirPin2);
  // Microcontroller settings
const int stepsPerRevolution = 200;

// Set up paizo buzzer
int buzzer = 52; //input is set to pin 52
const int buttonPin = 50;

// Set up control push button
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;

// Adjust qty of tray segment movements
int n1 = 20;
int n2 = 1+n1;
int i;


// Calibration Tools (adjust numbers at the end of each "#define" line below to set opperating parameters)
  // Set motors' speed/acceleration
    // Speed set 1
    #define motorSpeed1 5000
    #define motorAccel1 5000
    // Speed set 2
    #define motorSpeed2 5000 
    #define motorAccel2 5000
  // Set travel distances
    #define distance1 3000
    #define distance2 3000
  // Set pellet exposure time
    #define adminLength 30000
  // Set "tray move & image" wait period duration
    #define trayImageMove 60000
  // Set Hz of tones (1-3)
    #define toneHz1 1000
    #define toneHz2 4000
    #define toneHz3 1000
  // Set duration (miliseconds) of tones (1-3)
    #define toneLength1 200
    #define toneLength2 500
    #define toneLength3 2000



void setup() {
  // DO NOT EDIT THIS SECTION //
  stepper1.setMaxSpeed(10000);
  stepper1.setAcceleration(motorAccel1);
  stepper2.setMaxSpeed(10000);
  stepper2.setAcceleration(motorAccel2);

  // Define Variables
  #define resetPos1 stepper1.setCurrentPosition(0);
  #define resetPos2 stepper2.setCurrentPosition(0);
  #define debounce delay(200);

  // Define Beeps
  #define operatorBeep tone(buzzer,toneHz1,toneLength1);
  #define pelletBeep tone(buzzer,toneHz2,toneLength2);
  #define endBeep tone(buzzer,toneHz3,toneLength3);
  
  // Define Waits
  #define pelletWait delay(adminLength);
  #define imageWait delay(trayImageMove);

  // Define Movements
  #define moveForward resetPos1; resetPos2; while(stepper1.currentPosition() != -distance1 || stepper2.currentPosition() != -distance1){stepper1.setSpeed(-motorSpeed1); stepper2.setSpeed(-motorSpeed1); while(stepper1.runSpeed() || stepper2.runSpeed()){}}; resetPos1; resetPos2;
  #define moveBackward resetPos1; resetPos2; while(stepper1.currentPosition() != distance1 || stepper2.currentPosition() != distance1){stepper1.setSpeed(motorSpeed1); stepper2.setSpeed(motorSpeed1); while(stepper1.runSpeed() || stepper2.runSpeed()){}}; resetPos1; resetPos2;
}



void loop() {
  // DO NOT EDIT THIS SECTION //
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState) {
    buttonPushCounter++;
  } else {
    //do nothing
  }
  debounce; 
  if (buttonPushCounter % 2 == 1) {
    operatorBeep;
    debounce;
    for (i=0; i<n1; i++) {
      moveForward;
      pelletBeep;
      pelletWait;
      debounce; 
      }
    debounce;
    moveForward;
    endBeep;
    imageWait;
    int i = 0;
    debounce;
    for (i=0; i<n2; i++) {
      moveBackward;
      debounce;
      }
    debounce;
    endBeep;
    debounce;
    }
  debounce;
  lastButtonState = buttonState;
  debounce;
}`

I suspect the problem is my coding. This is my first electronics project ever however it's not just a hobby project so while I'm willing to learn more about Arduino and electronics generally speaking in the long term, I would really appreciate some hand holding as I am not only very new to this, but also on a time crunch so I may not always have to luxury to read how do solve my own problems. Please keep that in mind while replying if possible.

Here's the new code that isn't working. I'll upload a schematic of my wiring as well as soon as I can figure out how to make one without buying some expensive program. Please be patient on that part of things. Thanks.

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

// Define microstep controller connections:
  // Motor 1
#define dirPin1 46
#define stepPin1 48
#define motorInterfaceType 1
AccelStepper stepper1 = AccelStepper(motorInterfaceType, stepPin1, dirPin1);
  // Motor 2 (identical interface)
#define dirPin2 42
#define stepPin2 44
AccelStepper stepper2 = AccelStepper(motorInterfaceType, stepPin2, dirPin2);
  // Microcontroller settings
const int stepsPerRevolution = 200;

// Set up paizo buzzer
int buzzer = 52; //input is set to pin 52
const int buttonPin = 50;

// Set up control push button
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;

// Adjust qty of tray segment movements
int n1 = 20;
int n2 = 1+n1;
int i;


// Calibration Tools (adjust numbers at the end of each "#define" line below to set opperating parameters)
  // Set motors' speed/acceleration
    // Speed set 1
    #define motorSpeed1 5000
    #define motorAccel1 5000
    // Speed set 2
    #define motorSpeed2 5000 
    #define motorAccel2 5000
  // Set travel distances
    #define distance1 3000
    #define distance2 3000
  // Set pellet exposure time
    #define adminLength 10000
    #define emptyLength 5000
  // Set "tray move & image" wait period duration
    #define trayImageMove 60000
  // Set Hz of tones (1-3)
    #define toneHz1 1000
    #define toneHz2 4000
    #define toneHz3 1000
  // Set duration (miliseconds) of tones (1-3)
    #define toneLength1 200
    #define toneLength2 500
    #define toneLength3 2000



void setup() {
  Serial.begin(9600);
  stepper1.setMaxSpeed(10000);
  stepper1.setAcceleration(motorAccel1);
  stepper2.setMaxSpeed(10000);
  stepper2.setAcceleration(motorAccel2);

  // Define Variables
  #define resetPos stepper1.setCurrentPosition(0); stepper2.setCurrentPosition(0);
  #define debounce delay(200);

  // Define Beeps
  #define operatorBeep tone(buzzer,toneHz1,toneLength1);
  #define pelletBeep tone(buzzer,toneHz2,toneLength2);
  #define endBeep tone(buzzer,toneHz3,toneLength3);
  
  // Define Waits
  #define pelletWait delay(adminLength);
  #define emptyWait delay(emptyLength);
  #define imageWait delay(trayImageMove);

  // Define Movements
  #define moveForward while(stepper1.currentPosition() != -distance1 || stepper2.currentPosition() != -distance1){stepper1.setSpeed(-motorSpeed1); stepper2.setSpeed(-motorSpeed1); while(stepper1.runSpeed() || stepper2.runSpeed()){}};
  #define moveBackward while(stepper1.currentPosition() != distance1 || stepper2.currentPosition() != distance1){stepper1.setSpeed(motorSpeed1); stepper2.setSpeed(motorSpeed1); while(stepper1.runSpeed() || stepper2.runSpeed()){}};
}



void loop() {
  // DO NOT EDIT THIS SECTION //
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState) {
    buttonPushCounter++;
  } else {
    //do nothing
  }
  debounce; 
  if (buttonPushCounter % 2 == 1) {
    operatorBeep;
    delay (1000);
    for (i=0; i<n1; i++) {
      resetPos;
      moveForward;
      pelletBeep;
      pelletWait;
      endBeep;
      resetPos;
      moveForward;
      emptyWait;
      resetPos;
      moveBackward;
      pelletBeep;
      pelletWait;
      endBeep;
      resetPos;
      moveForward;
      emptyWait;
      delay (1000);
      }
    delay (1000);
    endBeep;
    resetPos;
    moveForward;
    imageWait;
    int i = 0;
    delay (1000);
    for (i=0; i<n2; i++) {
      resetPos;
      moveBackward;
      delay (1000);
      }
    delay (1000);
    operatorBeep;
    delay (1000);
    }
  delay (1000);
  lastButtonState = buttonState;
  delay (1000);
}

I don't have your setup, and didn't dig deeply into your code, but I'd be suspicious of these macros with the != test in them-- if they somehow get past distance, they may not ever stop.

I really dislike the style of mixing macros and code--it makes it very difficult to see what the intended function is. I'd much prefer what seems to be an equivalent function:

void moveForward(void) {
  while (stepper1.currentPosition() != -distance1 || stepper2.currentPosition() != -distance1) {
    stepper1.setSpeed(-motorSpeed1);
    stepper2.setSpeed(-motorSpeed1);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

But again, I'm not sure what this is supposed to do on your setup.

As functions instead of macros, you can debug them and see if they are doing what you think they are doing.

Thanks for your suggestion. I will try to rewrite the code that way. Once I define the function as indicated, would I just call the function as I was calling the macro or do I have to format it differently? This is my first ever Arduino project. I have some experience with python, but literally none with c++ unfortunately so I'm sorry I have no idea what I'm doing.

Nearly. In the example above from @DaveX , you would call it like this:

moveForward();

Thank you for the specific formatting. I realized after I typed that out I probably could have looked that up.

Here is the code with no macros

// Included libraries
#include <AccelStepper.h>
#include <MultiStepper.h>
// Register pins to control motors with libraries (motortype, Dir+Pin, Pul+Pin)
AccelStepper stepper1 = AccelStepper(1, 48, 46);
AccelStepper stepper2 = AccelStepper(1, 44, 42);
// Set up paizo buzzer and button pins
int buzzer = 52; //input is set to pin 52
const int buttonPin = 50;
// Push button elements
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
// Qty of tray movements
int n1 = 20;
int n2 = 21;
int i;


void setup() {
  Serial.begin(9600);
  stepper1.setMaxSpeed(10000);
  stepper1.setAcceleration(5000);
  stepper2.setMaxSpeed(10000);
  stepper2.setAcceleration(5000);
}

void moveForward(void) {
  while (stepper1.currentPosition() != -3000 || stepper2.currentPosition() != -3000) {
    stepper1.setSpeed(-3000);
    stepper2.setSpeed(-3000);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

void moveBackward(void) {
  while (stepper1.currentPosition() != 3000 || stepper2.currentPosition() != 3000) {
    stepper1.setSpeed(3000);
    stepper2.setSpeed(3000);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

void resetPos(void) {
  stepper1.setCurrentPosition(0);
  stepper2.setCurrentPosition(0);
}

void debounce(void) {
  delay(200);
}

void operatorBeep() {
  tone(buzzer,1000,200);
}

void pelletBeep() {
  tone(buzzer,4000,500);
}

void endBeep() {
  tone(buzzer,1000,2000);
}

void pelletWait() {
  delay(10000);
}

void emptyWait() {
  delay(5000);
}

void imageWait() {
  delay(60000);
}

void loop() {
  // DO NOT EDIT THIS SECTION //
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState) {
    buttonPushCounter++;
  } else {
    //do nothing
  }
  debounce; 
  if (buttonPushCounter % 2 == 1) {
    operatorBeep;
    delay (1000);
    for (i=0; i<n1; i++) {
      resetPos();
      moveForward();
      pelletBeep();
      pelletWait();
      endBeep();
      resetPos();
      moveForward();
      emptyWait();
      resetPos();
      moveBackward();
      pelletBeep();
      pelletWait();
      endBeep();
      resetPos();
      moveForward();
      emptyWait();
      delay (1000);
      }
    delay (1000);
    endBeep();
    resetPos();
    moveForward();
    imageWait();
    int i = 0;
    delay (1000);
    for (i=0; i<n2; i++) {
      resetPos();
      moveBackward();
      delay (1000);
      }
    delay (1000);
    operatorBeep();
    delay (1000);
    }
  delay (1000);
  lastButtonState = buttonState;
  delay (1000);
}

I'd like to add the stipulation that I would be fine with not monitoring to answer the question "where is the position now" between each movement, but I don't know any other methods for moving a set distance or having it run for a set time period or number of steps which I would actually prefer to what I am currently doing.

I'm still suspicious of the != here. I'd add some debugging like

void moveForward(void) {
  Serial.print(" moveForeward: ");
  Serial.print(stepper1.currentPosition());
  Serial.print(", ");
  Serial.print(stepper1.currentPosition());
  while (stepper1.currentPosition() != -3000 || stepper2.currentPosition() != -3000) {
    stepper1.setSpeed(-3000);
    stepper2.setSpeed(-3000);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

and consider changing to:

  while (stepper1.currentPosition() < -3000 || stepper2.currentPosition() < -3000) {
  //or 
  while (stepper1.currentPosition() > -3000 || stepper2.currentPosition() > -3000) {

depending on which side of -3000 you expect to be moving from. I think you might be somehow getting on the wrong side of -3000 and then this code keeps going.

Looks like you were right to suspect the "!=" @DaveX
I changed to "<" or ">" depending on desired direction and it ironed it right on out. I kept the debugging elements. I don't know what they do, but if they help, I'm glad to have them.

Final code that ended up working:

// Included libraries
#include <AccelStepper.h>
#include <MultiStepper.h>
// Register pins to control motors with libraries (motortype, Dir+Pin, Pul+Pin)
AccelStepper stepper1 = AccelStepper(1, 48, 46);
AccelStepper stepper2 = AccelStepper(2, 44, 42);
// Set up paizo buzzer and button pins
int buzzer = 52; //input is set to pin 52
const int buttonPin = 50;
// Push button elements
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
// Qty of tray movements
int n1 = 20;
int n2 = 21;
int i;


void setup() {
  Serial.begin(9600);
  stepper1.setMaxSpeed(10000);
  stepper1.setAcceleration(5000);
  stepper2.setMaxSpeed(10000);
  stepper2.setAcceleration(5000);
}

void moveForward(void) {
  Serial.print(" moveForeward: ");
  Serial.print(stepper1.currentPosition());
  Serial.print(", ");
  Serial.print(stepper1.currentPosition());
  while (stepper1.currentPosition() > -3000 || stepper2.currentPosition() > -3000) {
    stepper1.setSpeed(-5000);
    stepper2.setSpeed(-5000);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

void moveBackward(void) {
  Serial.print(" moveBackward: ");
  Serial.print(stepper1.currentPosition());
  Serial.print(", ");
  Serial.print(stepper1.currentPosition());
  while (stepper1.currentPosition() < 3000 || stepper2.currentPosition() < 3000) {
    stepper1.setSpeed(5000);
    stepper2.setSpeed(5000);
    while (stepper1.runSpeed() || stepper2.runSpeed()) {}
  };
}

void resetPos(void) {
  stepper1.setCurrentPosition(0);
  stepper2.setCurrentPosition(0);
}

void debounce(void) {
  delay(200);
}

void operatorBeep() {
  tone(buzzer,1000,200);
}

void pelletBeep() {
  tone(buzzer,4000,500);
}

void endBeep() {
  tone(buzzer,1000,2000);
}

void pelletWait() {
  delay(10000);
}

void emptyWait() {
  delay(5000);
}

void imageWait() {
  delay(60000);
}

void loop() {
  // DO NOT EDIT THIS SECTION //
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState) {
    buttonPushCounter++;
  } else {
    //do nothing
  }
  debounce; 
  if (buttonPushCounter % 2 == 1) {
    delay (1000);
    operatorBeep;
    delay (1000);
    for (i=0; i<n1; i++) {
      resetPos();
      moveForward();
      pelletBeep();
      pelletWait();
      endBeep();
      resetPos();
      moveForward();
      emptyWait();
      resetPos();
      moveBackward();
      pelletBeep();
      pelletWait();
      endBeep();
      resetPos();
      moveForward();
      emptyWait();
      delay (1000);
      }
    delay (1000);
    endBeep();
    resetPos();
    moveForward();
    imageWait();
    int i = 0;
    delay (1000);
    for (i=0; i<n2; i++) {
      resetPos();
      moveBackward();
      delay (1000);
      }
    delay (1000);
    operatorBeep();
    delay (1000);
    }
  delay (1000);
  lastButtonState = buttonState;
  delay (1000);
}

Thank you so much @DaveX and @wildbill

The debugging bits only help if you can read them. The Arduino/Tools/Serial Monitor could show you the stuff that gets printed out.

As for thanks, you're welcome. And you could go back and like the posts of the folks that helped you.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.