README

sm_mode_state_behavior_1

Demonstrates a client behavior defined at the mode state level, persisting across all inner superstate and leaf state transitions. The key insight: a behavior (here, CbDefaultKeyboardBehavior) owned by a parent state is created once when that parent enters and destroyed only when that parent exits — it survives every inner transition.

This machine also illustrates the correct solution to the double-event problem: if leaf states each had their own CbDefaultKeyboardBehavior, every keypress would generate two identical events (one per active behavior instance). By placing keyboard behavior exclusively in MsRunning, every keypress generates exactly one event regardless of which inner state is active.

What it demonstrates

  • CbDefaultKeyboardBehavior in OrKeyboard is declared in MsRunning::staticConfigure().

  • Leaf states (StPhaseA/B/C, StPhaseX/Y) have only CbTimerCountdownOnce — no keyboard behavior.

  • EvKeyPressN reactions in leaf states fire in response to events generated by MsRunning’s behavior — the event source and the reacting state are at different hierarchy levels.

  • EvKeyPressF reactions in SsPhase1/SsPhase2 switch between superstates; MsRunning’s keyboard behavior remains active throughout.

State hierarchy

SmModeStateBehavior1
├── OrTimer    (ClRos2Timer)
└── OrKeyboard (ClKeyboard)

MsRunning  ←  mode state; owns CbDefaultKeyboardBehavior in OrKeyboard
│              (keyboard behavior persists for the entire machine lifetime)
│
├── SsPhase1  (initial superstate)
│   │  Reacts: EvKeyPressF → SsPhase2
│   │
│   ├── StPhaseA  (initial)  3s timer
│   ├── StPhaseB             3s timer
│   └── StPhaseC             3s timer
│       (A → B → C → A cycle via timer or 'n')
│
└── SsPhase2
    │  Reacts: EvKeyPressF → SsPhase1
    │
    ├── StPhaseX  (initial)  5s timer
    └── StPhaseY             5s timer
        (X → Y → X cycle via timer or 'n')

Build

cd /home/brettpac/workspaces/isaac_ros-dev
colcon build --packages-select sm_mode_state_behavior_1
source install/setup.bash

Launch

ros2 launch sm_mode_state_behavior_1 sm_mode_state_behavior_1.launch.py

This opens two konsole terminals: the state machine node and the keyboard server.

Keyboard controls

Key

Effect

Handled by

n

Advance to the next leaf state within the current superstate

Leaf state reaction (event from MsRunning’s behavior)

f

Switch between SsPhase1 and SsPhase2

SsPhase1 or SsPhase2 reaction (event from MsRunning’s behavior)

(timer)

Auto-advance to next leaf state (3s in Phase1, 5s in Phase2)

Leaf state reaction

Send keystrokes via ROS 2 topic (if not using the konsole keyboard server):

ros2 topic pub /keyboard_unicode std_msgs/msg/UInt16 "data: 110" --once  # n  — next leaf state
ros2 topic pub /keyboard_unicode std_msgs/msg/UInt16 "data: 102" --once  # f  — switch superstate

Example walkthroughs

Manual leaf state cycling in SsPhase1

Start → MsRunning/SsPhase1/StPhaseA
  → press n → StPhaseB
  → press n → StPhaseC
  → press n → StPhaseA   (back to start of cycle)

Switch to SsPhase2 and cycle there

(in SsPhase1/StPhaseB)
  → press f → SsPhase2/StPhaseX   (SsPhase2 always re-enters at StPhaseX)
  → press n → StPhaseY
  → press n → StPhaseX

Switch back to SsPhase1

(in SsPhase2/StPhaseY)
  → press f → SsPhase1/StPhaseA   (SsPhase1 always re-enters at StPhaseA)

Observe keyboard behavior persistence

In the node console, [MsRunning] Entered appears once at startup. It does not re-appear when f is pressed or when leaf states advance — confirming the keyboard behavior is not recreated on inner transitions.

Monitoring

# Current state hierarchy
ros2 topic echo /sm_mode_state_behavior_1/smacc/status

# State transitions as they fire
ros2 topic echo /sm_mode_state_behavior_1/smacc/transition_log

Look for [MsRunning] Entered appearing only once in the console — and [SsPhase1] Exiting / [SsPhase2] Entered (or vice versa) each time f is pressed. The keyboard behavior spanning all of these transitions without restarting is the key demonstration.