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
CbDefaultKeyboardBehaviorinOrKeyboardis declared inMsRunning::staticConfigure().Leaf states (
StPhaseA/B/C,StPhaseX/Y) have onlyCbTimerCountdownOnce— no keyboard behavior.EvKeyPressNreactions in leaf states fire in response to events generated byMsRunning’s behavior — the event source and the reacting state are at different hierarchy levels.EvKeyPressFreactions inSsPhase1/SsPhase2switch 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 |
|---|---|---|
|
Advance to the next leaf state within the current superstate |
Leaf state reaction (event from MsRunning’s behavior) |
|
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.