arduino-fsm icon indicating copy to clipboard operation
arduino-fsm copied to clipboard

Possible problem on timed_transitions

Open njbuch opened this issue 6 years ago • 3 comments

Consider these transitions:

fsm.add_timed_transition(&state_waitfortriggerack, &state_waitfortriggerack, 3000, NULL);
fsm.add_transition(&state_waitfortriggerack, &state_rpinotworking, TIMEOUT, NULL);

and then I am doing a:

fsm.trigger(TIMEOUT);

I was expecting the loop of the 3000ms to stop, but it keeps calling the entry function of state_waitfortriggerack. The fsm.trigger(TIMEOUT) is actually changing the state and doing its thing, but the timed transition keeps repeating.

njbuch avatar Jan 22 '18 22:01 njbuch

Ping, anyone has managed to use timed transactions to same state?

njbuch avatar Apr 29 '18 18:04 njbuch

Hi, this is what I used and it seemed to work:

/* ----------------------------------------------------- */
#include "Fsm.h"
#include "Button2.h";
/* ----------------------------------------------------- */
#define TIMEOUT 1000
/* ----------------------------------------------------- */
void waitfortriggerack() {
  Serial.println("waitfortriggerack");
}

void rpinotworking() {
  Serial.println("rpinotworking");
}
/* ----------------------------------------------------- */
State state_waitfortriggerack("wait", &waitfortriggerack);
State state_rpinotworking("rpinotworking", &rpinotworking);

Fsm fsm(&state_waitfortriggerack);
Button2 btn = Button2(D0);
/* ----------------------------------------------------- */
void btn_released(Button2& btn) {
  Serial.println("CLICK");
  fsm.trigger(TIMEOUT);
}
/* ----------------------------------------------------- */
void setup() {
  Serial.begin(9600);
  delay(50);

  fsm.add_timed_transition(&state_waitfortriggerack, &state_waitfortriggerack, 3000, NULL);
  fsm.add_transition(&state_waitfortriggerack, &state_rpinotworking, TIMEOUT, NULL);
  
  btn.setReleasedHandler(btn_released);
}
/* ----------------------------------------------------- */
void loop() {
  btn.loop();
  fsm.run_machine();
}
/* ----------------------------------------------------- */

This is the output - I pressed the button after a little while:

waitfortriggerack
waitfortriggerack
waitfortriggerack
waitfortriggerack
waitfortriggerack
CLICK
rpinotworking

After the button press, the machine keeps the RPI state.

LennartHennigs avatar May 08 '18 06:05 LennartHennigs

In case anyone runs into this, there's a limitation that isn't super obvious in the FSM code as it is implemented. The state isn't recorded as being changed until after the on_enter is called on the new state. As a result, if you use trigger to send an event from the start of the new state, it won't find a transition from that new state to the next state.

i.e., if you have three states "one", "two" and "three", and you have a timed transition from two back to itself, it'll get called forever if you try to do a trigger(three) in the start method for two.

I fixed it in a local copy of the library by moving the m_current_state = transition->state_to; line in make_transition above the transition->state_to->on_enter() call.

Its a behavioral change, but because there's no real documentation for the library its unclear if the prior behavior is as-intended or not.

dotorg avatar Apr 15 '19 19:04 dotorg