Lifecycle coordination layer for ROS 2 node in the BotBot stack.
bot_state_machine keeps the platform’s lifecycle nodes synchronized: it parses the node graph, applies configure/activate/deactivate transitions in the proper order, exposes a high-level command service, monitors transition events, and automatically falls back between autonomous and teleop modes when navigation nodes misbehave.
This package glues the rest of the system together by:
- Coordinated Bringup/Shutdown – Drives every node through the ROS 2 lifecycle in dependency order (CORE → NAVIGATION → accessories, etc.).
- Dependency Management – Recursively validates dependencies/dependents and ensures PAYLOAD class nodes are never toggled automatically.
- Event Monitoring – Subscribes to lifecycle transition events and reacts to unexpected UNCONFIGURED/ACTIVE changes.
- Command Interface – Offers a
StateMachineservice to trigger activation, deactivation, or restart for any managed node. - Status Aggregation – Publishes
bot_custom_interfaces/msg/StatusArraywith the lifecycle state, priority, and health of every node. - Mode Arbitration – Maintains BRINGUP / AUTONOMOUS / TELEOP / BRINGDOWN / RESTARTING states, switching modes based on navigation health.
- Loads JSON node descriptions (per class) and converts them into
NodeProfileentries. - Creates lifecycle clients (
/get_state,/change_state) for every managed node. - Publishes
StatusArrayand exposesbot_custom_interfaces/srv/StateMachine. - Routes lifecycle transition events to the controller and clears stale events.
- Periodically invokes
update_callback,publish_callback, andevent_callback.
Finite-state machine:
- States:
BRINGUP,AUTONOMOUS,TELEOP,BRINGDOWN,IDLE,ERROR,RESTARTING. - Performs dependency checks, activation/deactivation, and restart logic.
- Maintains event queues, protected node sets, and command processing.
- Handles navigation fallbacks: if any NAVIGATION node fails activation, all NAV nodes are deactivated and the controller transitions to TELEOP.
- Lightweight helper that parses the class-specific JSON manifests.
- Converts entries into
NodeProfileobjects and builds dependency/dependent lists. - Sorts nodes by class and priority to guarantee deterministic bringup/bringdown ordering.
| File | Description |
|---|---|
core.json |
Core services (Docker, web socket, etc.) |
navigation.json |
Nav2 stack, localization, planners |
camera.json |
RealSense / perception nodes |
audio.json |
Voice pipeline |
accessories.json |
Miscellaneous utilities |
ia_stack.json |
AI/ML components |
payload.json |
Third-party payloads that the controller only monitors |
Each JSON entry contains the node name, display name, class, startup order, description, and dependency list.
| State | Description |
|---|---|
BRINGUP |
Sequentially configure and activate nodes based on class/order. |
AUTONOMOUS |
Navigation nodes are active; events may trigger restarts. |
TELEOP |
Navigation failed; system remains operational minus autonomous stack. |
BRINGDOWN |
Reverse-order deactivation & cleanup. |
IDLE |
All nodes inactive, waiting for next bringup. |
ERROR |
Bringdown encountered an unrecoverable failure. |
RESTARTING |
Controller is forcing a bringdown followed by bringup. |
| Input | Description |
|---|---|
robot_config.yaml (workspace root) |
Provides robot_configuration.robot_name used as the namespace prefix. |
config/ directory |
Passed through the nodes_json_path parameter. |
The launch file:
- Reads
robot_config.yamlto determine the namespace (e.g.,g1_robot/). - Starts the
state_machine_nodelifecycle node. - After the process appears, emits a
configuretransition. - When the node reaches
inactive, automatically emitsactivate.
# From the workspace root
source install/setup.bash
ros2 launch bot_state_machine state_machine.launch.py# List lifecycle states for a managed node
ros2 lifecycle get /<ns>/<node_name>
# Manually request a transition (advanced usage)
ros2 lifecycle set /<ns>/<node_name> deactivate# Restart a navigation node
ros2 service call /<ns>/state_machine bot_custom_interfaces/srv/StateMachine \
"{node: 'nav2_bt_navigator', command: 3}"/<ns>/state_machine/status publishes bot_custom_interfaces/msg/StatusArray containing the lifecycle state, priority, class, and diagnostic message for each node. Use ros2 topic echo or plug it into dashboards.
- Declare Nodes – Update the JSON file that matches the node’s class (e.g.,
navigation.json). - Set Dependencies – Add
dependencies(nodes that must be active before this node) anddependents_of(nodes that rely on this node for teardown ordering). - Assign Priority & Order –
priorityimpacts status reporting and UI ordering;ordercontrols startup order inside each class. - Deploy – Rebuild the workspace or redeploy containers; no code changes required.
The controller automatically reloads definitions on configure.
bot_state_machine/
├── include/
│ ├── lifecycle_manager.hpp # Lifecycle node orchestrator
│ ├── state_controller.hpp # FSM controller declaration
│ ├── graph_node.hpp # Helpers for parsing JSON node graphs
│ └── types.hpp # Shared enums, structs, and timeouts
├── src/
│ ├── state_controller.cpp # Bringup/bringdown logic + event manager
│ ├── lifecycle_manager.cpp # LifecycleNode implementation
│ └── state_machine_node.cpp # Main executable
├── config/ # JSON node graph grouped by class
├── launch/
│ └── state_machine.launch.py # Lifecycle launch + auto configure/activate
├── CMakeLists.txt / package.xml # ROS 2 build metadata
└── README.md # This document
# Start the state machine under a specific namespace (from robot_config.yaml)
ros2 launch bot_state_machine state_machine.launch.py
# Monitor status output
ros2 topic echo /g1_robot/state_machine/status
# Force a full restart (through the service API)
ros2 service call /g1_robot/state_machine bot_custom_interfaces/srv/StateMachine \
"{node: 'state_machine', command: 3}"Made with ❤️ in Brazil