Counting Stepper steps between Limit switches

Hello,

I would like some assistant on how I could code my program to be able to count the number of steps the motor takes between two limit switches. Any help or advice would be appreciated.

Below is what I have coded so far (from various examples online). I have managed to rotate the stepper clockwise and counter clockwise when a limit switch is triggered. How do I add a function that counts the number of steps the motor takes.

#include <AccelStepper.h>
const int dirPin = 8;
const int stepPin = 9;
const int enPin = 20;
const int limit1 = A11;// left limit
const int limit2 = A12;// right limit

void setup() {
  // Set up stepper motor
  Serial.begin(9600);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, LOW);

  //Set up 2 limit switch
  pinMode(limit1 , INPUT_PULLUP);
  pinMode(limit2 , INPUT_PULLUP);


}
void loop() {
  digitalWrite(dirPin, LOW); // setup motor turn left first
  do {
    digitalWrite(stepPin , HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin , LOW);
    delayMicroseconds(500);
  } while (digitalRead(limit1) == HIGH);  // motor turn left until touch limit 1 handle
  delay(500);
  digitalWrite(dirPin, HIGH);// motor turn right after limit1 powered ( touch limit1 handle).
  do {
    digitalWrite(stepPin , HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin , LOW);
    delayMicroseconds(500);
  } while (digitalRead(limit2) == HIGH);// motor turn right until touch limit 2 handle
  delay(500);
  digitalWrite(dirPin, LOW);// motor turn left after touch limit 2 handle
}


Well, since your code is stepping each step, why not add a counter in the while...do loops?
Be aware, the first direction of movement is probably starting mid-range, so you really just want to count the steps in the second direction, where it's going from limit to limit.
C

Would I use count++? I would want it to only count from limit switch 1 to limit switch 2.

Yes. Declare a long int above your setup code, initialize it to 0.
In your second loop, just count++.
C

If your limits are mechanical limit switches, you'll find that the count varies a bit from run to run.

Your do .. while loops should be while loops instead. As is, there will be one iteration of each loop even if the condition is not met.

EDIT: And the final digitalWrite(dirPin, LOW) has no effect so it may be removed.

1 Like

I've got it working now thank you. But my motor spins very slowly while it is counting the steps. Is this normal? i.e. going from limit switch 1 to 2 is very slow but from 2 to 1 it spins fast.

#include <AccelStepper.h>

const int dirPin = 9;
const int stepPin = 8;
const int enPin = 10;
const int motorInterfaceType = 1;

const int limit1 = A14;// left limit
const int limit2 = A15;// right limit

long int counter = 0;

AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  Serial.begin(9600);

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, LOW);

  pinMode(limit1 , INPUT_PULLUP);
  pinMode(limit2 , INPUT_PULLUP);

  stepper.setMaxSpeed(1000);   // set the maximum speed
  stepper.setAcceleration(100000); // set acceleration
}

void loop() {
  do {
   stepper.moveTo(8000);
   stepper.run();
  }   
  while (digitalRead(limit1) == HIGH);  // motor turn left until touch limit 1 handle
  delay(500);  
  do {
   Serial.println(counter);
   counter++;
   stepper.moveTo(-8000);
   stepper.run();
  }  

Serialprint is slow.

especially if you use a low baudrate like 9600 sending data to the serial interface is slow.

steppermotors need a very tight timimg.
accelstepper needs to call stepper.run() at a higher frequency than each single step occurs.

If it is really important that you print the number of steps for each and every iteration of your while-loop you must increase the baudrate.

If it is sufficient to know the number of steps between the limitswitches move the serial.print behind the while-loop.

If you want to do things in parallel to the step-pulse-creation you could use the MObaTools-library which does the step-pulse-creation in the backround

best regards Stefan

Hi, I tried doing this but I get an error of: expected '(' before '{' token

Thank you for the information.

You could print the counter less often. I'm unfamiliar with the AccelStepper, but you could try this:

 stepper.moveTo(8000);
 while (digitalRead(limit1) == HIGH) stepper.run();
 delay(500);  
 stepper.moveTo(-8000);
 while (digitalRead(limit1) == LOW)
 {
    stepper.run();
    if (++counter % 10 == 0) Serial.println(counter);
  }

without any context this posting is useless.
You can mark text in postings and then simply click on the quote-button that appears to have the context putted in quickly

Hi I tried to implement your code to my sketch but to rotate the direction of the motor I need to manually hold the limit switch closed. I am not sure why this is the case. I want it to be done automatically as soon as there is a contact on the limit switch.

#include <AccelStepper.h>

const int dirPin = 9;
const int stepPin = 8;
const int enPin = 10;
const int motorInterfaceType = 1;

const int limit1 = A1;// left limit
const int limit2 = A2;// right limit

long int counter = 0;

AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  Serial.begin(74880);

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, LOW);

  pinMode(limit1 , INPUT_PULLUP);
  pinMode(limit2 , INPUT_PULLUP);

  stepper.setMaxSpeed(1000);   // set the maximum speed
  stepper.setAcceleration(100000); // set acceleration
}

void loop() {
   stepper.moveTo(8000); // motor turn left until touch limit 1 handle
while (digitalRead(limit1) == HIGH) stepper.run();
delay(500);  
 stepper.moveTo(-8000); // motor turn right after limit1 powered ( touch limit1 handle).
while (digitalRead(limit1) == LOW)
{
    stepper.run();
    if (counter++ % 10 == 0) Serial.println(counter); // starts counting steps from limit switch 1 to 2 
  }  
  while (digitalRead(limit2) == HIGH);// motor turn right until touch limit 2 handle
    delay(500); 
    stepper.moveTo(counter/2); // move motor to half the number of steps it calculated
} 


Hi I am sorry I should have made myself clear. I have sorted out this issue now.

I tired increasing the baudrate and it does help the motor rotate faster. Thank you for the tip. I implemented a new code as shown above but now the motor will only move if limit switch 1 is held closed.

I'm pretty sure that is how the code you posted prior to my example would also work. You should try to make a state machine where the switches changes the state.

while (digitalRead(limit2) == HIGH);// motor turn right until touch limit 2 handle
delay(500); 
stepper.moveTo(counter/2); // move motor to half the number of steps it calculated

This will not do what you expect, it will lock until "limit2" goes LOW, wait ½ second and start a "moveTo" which is not performed due to the lack of "run()" statements..

int target = 8000, last_target = 0;
unsigned int counter = 0;

void loop()
{
  if (digitalRead(limit1) == LOW)
  {
    delay(50); //Debounce
    target = (target == 8000) ? -8000 : 8000;
  }
  if (digitalRead(limit2) == LOW)
  {
    delay(50); //Debounce
    target = counter / 2;
  }
  if (target != last_target)
  {
    last_target = target;
    counter = 0;
    stepper.moveTo(target);
  }
  if (stepper.run())
  {
    if (++counter % 10 == 0) Serial.println(counter);
  }
}

Hello. Thank you very much for your example. I have got the limit switches and motor working as intended. Sorry I am quiet new to coding so I am unsure on the code what this part does (see below). Say I want the motor to stop at the centre of the number of steps it calculated between limit switches 1 and 2 (like a homing position). I tried to do stepper.moveTo(counter/2); but it continues beyond the half way point.

    target = counter / 2;
  }
  if (target != last_target)
  {
    last_target = target;
    counter = 0;
    stepper.moveTo(target);

From this small code-snippet it is impossible to say why it might not work
always post your complete sketch
You can post code by using this method that adds the code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

Hi,

Here is the full sketch:

#include <AccelStepper.h>

const int dirPin = 9;
const int stepPin = 8;
const int enPin = 10;
const int motorInterfaceType = 1;

const int limit1 = A1;// left limit
const int limit2 = A2;// right limit

int target = 8000, last_target = 0;
unsigned int counter = 0;
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  Serial.begin(9600);

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enPin, OUTPUT);
  digitalWrite(enPin, LOW);

  pinMode(limit1 , INPUT_PULLUP);
  pinMode(limit2 , INPUT_PULLUP);

  stepper.setMaxSpeed(1000);   // set the maximum speed
  stepper.setAcceleration(100000); // set acceleration
}

void loop() {
  do {
    stepper.moveTo(8000);// motor turn left until it touches limit 1 handle
    stepper.run();
  }  while (digitalRead(limit1) == HIGH);  //  limit 1 is activated
  delay(500);                             //delay
  do {
    stepper.moveTo(-8000);// motor turn right
    stepper.run(); // motor moves right
    counter++; // starts counting number of steps from limit 1 to limit 2
  } while (digitalRead(limit2) == HIGH);// touches limit 2
  delay(500);
  do {
    target = counter;   // finds value of half total count recorded
    stepper.moveTo(target);// motor turn left and moves to target count
    stepper.run();
  } while (digitalRead(limit2) == HIGH);
}

What I mainly want to do is get a 0 position for my motor between the two limit switches.