Skip to content

Commit 5188cf5

Browse files
authored
Add ROS 2 Yasmin State Machine guide to programming section (#228)
This PR adds a new wiki entry for the ROS 2 Yasmin State Machine framework and ensures project-wide consistency. Key changes: - New article: `wiki/programming/yasmin-ros2-state-machine.md`. - Updated `_data/navigation.yml` to include the new article in the sidebar. - Synchronized `wiki/programming/index.md`. - Fixed image paths and standardized internal links to follow project conventions. - Improved documentation quality by reformatting raw URLs and fixing broken external links.
1 parent 631b92b commit 5188cf5

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

_data/navigation.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ wiki:
229229
url: /wiki/programming/tutorials-resources/
230230
- title: Python Construct
231231
url: /wiki/programming/python-construct/
232+
- title: ROS 2 Yasmin State Machine
233+
url: /wiki/programming/yasmin-ros2-state-machine/
232234
- title: Networking
233235
url: /wiki/networking/
234236
children:
212 KB
Loading

wiki/programming/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ This section focuses on **programming techniques, tools, and libraries** commonl
3333
- **[Python Construct Library](/wiki/programming/python-construct/)**
3434
Explores the Python Construct library for building and parsing binary data. Highlights its utility for reliable serial communication in robotics systems. Includes examples of creating structured messages with CRC error-checking.
3535

36+
- **[ROS 2 Yasmin State Machine](/wiki/programming/yasmin-ros2-state-machine/)**
37+
A tutorial on using the Yasmin framework for state machine-based task logic in ROS 2. Covers core fundamentals, installation, and practical usage examples.
38+
3639
## Resources
3740

3841
### General Programming Resources
@@ -50,6 +53,8 @@ This section focuses on **programming techniques, tools, and libraries** commonl
5053
- [Pthreads Tutorial](https://computing.llnl.gov/tutorials/pthreads/)
5154
- [Python Construct GitHub](https://github.com/construct/construct)
5255
- [Protocol Wrappers for Python](http://eli.thegreenplace.net/2009/08/20/frames-and-protocols-for-the-serial-port-in-python)
56+
- [Yasmin Documentation (4.0.1)](https://uleroboticsgroup.github.io/yasmin/4.0.1/)
57+
- [Official Yasmin Repository](https://github.com/uleroboticsgroup/yasmin)
5358

5459
### Tutorials and Forums
5560
- [Learn Code the Hard Way](https://learncodethehardway.org/): Without a doubt, the best, most comprehensive tutorials for Python and C in existence.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
date: 2025-11-30
3+
title: ROS 2 Yasmin State Machine
4+
---
5+
Yasmin (Yet Another State MachINe) is a lightweight, Python finite state machine framework for ROS 2. It mirrors the SMACH pattern with `State`, `StateMachine`, and `Blackboard` classes, plus optional ROS logging hooks and a simple viewer. This entry outlines what Yasmin provides, how to install it, and how to use it to organize ROS 2 control logic. It also documents how we apply Yasmin to SNAAK, tying together manipulation actions, perception services, and stock tracking, and closes with a short comparison against behavior trees for similar tasks.
6+
7+
## Core Fundamentals of YASMIN
8+
YASMIN uses finite state machines to describe robot behavior: the robot is always in one well-defined state, that state does some work, then reports an outcome that selects the next state. This gives a clear, deterministic graph of behaviors and makes it easy to reason about and debug complex tasks.
9+
10+
### Finite State Machines (FSM)
11+
An FSM has a finite set of states and transitions between them. In robotics, each state corresponds to a concrete mode or action (for example, “Idle”, “Navigate”, “Grasp”), and transitions capture how the robot switches modes as inputs or sensor data change. YASMIN’s `StateMachine` class implements this pattern and handles running the active state, collecting its outcome, and jumping to the next state.
12+
13+
### Hierarchical Finite State Machines (HFSM)
14+
When the number of states grows, a flat FSM can become hard to manage. YASMIN addresses this with hierarchical FSMs, where a “state” can itself be another state machine. This lets you hide complex sub-behaviors (such as navigation or manipulation) behind a single high-level state and keep top-level graphs small and readable, while still reusing those sub-machines in other tasks.
15+
16+
### Key Components in YASMIN
17+
18+
#### State
19+
A state is the basic building block: it encapsulates one step of behavior. You create states by subclassing `State` and implementing `execute(blackboard)`, which reads and writes data on the blackboard and returns an outcome string indicating how it finished.
20+
21+
#### Outcomes
22+
Outcomes are short strings (for example, `"succeeded"`, `"failed"`, `"next_ingredient"`) that summarize how a state ended. They do not change behavior by themselves; instead, they drive transitions by telling the state machine which edge of the graph to follow next.
23+
24+
#### Transitions
25+
Transitions are the mapping from outcomes to next states. When you add a state to a `StateMachine`, you provide a dictionary like `{"succeeded": "NEXT_STATE", "failed": "FAIL"}`. This mapping encodes all branches, retries, and terminations and makes the control flow explicit.
26+
27+
#### Blackboard
28+
The blackboard is a shared dictionary that all states can read and write. It carries data such as poses, flags, and intermediate results between states. Remapping lets a reusable state use its own internal key names while you wire those to different blackboard keys when adding it to a particular machine.
29+
30+
#### State Machine Composition
31+
YASMIN encourages building larger behaviors by composing smaller state machines. Nested machines allow you to group related states into modules (for example, “NavigateToLocation” or “ExecuteRecipe”) and reuse them in different high-level workflows without duplicating logic.
32+
33+
#### Concurrency
34+
For tasks that should run in parallel (for example, monitoring sensors while executing a motion), YASMIN provides a `Concurrence` container. It runs multiple states concurrently, then resolves their individual outcomes into a single combined outcome according to a policy you choose.
35+
36+
## Installing Yasmin
37+
- ROS 2 binaries (when released for your distro): `sudo apt install ros-$ROS_DISTRO-yasmin ros-$ROS_DISTRO-yasmin-ros ros-$ROS_DISTRO-yasmin-viewer`
38+
(installs into the active ROS 2 environment)
39+
- Python/pip (for virtualenvs or non-DEB setups): `python3 -m pip install yasmin yasmin-ros yasmin-viewer`
40+
- From source: clone the Yasmin repositories into your ROS 2 workspace, run `rosdep install --from-paths src -y`, then `colcon build`.
41+
42+
## Minimal Usage Pattern
43+
```python
44+
import yasmin
45+
from yasmin import State, StateMachine
46+
47+
class Hello(State):
48+
def __init__(self):
49+
super().__init__(outcomes=["next"])
50+
def execute(self, blackboard):
51+
yasmin.YASMIN_LOG_INFO("Hello from Yasmin")
52+
blackboard["count"] = blackboard.get("count", 0) + 1
53+
return "next"
54+
55+
sm = StateMachine(outcomes=["done"])
56+
sm.add_state("HELLO", Hello(), transitions={"next": "done"})
57+
58+
result = sm() # runs until an outcome is returned
59+
```
60+
Create states by subclassing `State`, list valid outcomes in `super().__init__`, and register transitions when adding to the `StateMachine`. Use the `blackboard` dictionary to persist context across states. When running inside ROS 2, call `yasmin_ros.set_ros_loggers()` to bridge Yasmin logs to `rclpy` and `YasminViewerPub("<topic>", sm)` to visualize execution.
61+
62+
### Blackboard remapping example
63+
```python
64+
from yasmin import Blackboard, StateMachine
65+
from yasmin_ros import ServiceState
66+
from example_interfaces.srv import AddTwoInts
67+
68+
blackboard = Blackboard()
69+
blackboard["a"] = 2
70+
blackboard["b"] = 3
71+
72+
sm = StateMachine(outcomes=["done"])
73+
sm.add_state(
74+
"ADD",
75+
ServiceState(
76+
AddTwoInts, "/add_two_ints",
77+
create_request_handler=lambda bb: AddTwoInts.Request(a=bb["x"], b=bb["y"]),
78+
outcomes={"succeeded", "aborted"},
79+
),
80+
transitions={"succeeded": "done", "aborted": "done"},
81+
remappings={"x": "a", "y": "b"}, # map state-local keys to blackboard keys
82+
)
83+
sm()
84+
```
85+
Remapping keeps the state reusable: the `ServiceState` expects `x`/`y`, but the blackboard stores `a`/`b`.
86+
87+
### ROS helper states in practice
88+
```python
89+
from yasmin_ros import ActionState, MonitorState
90+
from example_interfaces.action import Fibonacci
91+
from std_msgs.msg import String
92+
93+
sm = StateMachine(outcomes=["done"])
94+
95+
sm.add_state(
96+
"RUN_ACTION",
97+
ActionState(
98+
Fibonacci, "/fibonacci",
99+
create_goal_handler=lambda bb: Fibonacci.Goal(order=bb.get("n", 5)),
100+
outcomes={"succeeded", "aborted", "canceled"},
101+
result_handler=lambda bb, res: bb.update({"seq": list(res.sequence)})
102+
),
103+
transitions={"succeeded": "MONITOR", "aborted": "done", "canceled": "done"},
104+
)
105+
106+
sm.add_state(
107+
"MONITOR",
108+
MonitorState(
109+
String, "/topic",
110+
outcomes={"valid", "invalid"},
111+
monitor_handler=lambda bb, msg: "valid" if msg.data else "invalid",
112+
),
113+
transitions={"valid": "done", "invalid": "done"},
114+
)
115+
sm()
116+
```
117+
`ActionState` handles goal send/feedback/result (with optional timeout/retry); `MonitorState` consumes topic data and returns an outcome that drives the next transition.
118+
119+
## How We Use Yasmin for SNAAK
120+
121+
- State graph: `ReadStock → Home → Recipe → PreGrasp → Pickup → PrePlace → Place`, with side paths for `BreadLocalization`, `Restock`, and `Fail`.
122+
- Shared context: the blackboard holds `stock` and `recipe` dictionaries loaded from YAML, the current ingredient, gripper setup, assembly coordinates, running weight/vision feedback, retry counters, and a `SandwichLogger` for traceability.
123+
- Action/service integration: states call manipulation actions (`ReturnHome`, `ExecuteTrajectory`, `Pickup`, `Place`), vision services (`GetXYZFromImage`, `CheckIngredientPlace`), shredded grasp planning, and weight sensors. `send_goal` centralizes action handling.
124+
- Flow of Code: `PreGrasp` chooses the next ingredient and moves to its bin; `Pickup` retries vision-guided grasps with weight verification; `PrePlace` moves to the assembly tray; `Place` drops the item, checks weight/vision tolerance, updates recipe progress, and triggers `BreadLocalization` after the bottom slice; `Fail` and `Restock` safely persist stock and pause the robot.
125+
- Visualization: `YasminViewerPub("yasmin_snaak", sm)` publishes the state machine so operators can inspect progress live. The visualization of our system is shown below
126+
127+
128+
![Yasmin state machine](/assets/images/robotics_project_guide/state_machine.png)
129+
130+
131+
## Yasmin vs. Behavior Trees
132+
- Pros: very small API; explicit transition tables make debugging straightforward; blackboard simplifies sharing perception/action results; viewer gives immediate observability; close to SMACH for teams migrating from ROS 1.
133+
- Cons: less expressive than behavior trees for concurrent or fallback logic; transitions can grow unwieldy in large graphs compared to BT compositional nodes; no built-in tick-rate control or decorators like throttling; requires disciplined state design to avoid large monolithic `execute` blocks.
134+
- When to choose Yasmin: linear or mildly branching task flows (pick–place sequences, setup/teardown) where clarity and low overhead are priorities. Use behavior trees when you need richer composition, better low level control, or parallel behavior.
135+
136+
## Summary
137+
Yasmin brings a clear, ROS 2–native state machine to structure task logic with minimal boilerplate. Define outcomes, wire transitions, and keep run-time data on the blackboard. In our sandwich-assembly robot it ties together perception, manipulation, and inventory tracking while remaining easy to visualize. Reach for behavior trees when you need more complex composition; otherwise Yasmin offers a simple, readable backbone for many manipulation workflows.
138+
139+
## See Also:
140+
- [ROS 2 Navigation for Clearpath Husky](/wiki/common-platforms/ros2-navigation-for-clearpath-husky/)
141+
- [ROS Motion Server Framework](/wiki/common-platforms/ros/ros-motion-server-framework/)
142+
143+
## Further Reading
144+
- [Yasmin documentation (4.0.1)](https://uleroboticsgroup.github.io/yasmin/4.0.1/)
145+
- [Yasmin source and documentation (official repository)](https://github.com/uleroboticsgroup/yasmin)
146+
- [ROS 2 action design guide](https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html)
147+
- [ROS 2 service design guide](https://docs.ros.org/en/humble/Tutorials/Intermediate/Writing-an-Action-Server-Client/Py.html)
148+
- [Behavior tree tutorials for ROS 2](https://docs.nav2.org/behavior_trees/index.html)
149+
150+
## References
151+
- Include project-specific reports or papers here.

0 commit comments

Comments
 (0)