Trying to Use a limit switch to change the direction of rotation of Stepper motor

Hi guys a complete beginner here trying to get my hands dirty in the world of Arduino, i am trying to use a limit switch to change the direction of rotation of the Nema23 Stepper motor. What I want to achieve is say that the stepper motor is rotating in clockwise direction at a low rpm, say If the limit switch is pressed it should complete one entire circle in the anti-clockwise direction/opposite direction and should break out of the clockwise/(earlier direction of) rotation.

#include <Servo.h>  //Servo library
// Pin Definitions
#define LIMIT_SWITCH_PIN 7
#define dirPin 2   // Direction
#define stepPin 3  // Step Pulse
#define enaPin 4   // Enable Motor

// Variables
int stepDelay = 1250;  // Delay between steps in microseconds
int stepsToMove = 800;


void setup() {
  Serial.begin(9600);
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP);
  // // Set pin modes
  pinMode(enaPin, OUTPUT);
  digitalWrite(enaPin, LOW);  // Enable motor

  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
}

void switchHit() {
  digitalWrite(dirPin, HIGH);  
  for (int i = 0; i < stepsToMove; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(20);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelay - 20);
  }
}

void loop() {

  digitalWrite(dirPin, LOW); 
  for (int i = 0; i < stepsToMove; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(20);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelay - 20);

    if (digitalRead(LIMIT_SWITCH_PIN) == LOW) {
      switchHit();
      break;
    }
  }
  delay(3000); 

Here is the code that I am using.

The problem I am facing is that, say the stepper motor is in the process of rotating in a specific direction and I press the limit switch it changes direction but doesn't complete one full rotation in the opposite direction for some reason, it misses some steps, and ideas how can this be fixed?

Any help would be greatly appreciated.

Is this a school project? This is the third time this question is posted.
Please read and use the topic How to get the best out of this forum - Using Arduino / Project Guidance - Arduino Forum

and provide schematics for the build, links to datasheets, tell which of the 20 different Arduinos You use.

This delay makes your engine rotate n turns and stops for 3 seconds.
But this delay also impacts the button reading.
I suggest using millis() instead of delay().

The first mistake, as it looks like, is that You launch 800 steps, then looks for the limit switch. You need to check before each step taken.

HI man , no actually i am trying to make a string art machine , not a school project , I want to caliberate my machine and my idea is that I plan to use a limit switch at nail position 0 so that everytime that position is hit , I know that I am at nail 0 , this questions is a pretty common one , I totally agree , but all the solutions I could find online on ask how to change the direction , I was actually unable to solve the problem of steps being missed once the direction is changed , that's why I asked this question.

See if I understand your project correctly:
The engine rotates in cycles with 3-second stops.
When you feel the limit, it should rotate in the opposite direction for a few cycles and stop completely.
This is it?

yes kinda right, what i want to achieve is that , say the motor is completing a turn in a specific direction and in the middle of the turn say I hit the limit switch then it should complete one turn (360*) entirely in the opposite direction and then move out of the loop of the initial turn .

are u suggesting check for the limit switch before I send my stepPin high pulse ?

but dont you think that the limit switch is being hit in the for loop part and that has no impact what so ever on how whether the motor is completing one entire revolution in the opposite direction once the limit switch is hit since the delay of 3secs in induced only when I break out of the for loop.

The stepper seems of be missing some steps once I hit the limit switch to make it complete one entire revolution in the opposite direction.

Trying to find ready "solutions" often (always?) give You unknown code. Go a step lower, understanding what is done and why.
Often the name "Home switch" is used and it's a calibrating switch used a start up.

Correct. That's a mistake. See the reply #4

Yes.

1 Like

Hi man , thanks for replying first of all , coming to what I could make out from what u meant , if this is what u were suggesting , then even with the the stepper misses some steps in the opposite direction when the limit switch is hit.

digitalWrite(dirPin, LOW);  // Set direction to clockwise
  for (int i = 0; i < stepsToMove; i++) {

    if (digitalRead(LIMIT_SWITCH_PIN) == LOW) {
      Serial.println("Activated!");
      switchHit();
      break;
    }

    digitalWrite(stepPin, HIGH);
    delayMicroseconds(20);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelay - 20);
  }

could you plz elaborate on this? couldn't understand what u meant.

Let's go through the Jack process.

Part 1. You turn on your project and the step motor rotates 800 steps;
Part 2. Wait 3000 mS;
Part3. Tests whether the limit has been pressed;
Part4. If not, go to part 1;
Part5. If pressed, it rotates 800 steps in reverse;
Part6. Stop and stay still forever.

Is correct?

No , what i want to achieve is :

  1. Stepper starts to rotate 800 steps at a low rpm in a particular direaction
  2. If the limit switch is hit while the stepper is rotating and hasn't yet finished its turn completely (that's 360*) , it should start rotating in the opposite direction for one complete circle and break out of the earlier rotation loop.
  3. If the limit switch wasn't hit then it should complete its rotation in which ever direction it started rotating.
  4. Finally it should wait for 3 secs before the entire process starts again.

Does it make sense ?

Using break or return is like GoTo programming for me.

I would go by

  for (int i = 0; i < stepsToMove; i++) {

    if (digitalRead(LIMIT_SWITCH_PIN) =! LOW) {// No limit switch, make the step

      digitalWrite(stepPin, HIGH);
      delayMicroseconds(20);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepDelay - 20);
   }
 }

Try this code:

simulated in:

#include <Servo.h>  //Servo library
// Pin Definitions
#define LIMIT_SWITCH_PIN 7
#define dirPin 2   // Direction
#define stepPin 3  // Step Pulse
#define enaPin 4   // Enable Motor
// Variables
int stepDelay = 1250;  // Delay between steps in microseconds
int stepsToMove = 800;
bool run = true;
//-------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP);
  // // Set pin modes
  pinMode(enaPin, OUTPUT);
  digitalWrite(enaPin, LOW);  // Enable motor
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
}
//-------------------------------------------------------------
void switchHit() {
  digitalWrite(dirPin, HIGH);  // Set direction to clockwise
  for (int i = 0; i < stepsToMove; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(20);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepDelay - 20);
  }
  run = false;
}
//-------------------------------------------------------------
void loop() {
  if ( run == true) {
    digitalWrite(dirPin, LOW);  // Set direction to clockwise
    for (int i = 0; i < stepsToMove; i++) {
      if (digitalRead(LIMIT_SWITCH_PIN) == LOW) {
        Serial.println("Activated!");
        switchHit();
        break;
      }
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(20);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepDelay - 20);
    }
    delay(3000);  // Delay for 1 second
  }
}