Yes, I don't get it. Can you please explain better, best show the code to be generated from your diagram?
You have a small circle on the arrows with a value in it like the 0 and 3 here
My understanding is that it’s the binary value described here ( combine CK and DT as two bits)
So it means if the combined two bits is 0 (ie 00) then go to that next state and if it’s 3 (ie 11) go to that other state.
In your diagram I suppose you would write the condition in full like (CK==HIGH and DT==HIGH) instead of just the 3
He used indeed the combination as the state name (which means the diagram has multiple states with the same name which I don’t like)
they are the labels on the arcs: CW, CCW, limit, 10K, they are the stimuli to the state machine
this isn't one I drew. some are conditions for a state change: not CCW || limit. Instead of an OR case, there could be separate transitions for ! CW and limit
a more classic state machine implementation (one i'm more familiar with in communication) can be defined by 2 tables
typedef enum { S0, S1, S2 } State_t;
typedef Status(*Action_t)(void*) ;
State_t smTransitionTbl [N_STATE] [N_STIM] = {
{ S1, S2, },
{ S0, S2, },
{ S2, S1, },
};
Action_t smActionTbl [N_STATE] [N_STIM] = {
{ a, b },
{ c, __ },
{ __, a },
};
the smActionTbl [] contain function ptrs for actions performed during a transition. Some actions can be no-ops, ___ () (yes, the name of the function is "___". the following examples just print the function name
Status
c (void* a)
{
printf ("%s:\n", __func__);
return OK;
}
Status
__ (void* a)
{
printf ("%s:\n", __func__);
return OK;
}
the smTransitionTbl [] specifies the new state.
a stateMachine driver processes a stimuli, it capture the action function, updates the state and executes the action function. The transition needs to be complete before executing the action because the action may execute the state machine
stim is simply an integer that can be defind with symbols in an enumeration (e.g. CW, CCW)
static State_t _smState = S0;
Status
smEngine (Stim_t stim)
{
Action_t func;
State_t last = _smState;
if (N_STIM <= stim)
return ERROR;
func = smActionTbl [_smState] [stim];
_smState = smTransitionTbl [_smState] [stim];
printf (" stim %d, transition from state %d to %d, exec ",
stim, last, _smState);
return (*func) (NULL);
}
the beauty of this approach is that the state machine -- what the states are and what actions are to be taken without worrying the details of the action -- are all captured in the tables, not logic
I see no definition of a stimulus in your tables. Where and how is the current stimulus determined? Will you test all possible inputs (buttons...) in order to determine whether one is pressed and determines the current stimulus? It were much more efficient to only test the really possible stimuli of the current state. How can special combinations of buttons be handled?
Sometimes a state is left with a timeout or error in an action. How can that be implemented?
Hello pmi1234
Here is a very simple state machine for your own studies.
void (*state)();
void state_1()
{
Serial.println(__func__);
state = state_2; // switch to next state
}
void state_2()
{
Serial.println(__func__);
state = state_3; // switch to next state
}
void state_3()
{
Serial.println(__func__);
state = state_1; // switch to next state
}
void setup()
{
Serial.begin(115200);
Serial.println("start");
state = state_1; // start state
}
void loop()
{
state(), delay(1000); // for testing only
}
the 2 dimensional tables are indexed by state and stimulus. both are integers which symbols (e.g. CW, CCW, Tmout) can be defined for
buttons can be stimuli, some may be ignored, ___().
special code could be written to recognize multiple button being pressed (e.g. ctl-alt-del) as a unique stimuli. Otherwise there could be states recognizing the either of the buttons is pressed which cause a specific action if the other button is them pressed while in that state.
a timer can be a stimulus. it's likely to have different meanings in different states.
a stimulus in a particular state can be an error which would need to be handled in the action routine for that stimulus in that state. Severe error can always reset the state machine back to the start state
not sure i'm addressing all your questions. Tables are a simple, more methodical, data driven approach instead of using logic: switch and if statements. The table approach requires that all possible transitions be handled or ignored (i.e. ___())
Somebody’s been playing definition a bit too much, probably needs more real work.
I will define and fit states to accomplish my goals as I have been since 1980 or 1981. What Real I care about is If It REALLY WORKS.
No that is not a state machine, that is the implementation of a state machine. The actual state machine, the diagram you write this code from, is unknown.
I have enjoyed the conversation so far and learned some things.
Here is my state diagram for the launcher as of this point. Still needs some work. I decided to have a state called configuration to decode the messages, set up the hardware, and send a response to the controller, if needed. The launch state is external from config as it uses a timer to get back to waiting. The pairing state has some back and forth communication with the controller, so I found it cleaner to give it is own state as the hardware (LEDs and other displays) change with the communication.
The messages are simple:
typedef enum COMMANDS {
CMD_WAIT,
CMD_CHECK_IN,
CMD_CHECK_IN_OK,
CMD_PAIR_LAUNCHER,
CMD_LAUNCHER_PAIRED,
CMD_LAUNCH,
} Command;
I am using SimpleFSM for the state machine.
I think you would win clarity by
-
having unique states name if this is what you call the large squares. Could be like CW0 CW1 CW2 and CCW0 CCW1 CCW2 and The box labeled 3 could be START
-
using a different kind of box or labeling to flag variable settings
-
spell out the conditions in plain English like
(CK is HIGH and DT is HIGH)or potentiallyCK & DTand use the bar notation if not asserted - which would show a hardware background
The idea is that the diagram should be something as self explanatory as possible
And I agree. I have seen state machines that looked like works of art in their formalization but were completely useless for handling any practical task. However, for a “beginner in state programming,” it is important to understand that a state waits for something, while an improper state (one that does not wait for anything) can certainly be written and used, but may cause the loss of impulsive events that last only a single processing cycle. Once someone has understood the method, the implications of different implementation choices, and how to deal with various edge cases, then they can certainly do everything.
The problem with this representation is that it looks like there are two state 0, two state 1, and two state 2, whereas they are actually seven different states. I do understand, however, that the purpose is to show how the value of the bits read from the encoder changes at each step.
A note that applies to all diagrams presented in this topic:
A state machine is not only triggered when a condition (stimulus) changes. This requires that the current state is not changed if none of the expected stimuli occurs.
In your case e.g. state 1 is kept on stimuli1, changed to 0 on stimuli 0, and state 3 is reached only on stimuli 2, not on !0. Likewise state 3 does not change on stimuli 0 or 3.
it's hard for me to understand the purpose of the SM without understanding "what" it does?
why do you describe your processing of messages as configuration? are message only used to configure?
and what does launch mean, start some processing, what processing
and pairing. ???
since it appears that each stimulus is a 2-bit value, does NOT 2 mean anything other than 2: 0, 1, or 3, or does it mean 0x1?
not sure the following makes sense for state 0.
in state 0, isn't 1, NOT 2 and similarly 2, NOT 1 -- don't see how this can be implemented using a single state
and also, is a transition thru state from state 0 needed? why not just increment the cntr when stim 2 occurs in state 0 and transition to state 3?
i think this correct for the encoder below
the labels indicate the stim/action where action is a cw or ccw tic
digraph G {
Zero -> A [label = "A/ccw"]
Zero -> B [label = "B/cw"]
A -> AB [label = "B/ccw"]
B -> AB [label = "A/cw"]
A -> Zero [label = "!A/cw"]
B -> Zero [label = "!B/ccw"]
AB -> A [label = "!B/cw"]
AB -> B [label = "!A/ccw"]
}
> b
cw: 1
stateMach: 1 StA
> a
cw: 2
stateMach: 0 St0
> B
cw: 3
stateMach: 2 StB
> A
cw: 4
stateMach: 3 StAB
> b
cw: 5
stateMach: 1 StA
> a
cw: 6
stateMach: 0 St0
> A
ccw: 5
stateMach: 1 StA
> B
ccw: 4
stateMach: 3 StAB
> a
ccw: 3
stateMach: 2 StB
> b
ccw: 2
stateMach: 0 St0
> A
ccw: 1
stateMach: 1 StA
> B
ccw: 0
stateMach: 3 StAB
>







