Emergengy Stop Help

#include <Servo.h>

Servo myservo;  //defines servo

void setup()
{
  myservo.attach(9); //set up the servo as usual
 attachInterrupt(0, estop, LOW);  //attaches interrupt to pin 2 and starts estop code when pin2 goes LOW
}

void loop() {

// on this servo 1500 is stopped, above 1500 is clockwise, below is counter clockwise 800-2100

     {
      myservo.writeMicroseconds(800); // forward full speed for 5 seconds
      delay(5000);
     
     }
     myservo.writeMicroseconds(1150); // forward half speed for 5 seconds
      delay(5000);
      
     myservo.writeMicroseconds(1500); // stop for 1 seconds
      delay(1000);
     
     
      myservo.writeMicroseconds(2100); // reverse full speed for 5 seconds
      delay(5000);
      
      myservo.writeMicroseconds(1850); // reverse half speed for 5 seconds
      delay(5000);
      
      myservo.writeMicroseconds(1500); // stop for 1 seconds
      delay(1000);
     
   }
void estop()
{
while(digitalRead(2) == LOW){     //loops the stop command while pin 2 is LOW
myservo.writeMicroseconds(1500);   
delay(5000);                      //once pin 2 goes high waits 5 seconds to resume program
}
}

I am having issues with my setup here.. I am brand new to arduino so please go easy. Currently I have a sabertooth 2x25 motor controller connected to the arduino and an e-stop button. The e-stop button is normally closed and is in the open position when pressed. This is a twist to release style switch.
My problem is that when the e-stop is pressed the motor does not stop. when it is released it stops, waits 5 seconds then resumes. When the button is pressed, released, then pressed again the motor stops and does not resume turning until after the button is released a final time. I have been trying to figure this out for a while now and think that I just need some fresh eyes. Any input as welcome and appreciated! If there are any questions or something that I am leaving out please let me know. Also the button is connected per the schematic under arduino reference. Thanks.

You interruptroutine is not correct an IRQ should be short as possible., try code below

(code not tested or compiled)

#include <Servo.h>

Servo myservo;  

volatile boolean estopFlag = false;
#define RESETPIN 3

void setup()
{
  pinMode(RESETPIN, INPUT);
  pinMode(13, OUTPUT);
  myservo.attach(9); 
  attachInterrupt(0, estop, LOW);  
}

void loop()
{
  MyMove(800, 5000);
  MyMove(1150, 5000);
  MyMove(1150, 5000);
  MyMove(1500, 5000);
  MyMove(1500, 1000);
  MyMove(2100, 5000);
  MyMove(1850, 5000);
  MyMove(1500, 1000);

  if (digitalRead(RESETPIN) == LOW) estopFlag = false;  // reset the estop flag

}


void MyMove(int time, int del)
{
  digitalWrite(13, !digitalRead(13));  // do some led blinking to check activity

  if (estopFlag) return;  // if emergency no more servo 
  myservo.writeMicroseconds(time);
  delay(del);
}


void estop()
{
  myservo.writeMicroseconds(0);
  estopFlag = true;
}

Not much of an emergency if you can afford to wait up to five seconds for the stop.
Either look at the blink without delay example, or break your delays into smaller chunks, say ten milliseconds, and check for the stop flag each time through the delay loop.

The documentation claims that delay() generally does not work inside an ISR.
Also, the writeMicroseconds() function is probably not re-entrant, so if the interrupt comes in while you're in the middle of that function, you're unlikely to get the result you want.

If all you want to do is run this control loop, then you don't actually need interrupts at all. Replace your call to delay() with a function that polls the estop button once a millisecond until the designated time has elapsed, and do a stop/early exit if pressed.
I also imagine that your servo controller needs the signal to not be written for a short while to reset for the next command, hence making sure that there's always a short delay before/after the estop loop.

bool myDelay(unsigned long amt)
{
  unsigned long stop = millis() + amt;
  delay(1);
  while (millis() < stop) {
    if (digitalRead(STOP) == STOP_ACTIVATED) {
      do_estop();
      return false;
    }
    delay(1);
  }
  return true;
}

void loop()
{
  servo.writeMicroseconds(whatever);
  if (!myDelay(1000)) { /* estop interrupted this action */ }
   ...
}

robtillaart:
You interruptroutine is not correct an IRQ should be short as possible., try code below

(code not tested or compiled)

Thank you so much Rob, this worked wonderfully! I hade to change a few values from LOW to HIGH, but it works like a charm. For the estop sub routine I had to change the value to 1500 (which is full stop for my motor controller). I also like how you created MyMove and simplified the code tremendously. Now I can add in moves very easily. Thank you so much for your input. :grin:

If you wanted to be able to recover from the estop, you could have the estop function detach it's own interrupt and attach another interrupt (on a LOW to HIGH) that would set the flag to false (plus detach itself and attach the estop function).

something like this:

void estop() {
    estopFlag = true;
    detachInterrupt(2);
    attachInterrupt(2, unstop, RISING);
}

void unstop() {
    estopFlag = false;
    detachInterrupt(2);
    attachInterrupt(2, estop, FALLLING);
}

If in industrial use, if a switch is really defined as a safety emergency stop switch then it should have a set of contacts that directly removes power from the device it's protecting. Often one uses a switch with two sets of contacts (DPST) so one contact set removes power from the device and the other contact set wires to the control board so that it will know that it has been activated manually.

So take that as an example of how safety critical controls should be designed, if prevention of personnel injury is indeed the purpose of the switch.

Lefty

And be sure to wire the emergency stop button so it is PUSHED to shutdown the equipment. I had the misfortune to watch an operator try, first in vain then in panic, to shut down an assembly line only to realize on the fourth attempt that the button had to be pulled. Fortunately, the only loss was the integrator's integrity and any chance at future work.

This will eventually be used for theatrical purposes. There will be a hardwired estop on board the robot and two wireless estops on either side of the stage. Since it is battery powered there is no way to hardwire the estops offstage to the mobile platform. Even though the wireless ones will not be as fail safe as the one onboard the robot they will be there just in case.