ROS Parameters Demo (Python)
This tutorial shows how to use ROS 2 parameters within a YASMIN state
machine using the GetParametersState. Parameters allow
you to configure your state machine behavior at runtime without
modifying code. This is essential for creating flexible, reusable
robot behaviors that can be adapted to different scenarios, robots, or
environments simply by changing parameter values. Instead of
hardcoding values like loop counts, thresholds, or names, you can
expose them as parameters that can be set via launch files,
command-line arguments, or parameter files.
Background
ROS 2 parameters provide a way to:
- Configure node behavior at launch time (set values before execution)
- Dynamically reconfigure settings (change values during execution)
- Share configuration across nodes (maintain consistency)
- Set defaults with command-line overrides (flexible deployment)
- Document configurable aspects of your system (self-documenting code)
- Version control configuration separately from code (cleaner repositories)
1. Create Custom States
Define states that use parameters from the blackboard. Notice how
FooState retrieves max_counter and
counter_str from the blackboard instead of using
hardcoded values. This makes the state's behavior configurable - you
can change how many iterations it performs or what prefix it uses in
log messages without modifying the state's code. The same state class
can be used in different state machines with different parameter
values, promoting reusability. BarState simply logs the formatted
string, demonstrating how parameter-driven data flows through the
state machine naturally.
class FooState(State):
"""
Represents the Foo state in the state machine.
Attributes:
counter (int): Counter to track the number of executions of this state.
"""
def __init__(self) -> None:
"""
Initializes the FooState instance, setting up the outcomes.
Outcomes:
outcome1: Indicates the state should continue to the Bar state.
outcome2: Indicates the state should finish execution and return.
"""
super().__init__(["outcome1", "outcome2"])
self.counter = 0
def execute(self, blackboard: Blackboard) -> str:
"""
Executes the logic for the Foo state.
Args:
blackboard (Blackboard): The shared data structure for states.
Returns:
str: The outcome of the execution, which can be "outcome1" or "outcome2".
Raises:
Exception: May raise exceptions related to state execution.
"""
yasmin.YASMIN_LOG_INFO("Executing state FOO")
time.sleep(3) # Simulate work by sleeping
if self.counter < blackboard["max_counter"]:
self.counter += 1
blackboard["foo_str"] = f"{blackboard['counter_str']}: {self.counter}"
return "outcome1"
else:
return "outcome2"
class BarState(State):
"""
Represents the Bar state in the state machine.
"""
def __init__(self) -> None:
"""
Initializes the BarState instance, setting up the outcome.
Outcomes:
outcome3: Indicates the state should transition back to the Foo state.
"""
super().__init__(outcomes=["outcome3"])
def execute(self, blackboard: Blackboard) -> str:
"""
Executes the logic for the Bar state.
Args:
blackboard (Blackboard): The shared data structure for states.
Returns:
str: The outcome of the execution, which will always be "outcome3".
Raises:
Exception: May raise exceptions related to state execution.
"""
yasmin.YASMIN_LOG_INFO("Executing state BAR")
time.sleep(3) # Simulate work by sleeping
yasmin.YASMIN_LOG_INFO(blackboard["foo_str"])
return "outcome3"
2. Use GetParametersState
Create a state that retrieves ROS parameters and stores them in the
blackboard. The GetParametersState is initialized with a
dictionary mapping parameter names to default values. When executed,
it attempts to retrieve each parameter from the ROS 2 parameter
server. If a parameter is set (via command line with
--ros-args -p max_counter:=5, in a YAML file, or
programmatically), it uses that value. If not found, it falls back to
the default value provided in the dictionary. All retrieved parameters
are then stored in the blackboard, making them available to subsequent
states. This pattern - retrieve configuration before execution -
ensures your state machine is properly configured before running and
provides clear error handling if required parameters are missing.
from yasmin_ros import GetParametersState
from yasmin_ros.basic_outcomes import SUCCEED, ABORT
rclpy.init()
set_ros_loggers()
sm = StateMachine(outcomes=["outcome4"])
# Add parameter getter as first state
sm.add_state(
"GETTING_PARAMETERS",
GetParametersState(
parameters={
"max_counter": 3, # Parameter name with default value
"counter_str": "Counter", # Another parameter with default
},
),
transitions={
SUCCEED: "FOO",
ABORT: "outcome4",
},
)
3. Build the Rest of the FSM
Add the FooState and BarState to complete the state machine. These states use the parameters retrieved by the GetParametersState to control their behavior dynamically.
sm.add_state(
"FOO",
FooState(),
transitions={
"outcome1": "BAR",
"outcome2": "outcome4",
},
)
sm.add_state(
"BAR",
BarState(),
transitions={"outcome3": "FOO"},
)
YasminViewerPub(sm, "YASMIN_PARAMETERS_DEMO")
4. Execute
Run the state machine and handle any interruptions gracefully with proper ROS shutdown procedures.
# Publish FSM information for visualization
viewer = YasminViewerPub(sm, "YASMIN_PARAMETERS_DEMO")
# Execute the FSM
try:
outcome = sm()
yasmin.YASMIN_LOG_INFO(outcome)
except KeyboardInterrupt:
if sm.is_running():
sm.cancel_state()
finally:
viewer.cleanup()
del sm
# Shutdown ROS 2 if it's running
if rclpy.ok():
rclpy.shutdown()
if __name__ == "__main__":
main()
5. Run with Default Parameters
Run the demo using the default parameter values defined in the code.
ros2 run yasmin_demos parameters_demo.py
This will use the defaults: max_counter=3 and
counter_str="Counter".
6. Run with Custom Parameters
Override the default parameter values at runtime using ROS 2 command-line arguments to customize the state machine behavior:
ros2 run yasmin_demos parameters_demo.py --ros-args -p max_counter:=5 -p counter_str:="Iteration"
Expected Behavior
-
The FSM retrieves
max_counterandcounter_strfrom ROS parameters -
FooState loops until the counter reaches
max_counter -
BarState prints the formatted counter string using
counter_str
Key Points
-
Parameters are retrieved once at the start by
GetParametersState - Parameters are stored in the blackboard with the same key names
- Default values are used if parameters are not set
-
Returns
SUCCEEDif all parameters are retrieved,ABORTotherwise
YASMIN