Skip to content

02. State Machine

Marco Marini edited this page Jun 26, 2026 · 2 revisions

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.


Run

Once the application is installed, run the command

bin\executor

Java application

bin\runnit org.mmarini.wheelly.apps.RobotExecutor

Available 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 file

State machine agent

The 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: idle

State lifecycle

When a state becomes active:

  • onEntry commands execute
  • State runs and emits signals
  • Transitions may trigger, onTransition commands are executed
  • onExit commands 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.

State Reference

AvoidingState

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

ClearMapState

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.


ExploringPointState

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

Search States

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
            - put

SearchLabelState

The 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)

SearchUnknownState

The unknown sector path search state org.mmarini.wheelly.engines.SearchUnknownState selects the path to an unknown map sector.


SearchRefreshState

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.


HaltState

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]

LabelStuckState

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

MovePathState

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

MoveToState

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

Command specification

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 stack op(n-1) + op(n)
  • sub: subtracts the top two operands on the stack op(n-1) - op(n)
  • mul: multiplies the top two operands on the stack op(n-1) * op(n)
  • div: divides the second-to-top operand by the top operand op(n-1) / op(n)
  • neg: negates the top operand on the stack -op(n)
  • get: retrieves a value from the key-value map map.get(key=op(n))
  • put: stores a value in the key-value map map.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
  - put

Release 0.26.0

Clone this wiki locally