Repository navigation
02. State Machine
The application controls the robot through a configurable finite-state machine (FSM). Each state encapsulates a specific robot behavior, while transitions determine how the robot reacts to signals generated by the active state itself. The complete workflow is defined in a YAML configuration file.
Once the application is installed, run the command
bin\executorbin\runnit org.mmarini.wheelly.apps.RobotExecutorAvailable options:
usage: org.mmarini.wheelly.apps.RobotExecutor
[-h] [-v] [-c CONFIG] [-s] [-t LOCALTIME] [-d DUMP]
Run a session of interaction between robot and environment.
named arguments:
-h, --help show this help message and exit
-v, --version show current version
-c CONFIG, --config CONFIG
specify yaml configuration file (default:
executor.yml)
-s, --silent specify silent closing (no window messages)
(default: false)
-t LOCALTIME, --localTime LOCALTIME
specify number of seconds of session duration
(default: 43200)
-d DUMP, --dump DUMP specify dump signal fileThe FSM is defined in YAML and consists of:
- States
- Transitions
- Entry state
Transitions are defined by:
- source state
- target state
- trigger (regex matching emitted signals)
- optional onTransition commands
Example
---
######################################
# Idle agent
######################################
$schema: https://mmarini.org/wheelly/agent-state-machine-schema-0.4
class: org.mmarini.wheelly.engines.StateMachineAgent
flow:
entry: idle
states:
idle:
$id: https://mmarini.org/wheelly/state-halt-schema-0.1
class: org.mmarini.wheelly.engines.HaltState
scanInterval: 1000
minSensorDir: -90
maxSensorDir: 90
sensorDirNumber: 9
transitions:
".*Blocked":
to: avoid
avoid:
$id: https://mmarini.org/wheelly/state-avoid-schema-0.1
class: org.mmarini.wheelly.engines.AvoidingState
safeDistance: 0.1
transitions:
completed:
to: idleWhen a state becomes active:
-
onEntrycommands execute - State runs and emits signals
- Transitions may trigger,
onTransitioncommands are executed -
onExitcommands execute before leaving
A signal is a string emitted by a state and consumed by transition regex matching.
State → emit signal → transition regex match → onTransition → next state
States are initialized only once at startup.
Each state exposes:
-
<state-id>.entryTime: the time when the state was entered.
Moves away from obstacles.
Signals:
-
timeout: has elapsed since state entry. -
completed: the robot is no longer in contact with obstacles and has reached a safe distance from them. -
blocked: the robot cannot move in any direction.
Parameters:
-
timeout: timeout interval (ms) -
safeDistance: the safe distance from obstacle (m) -
speed: the escaping speed (pps)
Variables:
-
<state-id>.frontContact: true if the contact occurred at the front of the robot -
<state-id>.contactPoint: the robot position when contact occurred -
<state-id>.contactDirection: the robot direction at contact point (DEG) -
<state-id>.safePoint: the safety point to move towards
The clear radar map state org.mmarini.wheelly.engines.ClearMapState clears the radar map.
Signals:
-
completed: the radar map has been cleared.
Parameters:
This state has no parameters.
The exploring point state org.mmarini.wheelly.engines.ExploringPointState selects the free-cell point in the radar map that is furthest from the robot, provided it is beyond the safety distance and within the maximum reachable distance.
Signals:
-
timeout: has elapsed since state entry. -
completed: a suitable target point has been found. -
notFound: no suitable point is found.
Parameters:
-
timeout: timeout interval (ms) -
maxDistance: the maximum distance of the point from the robot (m) -
safeDistance: the safe distance (m)
Variables:
-
<state-id>.target: the target point in the unexplored area
All search states use the A*-RRT (A* Rapidly-exploring Random Tree) algorithm and expose the same output variable (path). They differ only in how the search target is selected.
Signals:
-
completed: the path is found. -
notFound: no path is found.
Common parameters:
-
growthDistance: maximum distance by which the search tree can expand at each iteration (m) default 0.5 m -
seed: the seed of random number generator default 0 -
maxIterations: the number of maximum iterations growing tree default maximum integer -
minGoals: the number of minimum goals to find default 1 -
maxSearchTime: the maximum searching time (ms) default 1h
Variables:
-
<state-id>.path: the sequence of points leading to the goal
Typically, when the completed signal is generated, the transition copies the computed path from the search state to a MovePathState instance:
transitions:
completed:
to: {moveState}
onTransition:
- {moveState}.path
- {searchState}.path
- get
- putThe label path search state org.mmarini.wheelly.engines.SearchLabelState selects the path to a label location.
Specific parameter is:
-
distance: the maximum distance of the goal location from the label location (m)
The unknown sector path search state org.mmarini.wheelly.engines.SearchUnknownState selects the path to an unknown map sector.
The refresh sector path search state org.mmarini.wheelly.engines.SearchRefreshState selects a path to a sector whose radar information is the oldest. This state is used to refresh outdated regions of the radar map.
The halt state org.mmarini.wheelly.engines.HaltState stops the robot and can automatically move the scanner.
Signals:
-
timeout: has elapsed since state entry. -
frontBlocked: the robot has front obstacle contact. -
rearBlocked: the robot has rear obstacle contact. -
blocked: the robot has both front and rear obstacle contacts.
Parameters:
-
timeout: timeout interval (ms) -
scanInterval: interval between scanner sensor movement (ms) -
minSensorDir: minimum scanner direction (DEG) -
maxSensorDir: maximum scanner direction (DEG) -
sensorDirNumber: number of directions to scan
Variables:
-
<state-id>.scanTime: the last scanner time -
<state-id>.scanIndex: the next scan index [0 ... (sensorDirNumber - 1) * 2]
The label-tracking state org.mmarini.wheelly.engines.LabelStuckState maintains the robot at a fixed distance from the label location.
The robot moves backward and forward to keep the distance from the label.
Signals:
-
timeout: has elapsed since state entry. -
notFound: no label is found in the given distance range. -
frontBlocked: the robot has front obstacle contact. -
rearBlocked: the robot has rear obstacle contact. -
blocked: the robot cannot move anywhere.
Parameters:
-
timeout: timeout interval (ms) -
distance: the distance from label (m) default 0.8 m -
speed: the maximum moving speed (pps) default 30 pps
The path-following state org.mmarini.wheelly.engines.MovePathState moves the robot along the specified path.
The robot moves at the given speed and gradually decelerates to minimum speed of 10 pps when it reaches 0.4 m from the path points.
Signals:
-
timeout: has elapsed since state entry. -
completed: the robot reaches the target. -
frontBlocked: the robot has front obstacle contact. -
rearBlocked: the robot has rear obstacle contact. -
blocked: the robot cannot move anywhere.
Parameters:
-
timeout: timeout interval (ms) -
approachDistance: the distance from path point to change the point (m) default 0.5 -
speed: the maximum moving speed (pps) default 60 pps
Variables:
-
<state-id>.target: the target location -
<state-id>.path: the path to follow
The move-to state org.mmarini.wheelly.engines.MoveToState moves the robot to a target location.
The robot moves at the maximum speed and gradually decelerates to a minimum speed of 10 pps as it approaches the target, starting when it is within 0.4 m of the stopping distance.
Signals:
-
timeout: has elapsed since state entry. -
completed: the robot reaches the target. -
frontBlocked: the robot has front obstacle contact. -
rearBlocked: the robot has rear obstacle contact. -
blocked: the robot cannot move anywhere.
Parameters:
-
timeout: timeout interval (ms) -
stopDistance: the distance from target to stop the robot (m) -
maxSpeed: the maximum moving speed (pps) -
x: the abscissa of target point -
y: the ordinate of target point
Variables:
-
<state-id>.target: the target location
Commands are evaluated as a stack-based language using Reverse Polish Notation (RPN). Each token is interpreted either as an operator or as a literal number value pushed onto the evaluation stack. Numeric tokens are parsed as numbers; all other tokens are treated as strings.
Available operators:
-
add: adds the top two operands on the stackop(n-1) + op(n) -
sub: subtracts the top two operands on the stackop(n-1) - op(n) -
mul: multiplies the top two operands on the stackop(n-1) * op(n) -
div: divides the second-to-top operand by the top operandop(n-1) / op(n) -
neg: negates the top operand on the stack-op(n) -
get: retrieves a value from the key-value mapmap.get(key=op(n)) -
put: stores a value in the key-value mapmap.put(key=op(n-1), value=op(n)) -
swap: swaps the top two operands on the stack -
time: pushes the current time value (ms) onto the stack
Any unrecognized token is treated as a literal string and pushed onto the evaluation stack.
Example:
Store the value 3 (= 1 + 2) in the key-value map under the key aKey:
onInit:
- aKey
- 1
- 2
- add
- putRelease 0.26.0