Starting a timer on a bigger than condition

Here is my situation:
I built a robot and burned a motor while it reached physical limitations and I did not paid attention .
Never again, I declared but this is not simple...

I implemented current sensors and did the analog read to Amps conversion.

so here is my function that I rings the alarm.

void CurrentAlarm (float Limit ) // in my case is 3A

{

if (Curr_A > Limit)
{ tone(Tone_Pin, 5000 , 500);

}
Works well, but with every motion the alarm rings and stops. As the motors reach their target.

The right way to do this:
If the "Limit" is exceeded for more than 4 sec, ring the alarm for 3 sec, and then stop the motors.

how do I create a "Time stamp" at the moment of (Curr_A > Limit) that would not update while the condition is true?

Cant use delays, there are another 100 processes going on.
If I can create the time stamp, (mills at that point) than I can do "this" at 3000 mills later, and that at 4000 mills later.... etc.

If the current drops in the meantime, (before the "stop Motors") all alarms and shut offs should be reset.

I thought this is not hard, but ... here I am. Please help

Thank you,
Mitch
I

You have 77 posts so you should know that code belongs inside the code-tag ...

You can solve this using a very simple state machine.

statemachine.jpg

S0 is the initial state. In that state the current is checked against the limit every time the CurrentAlarm function is called. When the current exceeds the limit, the sm (statemachine) changes to state S1. In there, time and current are monitored until either time > 3s or the current falls below the limit. S2 is essentially the same as S1, but it waits for 4s.

On exit of S0, you record the timestamp, which is checked in S1 and S2. On exit of S1 you play the beep tone and on exit of S2 you stop the motors. In S4 you can have conditions for current exceeding even after the motors are turned off (motor failure).

enum current_monitor_states {
  STATE_IDLE,
  STATE_LIMIT_EXCEEDED,
  STATE_LIMIT_EXCEEDED_FOR_3S,
  STATE_LIMIT_EXCEEDED_FOR_4S
} current_monitor_state;

void CurrentAlarm(int current, int limit) {
  static unsigned long current_exceeded_time;
  
  // if the current is lower than limit reset the state machine
  if(current <= limit) {
    Serial.println("current monitor: idle");
    current_monitor_state = STATE_IDLE;
    return;
  }
  
  switch(current_monitor_state) {
    case STATE_IDLE:
      if(current > limit) {
        Serial.println("current monitor: limit exceeded");
        current_monitor_state = STATE_LIMIT_EXCEEDED;
        current_exceeded_time = millis();
      }
      break;
    case STATE_LIMIT_EXCEEDED:
      // check the time
      if((millis() - current_exceeded_time) > 3000) {
        current_monitor_state = STATE_LIMIT_EXCEEDED_FOR_3S;
        // play beep
        Serial.println("beep");
      }
      break;
    case STATE_LIMIT_EXCEEDED_FOR_3S:
      // check the time
      if((millis() - current_exceeded_time) > 4000) {
        current_monitor_state = STATE_LIMIT_EXCEEDED_FOR_4S;
        Serial.println("motors off");
      }
      break;
    case STATE_LIMIT_EXCEEDED_FOR_4S:
      break;
  }
}

EDIT: I misread the timing you provided, but you should be able to adapt the code to your needs.

statemachine.jpg

It worked like a charm. Thanks a million,

I heard of machine state but I never 'got it", this all makes sense.
I will ad another few more machine states, who needs breakers anymore?

here is my implemented function:

void CurrentAlarm (float limit )

{ static unsigned long current_exceeded_time;
  Curr_A = (analogRead(A6) - 3000) / 10;
  CurrA_Ave.push(Curr_A);
  Curr_A = CurrA_Ave.mean();
  //Serial.print(Curr_A);
  Curr_A = map(Curr_A, 12.5, 48, 0.13, 3.25);
  Curr_A = constrain (Curr_A, 0, 13);

  Curr_B = (analogRead(A7) - 3000) / 10;
  CurrB_Ave.push(Curr_B);
  Curr_B = CurrB_Ave.mean();
  Curr_B = map(Curr_B, 12.5, 48, 0.13, 3.25);
  Curr_B = constrain (Curr_B, 0, 13);


 //if the current is lower than limit reset the state machine
  if(Curr_B <= limit) {
      Serial.println("current monitor: idle");
    current_monitor_state = STATE_IDLE;
    return;
  }
  
  switch(current_monitor_state) {
    case STATE_IDLE:
      if(Curr_B > limit) {
        Serial.println("current monitor: limit exceeded");
        current_monitor_state = STATE_LIMIT_EXCEEDED;
        current_exceeded_time = millis();
      }
      break;
    case STATE_LIMIT_EXCEEDED:
      // check the time
      if((millis() - current_exceeded_time) > 3000) {
        current_monitor_state = STATE_LIMIT_EXCEEDED_FOR_3S;
        tone(Tone_Pin, 1000 , 500);
        Serial.println("beep");
      }
      break;
    case STATE_LIMIT_EXCEEDED_FOR_3S:
      // check the time
      if((millis() - current_exceeded_time) > 1000) {
        current_monitor_state = STATE_LIMIT_EXCEEDED_FOR_4S;
        Serial.println("motors off");
      }
      break;
    case STATE_LIMIT_EXCEEDED_FOR_4S:
       Bus_Stop ();
      tone(Tone_Pin, 5000 , 500);
      break;
  }



  /* Serial.print(analogRead(A6));
    Serial.print("  curr A: ");
    Serial.print (Curr_A, 1);
    //Serial.print(analogRead(A7));
    Serial.print("  curr B: ");
    Serial.println(Curr_B, 1);
  */

}