Possible to create a "Timeout" for the Arduino sketch if no input in a certain time?

Hi!

I have a sketch running a couple of continuous rotation servos. I'm using one of them to control an object back and forth using string around a pulley, and microswitches as endpoints to make it change direction - this works perfectly.

As this will be running unattended, I want to have a failsafe function implemented, f.ex. "if microswitch left/right hasn't been clicked in the last two minutes, freeze sketch".

Is this possible?

It's just as a failsafe IF one of the microswitches were to fail, or any other strange hick-up, the string will most likely just skip around the pulley, with the obvious wear and tear.

How can I count since last input from 10 or 11? Or any input for that matter (it's the only ones).

Is this possible?

Yes. Use millis() for timing rather than delay() as the latter will stop anything else happening during the delay().

So, save the current value of millis() when you want to start timing then each time through loop() check whether the required input has been received or the required time has elapsed and execute code for either event as appropriate.

UKHeliBob: Yes. Use millis()

Aha!

I think I got it now, so maybe something like this? (in loop)

  unsigned long currentMillis = millis(); // refresh counter variable

  if (leftButtonState == LOW) {         // check if left button is activated,
     directionValue = 1;                // update direction value (1=right)
     previousMillis = currentMillis;    // reset timeout counter
  }
  else if (rightButtonState == LOW) {   // check if right button is activated,
    directionValue = 0;                 // update direction value (0=left)
    previousMillis = currentMillis;     // reset timeout counter
  }

  // failsafe test
  while (currentMillis - previousMillis > interval) {
    balloonServo.write(90);         // center/stop balloon servo
    lightServo.write(90);           // center/stop light servo
    
    // quickly flash status LED while stopped
    digitalWrite(statusLed, HIGH); 
    delay(200);
    digitalWrite(statusLed, LOW);
    delay(200);
  }
  
  if (directionValue == 0){             // check direction
    lightServo.write(180);              // spin servo left 
  }
  else {
    lightServo.write(0);                // spin servo right
  }

That looks like it would work as long as your aim is to completely stall the program and hold it in the while loop with no way out. Personally I would write to the servos just once and set a flag to lock the program in the while loop. To my mind it would make the code more readable and obvious what is going on.

  // failsafe test
  if (currentMillis - previousMillis > interval) 
  {
    balloonServo.write(90);         // center/stop balloon servo
    lightServo.write(90);           // center/stop light servo
    failsafe = true;
  }
  while (failsafe)
  {
    // quickly flash status LED while stopped
    digitalWrite(statusLed, HIGH); 
    delay(200);
    digitalWrite(statusLed, LOW);
    delay(200);
  }

Exactly.

I changed it to If, to get it out of the While loop, which also worked as the "previousMillis" still won't be updated.

Your approach seems much better. Thanks!

I guess I'll also have to update these two to include "failsafe = false;" then?

  if (leftButtonState == LOW) {         // check if left button is activated,
     directionValue = 1;                // update direction value (1=right)
     previousMillis = currentMillis;    // reset timeout counter
     failsafe = false;
  }
  else if (rightButtonState == LOW) {   // check if right button is activated,
    directionValue = 0;                 // update direction value (0=left)
    previousMillis = currentMillis;     // reset timeout counter
    failsafe = false;
  }

Or, of course the alternative could be to declare/set value to the "failsafe" variable in the loop void and be changed each time. What would be "best"? ...I guess it will have to be on each of the buttons to be able to exit that while loop?

I guess it will have to be on each of the buttons to be able to exit that while loop?

As it stands at the moment there is no way out of the while loop so you do not need to set the failsafe variable to false except at startup. If you want to exit the while loop once the error condition is cleared you will need to read something from within the while loop to indicate that it is safe to proceed and set the failsafe variable to false at that point.

Ah, of course.

It's not a big problem though, but I could include the button check in the while loop again - if it detects any buttons being activated, set failsafe to false.

I could include the button check in the while loop again

You don't actually need the while loop because the loop() function will repeat code for you.

What you have is a simple state machine that has 2 states, ie failsafe and !failsafe. Read the buttons in loop() and take action depending on the current state. If you want to flash LEDs when in failsafe do so using the BlinkWithoutDelay principle rather than delay()

Reading the inputs in one place will result in code that is more easily maintained and a state machine based on switch/case makes it more readable. It may seem like a lot of work for such a simple program but it is a powerful technique to have in your arsenal of programming techniques.