Coder Social home page Coder Social logo

arduino-fsm's People

Contributors

jonblack avatar pedrolopes avatar per1234 avatar thelmos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduino-fsm's Issues

States not transitioning properly

I am trying to transition cyclically between 3 states. But after the first transition it just stops. I'm not sure if it's my programming or something with the library. Can't seem to find similar examples. Any help would be appreciated. Thanks.
`#include <Fsm.h>

#define ARMED_RFID_TRIG 1
#define RFID_BLUE_TRIG 1
#define BLUE_ARMED_TRIG 1

void on_armed_on_enter();
void rfid_on_enter();
void blue_on_enter();

State state_armed(&on_armed_on_enter, NULL, NULL);//armed state, default
State state_rfid_scan(&rfid_on_enter,NULL, NULL);
State state_blue_scan(&blue_on_enter,NULL, NULL);
Fsm fsm(&state_armed);

void on_armed_on_enter()
{
Serial.println("entering armed");
fsm.trigger(ARMED_RFID_TRIG);//trigger transition from armed to rfid
delay(1000);
}
void rfid_on_enter()
{
Serial.println("entering rfid scan state");
delay(1000);
fsm.trigger(RFID_BLUE_TRIG);
}
void blue_on_enter()
{
Serial.println("entering bluetooth scan state");
fsm.trigger(BLUE_ARMED_TRIG);//trigger transition from rfid to blue
delay(1000);
}
void setup() {
Serial.begin(9600);
Serial.println(">> starting setup>");
//STATE TRANSITIONS
fsm.add_transition(&state_armed, &state_rfid_scan, ARMED_RFID_TRIG, NULL);//state from->state to->if event trigg
fsm.add_transition(&state_rfid_scan, &state_blue_scan, RFID_BLUE_TRIG, NULL);
fsm.add_transition(&state_blue_scan, &state_armed, BLUE_ARMED_TRIG, NULL);
}

void loop() {
fsm.run_machine();
delay(100);

}`

When to set m_current_state

Hi,
thank you for that wonderful and lean implementation of an FSM.
When test driving it, I came across the following question (probably not an issue):

The m_current_state is set after execution of transition->state_to->on_enter.
This means, you cannot set a trigger in the on_enter function to directly move to the next state.
Is this meant to be like this, or should m_current_state rather be set before execution of transition->state_to->on_enter?

void Fsm::make_transition(Transition* transition)
{
// Execute the handlers in the correct order.
if (transition->state_from->on_exit != NULL)
transition->state_from->on_exit();

if (transition->on_transition != NULL)
transition->on_transition();

if (transition->state_to->on_enter != NULL)
transition->state_to->on_enter();

m_current_state = transition->state_to;

"In state" callback function not executed?

I've created the following example.

#include "Fsm.h"

#define STATE_1_TO_2_EVENT 1
#define STATE_2_TO_1_EVENT 2

void on_state_1_on_enter()
{
  Serial.println("Entering State 1");
}

void on_state_1_in_state()
{
  Serial.println("State 1");
}

void on_state_1_on_exit()
{
  Serial.println("Exiting State 1");
}

void on_state_2_on_enter()
{
  Serial.println("Entering State 2");
}

void on_state_2_in_state()
{
  Serial.println("State 2");
}

void on_state_2_on_exit()
{
  Serial.println("Exiting State 2");
}

State state_1(&on_state_1_on_enter, &on_state_1_in_state, &on_state_1_on_exit);
State state_2(&on_state_2_on_enter, &on_state_2_in_state, &on_state_2_on_exit);
Fsm fsm(&state_1);

void on_trans_1_to_2() {
    Serial.println("State 1 -> State 2");
}

void on_trans_2_to_1() {
    Serial.println("State 2 -> State 1");
}

// standard arduino functions
void setup()
{
  Serial.begin(9600);

  fsm.add_transition(&state_1, &state_2,
                     STATE_1_TO_2_EVENT,
                     &on_trans_1_to_2);
  fsm.add_transition(&state_2, &state_1,
                     STATE_2_TO_1_EVENT,
                     &on_trans_2_to_1);
  fsm.run_machine();
}

void loop()
{
  delay(2000);
  fsm.trigger(STATE_1_TO_2_EVENT);
  delay(2000);
  fsm.trigger(STATE_2_TO_1_EVENT);
}

If I run the example the serial console output is as follows:

Entering State 1
State 1
Exiting State 1
State 1 -> State 2
Entering State 2
Exiting State 2
State 2 -> State 1
Entering State 1
Exiting State 1
State 1 -> State 2
Entering State 2
Exiting State 2
(...)

The "in state" callback function for state 1 on_state_1_in_state() is executed only once, implicitly as part of Fsm fsm(&state_1);. The callback function for state 2 on_state_2_in_state() is not executed at all. Have I not used the API correctly?

Trigger is not reentrant

Hi,

I would like to be able to call trigger from within a "enter" or "transition" function.
Do you see a easy modification of your lib to be able to write something like this:( modify your light_switch.ino and change just de bellow functions)

void on_light_on_enter()
{
  Serial.println("Entering LIGHT_ON");
  delay(2000);
  fsm.trigger(FLIP_LIGHT_SWITCH);
}

void on_light_off_enter()
{
  Serial.println("Entering LIGHT_OFF");
  delay(2000);
  fsm.trigger(FLIP_LIGHT_SWITCH);
}

void loop()
{
  fsm.trigger(FLIP_LIGHT_SWITCH);
}

My goal is to write some "routing state" that would automatically branch to another state depending on the value of some sensor. Something like:

void on_router_enter()
{
   int a = readSensor()
   if (a>5) {
       fsm.trigger(GO_STATE_HIGH);
   } else {
       fsm.trigger(GO_STATE_LOW);
   }
}

Regards,
Redge

License clarification

The LICENSE file states that the software is under the MIT license, while Fsm.cpp and Fsm.h state that the license is GPLv3; can you please fix it?
Thanks

Serial garbage

I'm using timed transitions and the serial gets filled with numbers: why is there a Serial.println(now) in Fsm.cpp:120?

fsm.trigger() not working

I wanna trigger a state change every 10 sec but it is not working..

#define WRITE_EVENT 2

while ( millis() - timer1 > 10000 ) {
Serial.print("<<< ");
Serial.print( millis()/divider );
Serial.println(" triggered stateWriteSerial");
fsm.trigger(WRITE_EVENT);
timer1 = millis();
}

setup() {

fsm.add_transition(&stateIdle, &stateWriteSerial, WRITE_EVENT,NULL );

}

Multiple triggers

To explain my problem a little more in detail. I wasn't able to get loops to run within each state to properly refresh the values being recorded and displayed from each sensor. As a solution I decided to implement a second trigger, that I called refresh_toggle, which would be regularly called such that a state would exit and enter back to itself thus refreshing the outputted data. The original trigger is used toggle between each sensor via push button that triggers display_button, causing the state to go to its next respective state. Within my setup I followed the example code and defined all my transitions. The transitions for the push button are defined first and the refresh transitions defined below them. My problem is that the refresh_toggle trigger triggers the display_button transitions, which are defined first. It's as if the trigger specified within the transition is irrelevant and the first found transition, matching the current state, is triggered.

#define display_button 1
#define refresh_toggle 1

//State machine states
State state_time_display(display_time_enter,display_time_exit);
State state_temperature_display(display_temperature_enter, display_temperature_exit);
State state_pressure_display(display_pressure_enter,display_pressure_exit);
State state_moisture_display(display_moisture_enter,display_moisture_exit);
State state_light_display(display_light_enter,display_light_exit);

Fsm fsm(&state_time_display);
  fsm.add_transition(&state_time_display,&state_temperature_display,
                    display_button,&trans_time_temperature);
  fsm.add_transition(&state_temperature_display,&state_pressure_display,
                    display_button,&trans_temperature_pressure);
  fsm.add_transition(&state_pressure_display,&state_moisture_display,
                    display_button,&trans_pressure_moisture);
  fsm.add_transition(&state_moisture_display,&state_light_display,
                    display_button,&trans_moisture_light);
  fsm.add_transition(&state_light_display,&state_time_display,
                    display_button,&trans_light_time);

  //state refresh transitions
  fsm.add_transition(&state_time_display,&state_time_display,
                    refresh_toggle,NULL);
  fsm.add_transition(&state_temperature_display,&state_temperature_display,
                    refresh_toggle,&trans_temperature_refresh);
  fsm.add_transition(&state_pressure_display,&state_pressure_display,
                    refresh_toggle,&trans_pressure_refresh);
  fsm.add_transition(&state_moisture_display,&state_moisture_display,
                    refresh_toggle,&trans_moisture_refresh);
  fsm.add_transition(&state_light_display,&state_light_display,
                    refresh_toggle,&trans_light_refresh);


}

void loop() {

  buttonState = digitalRead(buttonPin);
  if(buttonState == HIGH){
    fsm.trigger(display_button);
    delay(10);
    fsm.trigger(refresh_toggle);
  }

This causes the first two transitions to occur given the machine starts in the state_time_display state.

Any further development plans for this project?

Dear Jon and contributors

I was in the midst of writing my own FSM library when I came across this repo.

However, I can see that it has not been updated in years.

Are there any alternative forks that took over the maintenance of this project?

Otherwise, is anyone willing to keep it alive? I could personally do it however, I would need to find some space in my (very) busy schedule

Cheers

Sleep mode ?

Hi, I tried the fsm library and it works like a charm, even on a ESP8266! Thanks.
I'd like to know what happens if I put the arduino in sleep mode, like this:

#include <avr/power.h>
...
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);

How will my state machines behave? Will they still run or should I add a wakeup instruction at the beginning of the transition state functions?
Fabrice

Possible problem on timed_transitions

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.

Store current state of state machine in EEPROM and on next boot initalize state machine with that state

This is a question/feature request:
Store current state of state machine in EEPROM and on next boot initalize state machine with that state.

I guess these sub-issues had to be solved for this to work:

  • get the current state of the state machine (the pull request #24 implements this).
  • either serialize the current state object or create a unique identifier of it and store this in EEPROM/flash. Again pull request #24 adds names for states which could be used as identifiers; but currently these names are not guaranteed to be unique.
  • after reboot: create state objects in a way that one of the newly created ones can be identified as the stored one (or detect incompatible state).
  • if state from EEPROM is valid, initialize state machine with that state.

This would be useful if deep sleep is used to save battery/energy.

Allow on_state() functions

Allow states to have a on_state() function that will run while in that state.

Main program loop will need a call to run_machine() to resolve than on_state() calls and resolve timed transitions.

This example shows how it would work (not tested, can contain errors):

#include <Fsm.h>

/*
 * FSM Library sample with user and timed
 * transitions.
 * Uses a button and Arduino builtin led, 
 * button can be replaced just grounding 
 * pin.
 */

// Used pins
#define LED_PIN     13
#define BUTTON_PIN  8

//Events
#define BUTTON_EVENT  0

int buttonState = 0;

/* state 1:  led off
 * state 2:  led on
 * transition from s1 to s2 when pusshing button
 * transition back from s2 to s1 after 3 seconds
 * SECOND PARAM IS NEW "on_state()" FUNCTION
 */
State state_led_off(&led_off, &check_button, null);
State state_led_on(&led_on, null, null);
Fsm fsm(&state_led_off);

// Transition functions
void led_off()
{
  digitalWrite(LED_PIN, LOW);
}

void led_on()
{
  digitalWrite(LED_PIN, HIGH);
}

void check_button()
{
  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {
    fsm.trigger(BUTTON_EVENT);
  }
}

// standard arduino functions
void setup()
{
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);

  fsm.add_transition(&state_led_off, &state_led_on,
                     BUTTON_EVENT, null);
  fsm.add_timed_transition(&state_led_on, &state_led_off, 3000, NULL);
}

void loop()
{
  // Call fsm run
  fsm.run_machine();
}

Links in Documentation section of Readme now dead

The humblecoder.com domain that the two links in the section point to is not registered anymore. It now redirects to advertisements. It might be rescued with archive.org as an alternative to looking for a new set of examples.

Allow dynamic time transitions

A user left a comment on the blog asking for the ability to set the timed transition interval dynamically. I need a good use case example for this.

Add timing to state transitions

A comment on my blog asked about using multiple FSM's to simulate multi-tasking. This is a nice idea, but the FSM cannot control the timing in its current state.

For example, if you want a servo to spin for 3 seconds and during the same period have an LED blink 6 times, the client needs to keep track of the time. In a large sketch with a lot of multi-tasking, this would be cumbersome.

A possible solution is to add a function called add_timed_transition which takes a parameter stating how long the FSM stays in the given state before automatically transitioning to another.

trigger running transition function before old state exits.

For example I have 2 states where from state_idle we trigger event to change to state_manual. Trigger is called in function on_state_idle. Monitor log illustrating issue:

  1. ENTER: state_idle_enter
  2. EXIT: state_idle_exit
  3. ENTER: state_manual_enter
  4. STATE idle after trigger

Here I noticed that trigger function actually calls Fsm::make_transition, witch will call state_idle_exit, and after that state_manual_enter state transition functions.
Problem is that execution continues still in on_state_idle function witch produces my debug printout "STATE idle after trigger". Of course we cannot bail out from on_state_idle, but it would make more sense that transition would occur only when run_machine is called next time, witch would prevent above condition.

Thank you for this awesome library!

C memory management functions

Usually in embedded uC it is not recommended to use low-level memory management functions.
Can you think of possible workarounds, including checking if there's enough free memory to run dynamic allocation?

call back objects support

  1. currently, fsm can work only with free call back functions:
struct State {
  State(void (*on_enter)(), void (*on_state)(), void (*on_exit)());
  void (*on_enter)();
  void (*on_state)();
  void (*on_exit)();
};
  1. this makes fsm non-composable with objects, lambdas, etc.

  2. please add support for call back objects instead:

struct State {
  virtual void on_enter() = 0;
  virtual void on_state() = 0;
  virtual void on_exit() = 0;
};
  1. same also applies to transitions
  struct Transition
  {
    State* state_from;
    State* state_to;
    int event;
    void (*on_transition)();

  };

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.