Please help debug stepper motor code issue

Hello every one, I am very new to this and was hoping I could get some help/advice.

I have a school project requiring me to control 2 stepper motors. I am starting out small trying to control just one motor. For now the plan is to push a button, have the motor move one full revolution, then pause and move another full revolution in the other direction and then stop.

I am using an Arduino UNO, an Easydriver and a NEMA17 motor.

I have the push button working. I was able to the motor to turn and then stop. I am able to get the motor to turn, pause, change direction. Here is where my problem start. Instead of stopping, the program loops back the delay and continues running. I thought it wold stop, not loop back.

Another interesting issue, no matter what I make DISTANCE2, it only runs whatever is in DISTANCE1.

Thank you in advance, here is my code

#define DISTANCE1 1600      // distance for 1st travel
#define DISTANCE2 1600      // distance for 2nd travel

//1600 steps per revalution
int StepCounter = 0;
int Stepping = false;

void setup() {               
  
   pinMode(8, OUTPUT);        // pin 8 controles dirction
  pinMode(9, OUTPUT);         // pin 9 controles steps
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  
  pinMode(3,INPUT_PULLUP);    // Creates push button
  
  Serial.begin(9600);         // Alows serial monitoring
}

void loop() {
  {
    Serial.println(StepCounter);
  
  }
  
  if (digitalRead(3) == LOW && Stepping == false)   // Push button to start Program
  {
    Stepping = true;
  }

  if (Stepping == true)
  {
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);

    StepCounter = StepCounter + 1;

    if (StepCounter == DISTANCE1)   // Distance to stop at
      {
        StepCounter = 0;            // Reset counter to 0
        //Stepping = false;         // stops program, when activated motor stops 
        
          delay(5000);              // Pause 5 seconds
          digitalWrite(8, HIGH);    // Change direction
          digitalWrite(9, HIGH);    // Run next distance
          delay(1);         
          digitalWrite(9, LOW);
          delay(1);
      }
      
      
      if (StepCounter == DISTANCE2)  // Distance to stop at
      {
        StepCounter = 0;              //Reset counter
        Stepping = false;             // stops program, istead loops back to delay(5000)  
      }
  }
}

when you are stepping your code does two tests

    if (StepCounter == DISTANCE1)   // Distance to stop at
    {
      ...
    }


    if (StepCounter == DISTANCE2)  // Distance to stop at
    {
      ...
    }

when you are moving forward, the first test catches what you expect and reverse the motor direction after DISTANCE1 steps. But then as you keep moving backward, the first test is still active and will catch the StepCounter == DISTANCE1 condition before the second one which will have the side effect to reset StepCounter to 0 and thus not entering the second test and you'll keep going.

you need a test when moving forward and one when moving backward

What JML said.

The kind of situation you are describing is called a state machine, and there is a State Machine tutorial you should read. Actually if you search for state machine you'll find more then one tutorial on here.

Also, you need to lean to implement delays without using delay. For what you are doing now it probably doesn't matter, but it will matter as your code gets more complex. If you are ready to think about that read
Using millis for timing
Demonstration for several things at the same time

++Karma; //For posting you code correctly on your first post and for making a decent effort.

i think you need to keep track of which direction you are turning. when you reach DISTANCE going in the one direction you simply want to reset the count and change direction. when you reach DISTANCE in the reverse direction you also want to reset the count and direction for the next time, but also set stepping to false

Thank you everyone for the response.

J-L-M, I think I understand your suggestion, but I am not sure on how to implement it. I thought that

    if (StepCounter == DISTANCE1)   // Distance to stop at
    {
      ...
    }


    if (StepCounter == DISTANCE2)  // Distance to stop at
    {
      ...
    }

was a test for each instance, Distance1 for forward, Distance2 for reverse. What else would I need to complete the additional test?

PerryBebbington, I looked into the state machine. I looks like it could do the job. Being that I am using 2 stepper motor's, I planed on using Accelstepper. I am wondering how this would transfer when I get to that point. While I am learning this and following tutorials for Accelstepper, I am hesitant on jumping into a state machine for this. Any thoughts?

GCJR, this is exactly what I am trying to do and thought I was. When I reached DISTANCE1, I had the counter reset, or tried to. The motor did change direction but did not go to DISTANCE2, continues to repeat DISTANCE1.

GCJR, this is exactly what I am trying to do and thought I was. When I reached DISTANCE1, I had the counter reset, or tried to. The motor did change direction but did not go to DISTANCE2, continues to repeat DISTANCE1.

each time loop() is called it checks if steeping is true and if stepCounter == DISTANCE. it will never reach that 2nd test for DISTANCE for various reasons, but there needs to be a test if it reaches DISTANCE and is going in the reverse direction

(step thru your code in your mind assuming DISTANCE1 == DISTANCE2 == 2)

muellercandd:
PerryBebbington, I looked into the state machine. I looks like it could do the job. Being that I am using 2 stepper motor's, I planed on using Accelstepper. I am wondering how this would transfer when I get to that point. While I am learning this and following tutorials for Accelstepper, I am hesitant on jumping into a state machine for this. Any thoughts?

I don't know anything about Accelstepper so cannot comment on that part. The reason I think you need a state machine is because what you have described so far seems to break down into 3 distinct actions, each of which can be defined as a state. Those state are stop, run forward and run backwards. You might think there are different states to those, that's fine; just make a list of all the possible states and what has to happen in each state for it to transition to a different state.

Get it working for 1 motor to your satisfaction, and make sure you understand it. When you've done that I hope you will be able to see how to extend the same idea for 2 or more motors.

muellercandd:
J-L-M, I think I understand your suggestion, but I am not sure on how to implement it. I thought that
...
was a test for each instance, Distance1 for forward, Distance2 for reverse. What else would I need to complete the additional test?

you need something that says "if I'm going forward, only test against DISTANCE1, if I'm going backward then only test against DISTANCE2.

that can be achieved with a boolean variable for example that you set to false when you go backward and starts being true when going forward.

if (goingForward) {
    if (StepCounter == DISTANCE1)   // Distance to stop at
    {
      ...
      goingForward = false; // remember we changed direction
    }
} else {
    if (StepCounter == DISTANCE2)  // Distance to stop at
    {
      ...
    }
}

I will take these ideas and plug away. Thanks for the idea's. I am sure I will be back, probably the weekend.

Ok, I have been looking around and have decided to go a slightly different rout. Again it works almost as expected. Because this program will run the travel distance many times, I decided to go with a function. I get it to enter travel DISTANCE1 and displays Distance Traveled in the serial monitor. I was hoping that the return; would send it back to run travel DISTANCE2, but like earlier it just jumps to travel DISTANCE1 again.

I can not seem to find any good examples that show how to do this. If the answer is the same as previously, I apologize for asking the same question, but I just cant wrap my head around what is needed.

# define DISTANCE1 1600
# define DISTANCE2 3200
# define LEFT 800
# define RIGHT 800
int STEPS = 0;
int StepCounter = 0;
int Stepping = false;


void setup() {
  
  pinMode(8, OUTPUT);        // pin 8 controles dirction
  pinMode(9, OUTPUT);         // pin 9 controles steps
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);

  pinMode(3,INPUT_PULLUP);    // Creates push button
 
  Serial.begin(9600);         // Alows serial monitoring
}

void loop() {

  {
    Serial.println(StepCounter);
  }

  if (digitalRead(3) == LOW && Stepping == false)   // Push button to start Program
  {
    Stepping = true;
  }

  if (Stepping == true)
  {
  travel (DISTANCE1);
  STEPS = DISTANCE1;
  //turnLeft (LEFT);
  travel (DISTANCE2);
  STEPS = DISTANCE2;
  //turnRight (RIGHT);
  }

 // END LOOP    HOW TO?????

}

void travel (int distance) {

    digitalWrite(8, LOW);           //Sets motor to FWD
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);  

       
    StepCounter = StepCounter + 1;

    if (StepCounter == STEPS)   // Distance to stop at
      
      {
        StepCounter = 0;
        //Stepping = false;
        Serial.println("Distance Traveled");
        delay (2000);
      }
    if (StepCounter == 0)
    {
    return; //start next line from void loop() HOW TO????
    }
}



void turnLeft (int left) {

    digitalWrite(8, HIGH);          // Changes direciton
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);
}

void turnRight (int right) {

    digitalWrite(8, LOW);          // Changes direciton
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);
}

Again, thank you

You never change motor direction.

Another problem is the steps variable. Get rid of it- you are passing the number of steps you want to the travel function but you ignore it.

After you have done the two travel calls set stepping false.

 // END LOOP    HOW TO?????

What do you mean by this? loop() doesn't end, it goes back to the start, that's the whole point of it, it loops forever.

Thanks for the pointer on removing the STEPS, I got that working and it makes sense.

Now when I test when I test travel, turnLeft, turnRitht individually the serial monitor show's traveled or turned, pauses and starts over. If I set my code like this

  travel (DISTANCE1);
  turnLeft (LEFT);
  travel (DISTANCE2);
  turnRight (RIGHT);

The count just continues to rise. If set like

  travel (DISTANCE1);
  //turnLeft (LEFT);
  travel (DISTANCE2);
  //turnRight (RIGHT);

It only runs to whatever value I have DISTANCE2 set at.

I am not sure how to tell the program to run travel (DISTANCE1) then move to turnLeft then travel then turnRight.

When I said // END LOOP how to????

this is where I want the program to set stepping = false

but if I place it there the program will only run while holding the button

Here is the updated code

# define DISTANCE1 1600
# define DISTANCE2 1700
# define LEFT 800
# define RIGHT 850

int StepCounter = 0;
int Stepping = false;


void setup() {
 
  pinMode(8, OUTPUT);        // pin 8 controles dirction
  pinMode(9, OUTPUT);         // pin 9 controles steps
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);

  pinMode(3,INPUT_PULLUP);    // Creates push button
 
  Serial.begin(9600);         // Alows serial monitoring
}

void loop() {

  {
    Serial.println(StepCounter);
  }

  if (digitalRead(3) == LOW && Stepping == false)   // Push button to start Program
  {
    Stepping = true;
  }

  if (Stepping == true)
  {
  travel (DISTANCE1);
  turnLeft (LEFT);
  travel (DISTANCE2);
  turnRight (RIGHT);
  }

  //Stepping = false; Set stepping = false after all directiont commands have been run
}

void travel (int distance) {

    digitalWrite(8, LOW);           //Sets motor to FWD
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1); 

       
    StepCounter = StepCounter + 1;

    if (StepCounter == distance)   // Distance to stop at
     
      {
        StepCounter = 0;
        //Stepping = false;
        Serial.println("Distance Traveled");
        delay (2000);
      }
    if (StepCounter == 0)
    {
    return; //start next line from void loop() HOW TO????
    }
}



void turnLeft (int left) {

    digitalWrite(8, HIGH);          // Changes direciton
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);

       StepCounter = StepCounter + 1;

    if (StepCounter == left)   // Distance to stop at
     
      {
        StepCounter = 0;
        //Stepping = false;
        Serial.println("Turned Left");
        delay (2000);
      }
    if (StepCounter == 0)
    {
    return; //start next line from void loop() HOW TO????
    }
}

void turnRight (int right) {

    digitalWrite(8, LOW);          // Changes direciton
    digitalWrite(9, HIGH);          // Run motor
    delay(1);         
    digitalWrite(9, LOW);
    delay(1);


       StepCounter = StepCounter + 1;

    if (StepCounter == right)   // Distance to stop at
     
      {
        StepCounter = 0;
        //Stepping = false;
        Serial.println("Turned Right");
        delay (2000);
      }
    if (StepCounter == 0)
    {
    return; //start next line from void loop() HOW TO????
    }
}

how do you turn the motor? i see turnLeft() and turnRight() affecting pins 8 & 9 which are associated with motor direction and enable according to the comments.

why do all functions turn the motor on for only 1 msec (delay(1) before turning it off?

should travel() have a direction argument.

Eventually there will be a second motor added to this. when that happens, pin 10 and 11 will drive second motor. in turnLeft or trunRight, pin 10 will be the opposet of pin 8, causing the device the motors drive to turn. SOmething like

void turnLeft (int left) {

    digitalWrite(8, HIGH);          // Changes direciton
    digitalWrite(10, LOW); 
    digitalWrite(9, HIGH);          // Run motor
    digitalwrite(10,HIGH);
    delay(1);
    digitalWrite(10,LOW);         
    digitalWrite(9, LOW);
    delay(1);

I wanted to get one motor working before adding the second and having more stuff to debug.

The delay(1) is there only because it was in the reloaded examples with IDE to turn the motor.

I don't believe that travel() needs and argument, as it will never be in reverse.

When I said // END LOOP how to????

this is where I want the program to set stepping = false

but if I place it there the program will only run while holding the button

Your approach to the program is still to start at the top of loop() and work through once with all the activity taking place by the time it gets to the bottom of loop(), then stopping. This isn't how to write effective programs. The proper way is explained in the 2 tutorials I gave you links to. Loop() should go round and round freely many thousands of times per second, updating and changing things that need to be updated and changed as it goes. If you follow the 2 tutorials and re-write your code along the lines of the methods suggested then your problems largely will go away.