ETLCPP / etl

Embedded Template Library
https://www.etlcpp.com
MIT License
2.05k stars 372 forks source link

HFSM: How do I get information about the parent from the child state? #853

Closed digiexchris closed 2 months ago

digiexchris commented 4 months ago

Could you perhaps add some usage examples for HFSM? I'm having trouble trying to wrap my head around how to interact with the child states where there are multiple parent states that have several common child states between them.

eg:

Encoder HFSM can be in a parent state "Incremental" or "Absolute", and each parent state can have a child state being either "Moving" or "Stopped".

How can I determine that the FSM is in the Incremental "Moving", and not the absolute Moving state? It's likely I'm misunderstanding something fundamental about the HFSM implementation.

jwellbelove commented 4 months ago

I think that the idea of substates in an HFSM is that they are independent of their parent states. They are meant to be common functionality. If Incremental Moving and Absolute Moving require different functionality then they should probably be different sub-states.

I must admit I am not an expert in hierarchical state machines. I wrote the original FSM implementation and someone else added the HFSM, as an extension to it.

digiexchris commented 4 months ago

AH I see, thank you! would you be open to me making a pr that exposes a getter to access the parent from the child?

On Sat, Mar 2, 2024, 04:00 John Wellbelove @.***> wrote:

I think that the idea of substates in an HFSM is that they are independent of their parent states. They are meant to be common functionality. If Incremental Moving and Absolute Moving require different functionality then they should probably be different sub-states.

I must admit I am not an expert in hierarchical state machines. I wrote the original FSM implementation and someone else added the HFSM, as an extension to it.

— Reply to this email directly, view it on GitHub https://github.com/ETLCPP/etl/issues/853#issuecomment-1974751404, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABMZQGRQDXLNWKJUELPJBB3YWGPLVAVCNFSM6AAAAABECNVPOGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNZUG42TCNBQGQ . You are receiving this because you authored the thread.Message ID: @.***>

jwellbelove commented 4 months ago

Yes go ahead. Don't forget to update the etl::hfsm unit tests. If you are altering etl::fsm, you'll also need to reflect the changes in fsm_generator.h.

KLMANDARA commented 3 months ago

Using inheritance concept And sub class and superclass

pulkitpathak99 commented 3 months ago

Understanding Child States with Multiple Parents:

In your encoder example, "Moving" and "Stopped" are child states shared by both "Incremental" and "Absolute" parent states. Here's how to handle interactions:

State Naming: Clearly differentiate states with distinct prefixes or suffixes reflecting their parent. Here, you could rename the child states to:

IncrementalMoving IncrementalStopped AbsoluteMoving AbsoluteStopped Transitions: Define transitions explicitly within the child state itself. Consider these examples:

If a transition from another state leads to "moving" behavior regardless of the parent state (e.g., receiving an "encoder started" event), the transition within the Moving child state could look like:

Moving -> IncrementalMoving (if current parent is Incremental) Moving -> AbsoluteMoving (if current parent is Absolute) This ensures the transition goes to the appropriate state based on the current parent.

Event Handling: If events trigger transitions to different parent states from the child state, handle the event logic within the child and explicitly specify the target state based on the event context.

State Activation/Deactivation: When a parent state becomes active, its child states might need specific handling. Consider implementing entry/exit actions in the child state to perform necessary actions upon parent state activation/deactivation. For example, the IncrementalMoving state might need to reset an incremental counter upon entry, while AbsoluteMoving might set a different initial value.

Determining Current State within a Parent:

Here, considering the distinct child state names, you can easily determine the current state within a parent:

State Stack: If using a state stack, the top element would reveal the current state. In your example, if the stack shows "IncrementalMoving", you know the HFSM is in the "Incremental" parent state with the "Moving" child state active.

State Flags: With state flags, you'd have separate flags for IncrementalMoving, IncrementalStopped, AbsoluteMoving, and AbsoluteStopped. By checking which flag is active, you can identify the current child state within the parent.

Example with your Encoder:

Imagine the following scenario:

The HFSM starts in the "Incremental" parent state with "IncrementalStopped" child state active (initial state).

An "encoder started" event is received.

The "Moving" child state doesn't have a parent-specific transition, so you define it within the Moving state itself:

Moving -> IncrementalMoving (if current parent is Incremental) -> AbsoluteMoving (if current parent is Absolute) Since the current parent is "Incremental", the transition leads to the IncrementalMoving state.

Now, if you check the current state:

Using a state stack: The stack would show "IncrementalMoving". Using state flags: The IncrementalMoving flag would be active. This clarifies that the HFSM is in the "Incremental" parent state with the "Moving" child state specifically associated with the incremental mode.

By incorporating these refinements, you can effectively manage child states with multiple parent states in your HFSM, ensuring clear state identification and proper behavior.

jwellbelove commented 3 months ago

@pulkitpathak99 Thank you for those suggestions.