Interrupt as emergencystop

Hi.
I have a robot arm, which i have programmed using delays all over the place! I have to program it fast for a school project, and i am a newbee. Kinematics doesn't matter right now.

So okay, i have a sequence in which the arm is making some movement, but i need a emergencystop.
Then i thought aha! I'll just use the interrupt LOW to stop the arm. It works just fine. the arm stops... BUT it detaches all servos and the arm falls down with a slam!

So i was thinking if it was possible to use a interrupt to call a "subroutine" where it does nothing, and when i get the interrupt HIGH again (reset emergency stop) it stays there until i press start again?

That means :

  if (start==HIGH){
        wait();
      }

Regards NIC

You don't really want to be doing nothing for a long time in an interrupt.

It works just fine. the arm stops... BUT it detaches all servos and the arm falls down with a slam!

That shouldn't happen. Can you post your code?

#include <VarSpeedServo.h>
VarSpeedServo BASSERVO;  // base servo dreje
VarSpeedServo SHLSERVO;  // skuldlerled med 2 servoer
VarSpeedServo ELBSERVO;  // albueled
VarSpeedServo WRISERVO;  // håndled op ned
VarSpeedServo WROSERVO;  // håndled roter
VarSpeedServo GRISERVO;  // griber
VarSpeedServo ELB2SERVO;  // albueled roter
const int startpin = 53;
int start=0;
const int stopknappin = 51;
int stopknap=0;
const int start2pin = 49;
int start2=0;

// ingen servoer bliver attached i setup, for ikke at skabe pludselige bevægelser. 
void setup()
{
  pinMode (startpin,INPUT);
  pinMode (start2pin,INPUT);
  pinMode (stopknappin,INPUT);
  attachInterrupt(2, jaja, LOW);
  //BASSERVO.attach(3, 0,180);
  //SHLSERVO.attach(4, 540,1440);// 1400 er midt og 650 er bunden
  //ELBSERVO.attach(5, 540,1440);//min 980  1600 er midt
  //WRISERVO.attach(6, 540,1440);//2000 - 1600 - 680
  //WROSERVO.attach(7, 540,1440);  // 1400 er midt
  //GRISERVO.attach(8, 0,180); 
  //ELB2SERVO.attach(10, 540,1440); // 1550 er midt
}

void jaja(){
  jaja();
}


// her ses på om nødstop er trukket. er det ikke trukket går programmet til et ventetrin.
void stoppet(){
  stopknap = digitalRead(stopknappin);
  if (stopknap==HIGH){
    inite();
  }
  else
    if (stopknap==LOW){
      stoppet();
    }

}
// Er begge startsignaler høje vil armen gå i venteposition.
void inite()
{
  start = digitalRead(startpin);
  start2 = digitalRead(start2pin);
  if (start==HIGH & start2==HIGH){
    reset();
  }
}

void reset()
{
  BASSERVO.write(140);  // de første linjer her skriver hvilken position servoerne skal starte i, så de ikke flyver ud og starter i midterpositionen. Heref
  er tildeles de en pin med et signal.
    SHLSERVO.write(650); 
  ELBSERVO.write(980);  
  WRISERVO.write(1600);   
  WROSERVO.write(1400);  
  GRISERVO.write(90);
  ELB2SERVO.write(1550);
  BASSERVO.attach(3, 0,180);
  SHLSERVO.attach(4, 540,1440);
  ELBSERVO.attach(5, 540,1440);
  WRISERVO.attach(6, 540,1440); 
  WROSERVO.attach(7, 540,1440);
  GRISERVO.attach(8, 0,180); 
  ELB2SERVO.attach(10, 540,1440); 
  delay(2000);
  vente(); 
}

//ventetrin
void vente(){
  BASSERVO.slowmove(140,40);  
  SHLSERVO.slowmove(650,40); 
  ELBSERVO.slowmove(980,40);  
  WRISERVO.slowmove(1600,40);   
  WROSERVO.slowmove(1400,40);  
  GRISERVO.slowmove(90,100);
  ELB2SERVO.slowmove(1550,40);
  delay(1500);
  BASSERVO.detach();
  SHLSERVO.detach();
  ELBSERVO.detach();
  WRISERVO.detach();
  WROSERVO.detach();
  GRISERVO.detach();
  ELB2SERVO.detach();
  delay(500);
  vente2();
}

void vente2(){ // her ses der på hvilket startsignal der kommer.
  start = digitalRead(startpin);
  start2 = digitalRead(start2pin);
  if (start==HIGH & start2==LOW){
    sekvens();
  }
  else
    if (start2==HIGH & start==LOW){
      sekvens2();
    }
    else
      if (start2==LOW & start==LOW){
        vente2();
      }
}  

// selve sekvensen hvor servoerne køres til de forskellige positioner i et givet tempo og med delay mellem hvert punkt armen rammer.
void sekvens()             // Sekvens 
{ 
  BASSERVO.attach(3, 0,180);
  SHLSERVO.attach(4, 540,1440);
  ELBSERVO.attach(5, 540,1440);
  WRISERVO.attach(6, 540,1440); 
  WROSERVO.attach(7, 540,1440);
  GRISERVO.attach(8, 0,180); 
  ELB2SERVO.attach(10, 540,1440);
  //  stopknap = digitalRead(stopknappin); 
  // if (stopknap==LOW){stoppet();}
  SHLSERVO.slowmove(1250,30);
  ELBSERVO.slowmove(1400,40);
  WRISERVO.slowmove(680,100);
  //stopknap = digitalRead(stopknappin); // hvis nødstop aktiveres går armen i venteposition og starter ikke før nødstop er resat og de
  får startsignal igen.
    //if (stopknap==LOW){stoppet();}
  delay(900);
  GRISERVO.slowmove(20,50);
  delay(1000);
  ELBSERVO.slowmove(1800,40);
  SHLSERVO.slowmove(1400,20);
  // stopknap = digitalRead(stopknappin); 
  //if (stopknap==LOW){stoppet();}
  delay(800);
  BASSERVO.slowmove(10,40);
  // stopknap = digitalRead(stopknappin); 
  //if (stopknap==LOW){stoppet();}
  delay(800);
  SHLSERVO.slowmove(1600,20);
  ELBSERVO.slowmove(1750,15);
  // stopknap = digitalRead(stopknappin); 
  //if (stopknap==LOW){stoppet();}
  delay(800);
  GRISERVO.slowmove(90,50);
  delay(600);
  SHLSERVO.slowmove(1400,35);
  ELBSERVO.slowmove(1950,35);
  // stopknap = digitalRead(stopknappin); 
  //if (stopknap==LOW){stoppet();}
  delay(600);
  vente();
} 

void sekvens2()             // Sekvens2 kasserede emner
{ 
  BASSERVO.attach(3, 0,180);
  SHLSERVO.attach(4, 540,1440);
  ELBSERVO.attach(5, 540,1440);
  WRISERVO.attach(6, 540,1440); 
  WROSERVO.attach(7, 540,1440);
  GRISERVO.attach(8, 0,180); 
  ELB2SERVO.attach(10, 540,1440);
  stopknap = digitalRead(stopknappin); 
  if (stopknap==LOW){
    stoppet();
  }
  SHLSERVO.slowmove(1250,30);
  ELBSERVO.slowmove(1400,40);
  WRISERVO.slowmove(680,100);
  stopknap = digitalRead(stopknappin); // hvis nødstop aktiveres går armen i venteposition og starter ikke før nødstop er resat og den får startsignal igen.
  if (stopknap==LOW){
    stoppet();
  }
  delay(900);
  GRISERVO.slowmove(20,50);
  delay(1000);
  ELBSERVO.slowmove(1800,40);
  SHLSERVO.slowmove(1400,20);
  stopknap = digitalRead(stopknappin); 
  if (stopknap==LOW){
    stoppet();
  }
  delay(800);
  BASSERVO.slowmove(180,40);
  stopknap = digitalRead(stopknappin); 
  if (stopknap==LOW){
    stoppet();
  }
  delay(800);
  GRISERVO.slowmove(90,50);
  delay(600);
  vente();
}

//
void loop(){
  inite();
}

The thing that i call "stoppet" was my first attempt to do emergency stop with a normal input... in sekvens2 i have not disabled this, but i am only testing in sekvens.

Regards NIC

void jaja(){
  jaja();
}

Recursive ISR - I suppose there's a first time for everything.

The key to having an emergency stop seems to me, from a very quick scan, to get rid of all the calls to "delay", then you could easily poll a switch.

void stoppet(){
  stopknap = digitalRead(stopknappin);
  if (stopknap==HIGH){
    inite();
  }
  else
    if (stopknap==LOW){
      stoppet();
    }
}

More recursion?
Not really recommended, particularly in a safety situation.

  if (start==HIGH & start2==LOW){

Not what you want, I think

Yes i know.. I am a newbee...

I know that without delays everything should be easy. I just don't have the time to learn programming the arduino in the best way for this project... The easiest to understand is with delay.
And as interrupt also works when i use delay i thought this would do the trick...

i guess im stuck here for now...

The reason your servos detached when you used the interrupt is because the routine "jaja" calls itself.
Every time it does this, it uses some more stack.
There isn't very much stack.
Eventually (very quickly, in reality), the stack will start overwriting variables, like your servo objects.
I don't know why your routine "stoppet" calls itself either - you'd be better off just looping.

One very simple way of doing what you want is to write your own version of "delay", that breaks down the delay into, say 10mS slices.
Replace all calls to "delay" with calls to "myDelay".
Every "slice", you check the emergency stop switch, and if it set, you enter a loop.

This isn't ideal, but may get you out of your difficulties.

Thank you for the suggestion about the delay. I am totally new to programming. My only experience is PLC ladder programming... You write that i could make my own delay? so i make a myDelay with a delay inside of 10ms and then check emergency stop? How do i then get it to do that lets say 150times in a row before moving to the next step in the sequence?

The thing about the stoppet and it calling itself all the time. I do this to make a loop in stoppet so that it checks itself over and over again...

And you say that i will have to do is get rid of the line that calls stoppet again and then do the digital read in void loop? or make a loop inside stop somehow?

void stoppet(){
  stopknap = digitalRead(stopknappin);
  if (stopknap==HIGH){
    inite();
  }
  else
    if (stopknap==LOW){
      stoppet();
    }

Regards Nic

Recursion without limits is a really, really bad idea on...well, any architecture.
If you need to loop, put a proper loop construct in.

nic6911:
The thing about the stoppet and it calling itself all the time. I do this to make a loop in stoppet so that it checks itself over and over again...

void stoppet(){

stopknap = digitalRead(stopknappin);
  if (stopknap==HIGH){
    inite();
  }
  else
    if (stopknap==LOW){
      stoppet();
    }

This code is going to crash your Arduino faster than you can blink. And a "crashed" Arduino is likely to reset or freeze.

If you want to wait while stopknappin is low, do something like this:

void stoppet(){

  while (digitalRead(stopknappin) == LOW)
    ;  // loop 

  inite();

    }

But I fear even this is fundamentally flawed. An ISR can fire in the middle of your "loop" function (it probably will). Why not just test this button inside loop? No need for an "emergency stop ISR".

Any emergency stop should not be dependent of code.

Why not have a global variable that is set inside your ISR and is ALWAYS tested together with blocking functions of your code?

This depends on code doesn't it?

If you want a "real" emergency stop, have a switch on the side that cuts off supply from the battery.