Stop stepper motor with endstop

I have a Stepper motor connected to a L298N (It works perfectly).

I also have 2 endstop (they work perfectly as well). My problem is when I join both codes. What I want to do is make the stepper motor stop when it reaches the end (linear movement), but I have not been able to do it, can you help me?

#include <Stepper.h>

const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

// Endstop
int endstop_1 = 3;
int endstop_2 = 2;

const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

void setup() {

  // set the speed at 60 rpm:
  myStepper.setSpeed(60);

  pinMode(endstop_1, INPUT);
  pinMode(endstop_2, INPUT);

  // initialize the serial port:
  Serial.begin(115200);
  Serial.setTimeout(0);

  // Indicaciones para el control
  Serial.println("Derecha - 1");
  Serial.println("Izquierda - 2");
}
  
void loop() {
  recvWithEndMarker();
  microControl();
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0';
      ndx = 0;
      newData = true;
    }
  }
}

void microControl() {
  if (newData == true) {

    // Derecha 
    if (receivedChars[0] == '1') {
      Serial.println("Derecha adelante");
      Serial.println(atoi(&receivedChars[2]));
      Serial.println("clockwise");
      myStepper.step(stepsPerRevolution);
      if (digitalRead(endstop_1) == HIGH) { // assumes LOW = pressed, HIGH = not pressed
        Serial.println("endstop_1 pressed");
        myStepper.setSpeed(0);
      }
      else if (digitalRead(endstop_2) == HIGH) { // assumes LOW = pressed, HIGH = not pressed
        Serial.println("endstop_2 pressed");
        myStepper.setSpeed(0);
      }
    }

    // Izquierda
    else if (receivedChars[0] == '2') {
      Serial.println("Izquierda adelante");
      Serial.println(atoi(&receivedChars[2]));
      Serial.println("counterclockwise");
      myStepper.step(-stepsPerRevolution);
      
      if (digitalRead(endstop_1) == HIGH) { // assumes LOW = pressed, HIGH = not pressed
        Serial.println("endstop_1 pressed");
        myStepper.setSpeed(0);
      }
      else if (digitalRead(endstop_2) == HIGH) { // assumes LOW = pressed, HIGH = not pressed
        Serial.println("endstop_2 pressed");
        myStepper.setSpeed(0);
      }
    }

    newData = false;
  }
}

The motor starts when I press 1 or 2, but when it reaches the limit and is activated the endstop does not recognize it. It seems that it does not enter the conditional:
if (digitalRead(endstop_1) == HIGH) {

You're telling the stepper to do 200 steps and then check the end stop. Usually, people do one at a time, checking after every step.

in most cases steppermotors are used in a way that they don't loose steps.
This means that your code can know at which position your system is and how much steps are possible to drive without hitting mechanical limits.
Your code then can calculate if a new command
"drive to position "x" " is within the limits or not
and if it is outside creating an error or just limiting the new position to what is mechanically possible.

Anyway endswitches are used to "reference" the position. But this is a special case called reference-drive. And indeed in the refrence drive you do one step and immidiately check if limit-switch is "on" if not do the next single step.

If you give an overview about what you want to do in the end much better suggestions can be made how to realise such a functionality.

best regards Stefan

Check the endstop before each step:

#include <Stepper.h>

const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

// Endstop
int DerechaEndstopPin = 3;
int IzquierdaEndstopPin = 2;

const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

void setup()
{

  // set the speed at 60 rpm:
  myStepper.setSpeed(60);

  pinMode(DerechaEndstopPin, INPUT);
  pinMode(IzquierdaEndstopPin, INPUT);

  // initialize the serial port:
  Serial.begin(115200);
  Serial.setTimeout(0);

  // Indicaciones para el control
  Serial.println("Derecha - 1");
  Serial.println("Izquierda - 2");
}

void loop()
{
  recvWithEndMarker();
  microControl();
}

void recvWithEndMarker()
{
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  while (Serial.available() > 0 && newData == false)
  {
    rc = Serial.read();
    if (rc != endMarker)
    {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars)
      {
        ndx = numChars - 1;
      }
    }
    else
    {
      receivedChars[ndx] = '\0';
      ndx = 0;
      newData = true;
    }
  }
}

void microControl()
{
  if (newData == true)
  {
    // Derecha
    if (receivedChars[0] == '1')
    {
      int stepsRemaining = atoi(&receivedChars[2]);
      Serial.println("Derecha adelante");
      Serial.println(stepsRemaining);
      Serial.println("clockwise");

      for (int step = 0; step < stepsRemaining; step++)
      {
        if (digitalRead(DerechaEndstopPin) == HIGH)
        {
          Serial.println("DerechaEndstopPin pressed");
          return;
        }
        myStepper.step(1);
      }
    }
    // Izquierda
    else if (receivedChars[0] == '2')
    {
      int stepsRemaining = atoi(&receivedChars[2]);
      Serial.println("Izquierda adelante");
      Serial.println(stepsRemaining);
      Serial.println("counterclockwise");

      for (int step = 0; step < stepsRemaining; step++)
      {
        if (digitalRead(IzquierdaEndstopPin) == HIGH)
        {
          Serial.println("IzquierdaEndstopPin pressed");
          return;
        }
        myStepper.step(-1);
      }
    }
    else
      Serial.println("????");
  }
  newData = false;
}

The MoBaTools have a demo-code that show how to do a reference-drive with the MoBaTools-library

best regards Stefan

P.S: Your Fritzing-picture is one if the very rare exceptions where a fritzing-picture comes close to a schematic. Could have been even more easy to read by recersing the sequence of the IO-pins connected to the driver-board-inputs. Just change the sequence of the numbers inside the code and everyrhing runs the same way and the wire-crossings would not b there

Thanks for your opinion. You're absolutely right, I was a bit lost. Actually it is not necessary because each step is known exactly, it is not a normal motor.

I have an other question. I want to turn off the engine. Should I use the ENA ENB pins for that?

Does the stepper motor shut down or does it just slow down while it stays running?
Because if it stays on, I better put a relay on it.

I do the following (it works, but I don't know if the stepper motor is off by default):

#include <Stepper.h>

const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);
int EN1 = 3;
int EN2 = 2;

const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

void setup() {

  // set the speed at 150 rpm:
  myStepper.setSpeed(150);

  // initialize the serial port:
  Serial.begin(115200);
  Serial.setTimeout(0);

  // Indicaciones para el control
  Serial.println("Delante del stepper - 3");
  Serial.println("Atrás del stepper - 4");

  // Pines EN stepper motors
  pinMode (EN1, OUTPUT);
  pinMode (EN2, OUTPUT);
}
  
void loop() {
  recvWithEndMarker();
  microControl();
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (rc != endMarker) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0';
      ndx = 0;
      newData = true;
    }
  }
}

void microControl() {
  if (newData == true) {
  
    // Hacia afuera del stepper
    else if (receivedChars[0] == '3') {
      analogWrite (EN1, HIGH);
      analogWrite (EN2, HIGH);
      Serial.println("Afuera");
      Serial.println(atoi(&receivedChars[2]));
      Serial.println("Counterclockwise");
      myStepper.step(atoi(&receivedChars[2]));
     analogWrite (EN1, LOW);
     analogWrite (EN2, LOW);
    }

    // Hacia adentro del stepper
    else if (receivedChars[0] == '4') {
      analogWrite (EN1, HIGH);
      analogWrite (EN2, HIGH);
      Serial.println("Adentro");
      Serial.println(atoi(&receivedChars[2]));
      Serial.println("Counterclockwise");
      myStepper.step(-atoi(&receivedChars[2]));
      analogWrite (EN1, LOW);
      analogWrite (EN2, LOW);
    }
    newData = false;
  }
}

Like I said, it works perfectly. My problem is that I don't know if the engine is actually off. My motor is low consumption (350 mA), but I don't want it to always keep consuming that, I want to turn it off or when I'm not using it.

Do I have a mistake?

You can test it very easy: pull off the jumpers and test if you can turn the motor.
If yes the motor is shut off.
and then you can use two additional pins to switch on/off
best regards Stefan

1 Like

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