Should I use an interrupt to stop stepper?

I have a stepper motor that will drive a belt to control the position of a platform, which will ride on a set of rails. I want to “deploy” the platform by moving it to the front of the rail, and later “stow” the platform by moving it back to the back of the rail. I could easily set this up on my desk and use trial and error to count the steps needed to move it to either location. My concern is that if the platform somehow gets moved by being bumped or if the power goes out and the system loses track of the location, I could end up ramming the platform at the front or back of the rail. Hence, I will add limit switches at both ends of the rail that will be activated by the platform if it tries to travel too far. I plan to eventually use an app with the cloud to control deploying/stowing the platform. For now I’m using pushbuttons in place of the app controls.
Here is my thought process: Determine the number of steps to deploy when starting from the stow position, which should equal the number of steps to stow when starting from the deploy position. Easy, peezy. To move the platform I will call a function to either deploy or stow the system. My real question is around the limit switches. Suppose the system got bumped and the platform is only 100 steps away from the deploy position, but the function would normally use 120 steps to deploy when starting from the stow position. This situation would activate the limit switch. Now, how do I use the limit switch activation to prevent the platform from trying to go the full 120 steps, when I need it to stop after 100? I’m thinking using an interrupt is the way to go. Would this work, or would the program resume inside the function call and run the final 20 steps anyway? Any ideas for a different approach are welcome.

For safety you should never rely on software (and especially not on interrupts).

Limit switches are often used to directly shut down motor power in order to prevent catastrophic collisions or equipment damage. There can be two levels of limit switches: one that works at the software level, and a backup level that works when the software fails.

Please post the code, in code tags and let us see what can be done.

Respect the reply #2 from @anon94801460!

Separate from limit switches used for safety purposes, there should be a home switch to tell you when you are at the starting position.

But you also need to position the platform to specific positions between the two limits, with millimeter precision, yes?

If the answer is no, then a stepper motor was not the appropriate choice of motor in this situation.

A DC motor, with a gearbox, would have been a more appropriate choice. Cheaper, stronger and simpler to use than steppers in this situation, which have no advantage.

Choosing a DC motor would have an additional benefit: easy to wire limit switches to cut the power without any need for code additions.

But even with your stepper motor, interrupts are not required.

@cattledog suggested another switch, we will call home. When coming out of reset I would assume that is the time to re-calibrate or if an error is detected. At that point step away from that switch until it is open, then step back until tripped, that is your home position. You could use a linear sensor that will always give you the exact position of the platform, probably the most accurate.

Good points, but if I kill power to the motor how would I restore the system without manually moving the platform? I want to be able to restore the system without having to manually intervene.

#include <Stepper.h>

const int stepsPerRevolution = 200;
int deployLimitPin = 5;
int stowLimitPin = 6;
int runForwardPin = 3;
int runReversePin = 4;

// initialize the stepper library on pins 8 through 11
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

// function to step one full revolution in forward direction.  Determine the actual number of
// steps needed later and use that number in place of stepsPerRevolution.
void forward() {
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(500);
}

// function to step one full revolution in reverse direction
void reverse() {
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(500);
}
// need to add code to respond to the pressing of the limit switches
void setup() {
  // set the speed at 60 rpm:
  myStepper.setSpeed(60);
  // initialize the serial port:
  Serial.begin(9600);
  // set pinmodes for limit switches
  pinMode(deployLimitPin, INPUT_PULLUP);  //simulating limit switch with pushbutton for now
  pinMode(stowLimitPin, INPUT_PULLUP);    //simulating limit switch with pushbutton for now
  pinMode(runForwardPin, INPUT_PULLUP);   //pushbutton to deploy platform
  pinMode(runReversePin, INPUT_PULLUP);   //pushbutton to stow platform
}

void loop() {
  // step one revolution  in one direction:
  //Serial.println("clockwise");
  //myStepper.step(stepsPerRevolution);
  //myStepper.step(1);
  //delay(500);

  // call reverse function if reverse pin = 0
  if (digitalRead(runForwardPin) == 0) {
    forward();
  }
  // call reverse function if reverse pin = 0
  if (digitalRead(runReversePin) == 0) {
    reverse();
  }


  Serial.print("status of deploy limit switch = ");
  Serial.println(digitalRead(deployLimitPin));
  Serial.print("status of stow limit switch = ");
  Serial.println(digitalRead(stowLimitPin));
  Serial.print("status of Forward switch = ");
  Serial.println(digitalRead(runForwardPin));
  Serial.print("status of Reverse switch = ");
  Serial.println(digitalRead(runReversePin));
}

#include <Stepper.h>

const int stepsPerRevolution = 200;
int deployLimitPin = 5;
int stowLimitPin = 6;
int runForwardPin = 3;
int runReversePin = 4;

// initialize the stepper library on pins 8 through 11
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

// function to step one full revolution in forward direction.  Determine the actual number of
// steps needed later and use that number in place of stepsPerRevolution.
void forward() {
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(500);
}

// function to step one full revolution in reverse direction
void reverse() {
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(500);
}
// need to add code to respond to the pressing of the limit switches
void setup() {
  // set the speed at 60 rpm:
  myStepper.setSpeed(60);
  // initialize the serial port:
  Serial.begin(9600);
  // set pinmodes for limit switches
  pinMode(deployLimitPin, INPUT_PULLUP);  //simulating limit switch with pushbutton for now
  pinMode(stowLimitPin, INPUT_PULLUP);    //simulating limit switch with pushbutton for now
  pinMode(runForwardPin, INPUT_PULLUP);   //pushbutton to deploy platform
  pinMode(runReversePin, INPUT_PULLUP);   //pushbutton to stow platform
}

void loop() {
  // step one revolution  in one direction:
  //Serial.println("clockwise");
  //myStepper.step(stepsPerRevolution);
  //myStepper.step(1);
  //delay(500);

  // call reverse function if reverse pin = 0
  if (digitalRead(runForwardPin) == 0) {
    forward();
  }
  // call reverse function if reverse pin = 0
  if (digitalRead(runReversePin) == 0) {
    reverse();
  }


  Serial.print("status of deploy limit switch = ");
  Serial.println(digitalRead(deployLimitPin));
  Serial.print("status of stow limit switch = ");
  Serial.println(digitalRead(stowLimitPin));
  Serial.print("status of Forward switch = ");
  Serial.println(digitalRead(runForwardPin));
  Serial.print("status of Reverse switch = ");
  Serial.println(digitalRead(runReversePin));
}

Thanks for the insight. I do not need to hit other points in between the deploy and stow positions.

Here is some more background. The platform has a camera mount to hold a security camera in our kitchen which will sit on top of the upper cabinets. My wife doesn’t like seeing the camera, and it is not really needed when we are home and in the kitchen. I plan to deploy it whenever I put the alarm system in an armed state, and stow it whenever I disarm the alarm system. (I haven’t gotten to this part of the design yet, but I have an idea that I believe will work.)

The reason I chose a stepper motor was because of the precise control. I do not plan to stop the motor with the limit switches unless something goes wrong. And in those cases I obviously want to stop the motor, but I don’t want to do that by killing the power because then I would have no way to restore to system to it’s normal state without physically moving the platform manually. I’m trying to avoid that, especially if it hit with stow limit switch and I wasn’t aware of it left on vacation. I wouldn’t be able to deploy the camera.

I like your thoughts, but I’m thinking it might be simpler that if it ever did run into a limit switch, I would know how many steps away I was from the home position and could simply step back without needing a sensor (although I do like the idea of feedback.) I need to give this more thought.

No, you will always have the possibility of being off by one step, either 1 to many or one less, or right on! All depends on when the movement hits the switch and when it is discovered by your code.

Okay, in my case where I’m positioning a camera if I’m off a few steps it shouldn’t be an issue. Basically, when deploying the camera I need it close enough to the front of the cabinet so that I have a good view of the kitchen. When stowing it, I just need to move it back far enough to be out of sight from floor level.

At this point I need to experiment to determine how to “kill” the function that is either deploying or stowing the unit if I run into a limit switch, something that under normal circumstances should never happen. I just want a safety factor in place. I’m quite sure I can detect the limit switch from the interrupt, but then what do I have the interrupt routine do? I don’t want the program pick up in the original function (deploy or stow) and continue until it makes all of the originally intended steps. If I can’t do that with an interrupt, then I need to rethink the whole process.

Wait, I have another idea. If I can use the interrupt to have the platform take five or more steps back to get away from the limit switch, then upon returning to the function (deploy or stow) even if it tried to complete the original number of steps sooner or later it should stop before hitting the limit switch! Sort of a two steps back, one step forward scenario. Hmm, this just might work. Time to start tinkering some more. I’ve never used an interrupt before, so I’ll need to work through that learning curve.

You are creating a monster to solve an non-existant problem!

No, you don't need to. Often interrupts create more problems than they solve. There are only few situations where they are really needed, and then you should really know what you are doing.

Learn how to write non blocking programs and read the limit switch in loop(). First of all you should get rid of that stepper.h library and use a better one, because all steppermoves with this library are blocking.

Use a linear sensor such as a pot, you will always know where you are. We did that many years ago with molding machines, worked great for many years. The hard with the pot is connecting it but maybe a slide pot with a pivot connecting to the moving slide.

Yes there is a way. The limit switches would not directly cut the power to the motor, they could do it by controlling the motor driver (an H-bridge).

The right choice of H-bridge driver model is important for this to be possible. You would need to use a model with separate "forward" and "reverse" inputs. Not one with a "direction" and "speed/enable" pins.

One example of an H-bridge driver with such inputs is the classic L298, but I would not recommend that model because it's old and inefficient. But there are more modern and efficient drivers that have similar inputs, such as TB6612FNG.

The way you would wire the driver would be to connect the inputs to 2 Arduino pins via the normally-closed terminals of the limit switches. The normally open terminals would be connected to ground. That way, the motor will begin to move forward when the Arduino pin connected to the forward control input goes high. But when the forward limit switch is activated, this will cut the signal and the motor will stop. No code, no interrupts required.

When the Arduino wants to put the motor in reverse, the fact that the forward limit switch is activated doesn't matter. This method works in both directions.

Maybe

I know it's where I'll start if I ever get serious about stepping.

a7

Which stepper library would you suggest?

Great advice, thanks! I was actually using the L298, but will take a look at the TB6612FNG. I’m not in any big hurry here. Just want to learn what I can and come up with a good design that works.

Thanks for the tip. I’ll have a look at this.