Skip to content

Commit e1b8610

Browse files
authored
Merge pull request #72 from robotpy/fsm-docs
Update StateMachine documentation
2 parents 15a90fe + 20b8d1d commit e1b8610

File tree

1 file changed

+48
-20
lines changed

1 file changed

+48
-20
lines changed

magicbot/state_machine.py

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,23 @@ def default_state(f=None):
192192

193193
class StateMachine(metaclass=OrderedClass):
194194
'''
195-
This object is designed to be used to easily implement magicbot
196-
components that are basically a big state machine.
195+
The StateMachine class is used to implement magicbot components that
196+
allow one to easily define a `finite state machine (FSM)
197+
<https://en.wikipedia.org/wiki/Finite-state_machine>`_ that can be
198+
executed via the magicbot framework.
197199
198-
You use this by defining a class that inherits from ``StateMachine``.
199-
To define each state, you use the :func:`timed_state` decorator on a
200-
function. When each state is run, the decorated function will be
201-
called. Decorated state functions can receive the following
202-
parameters:
200+
You create a component class that inherits from ``StateMachine``.
201+
Each state is represented as a single function, and you indicate that
202+
a function is a particular state by decorating it with one of the
203+
following decorators:
204+
205+
* :func:`@default_state <.default_state>`
206+
* :func:`@state <.state>`
207+
* :func:`@timed_state <.timed_state>`
208+
209+
As the state machine executes, the decorated function representing the
210+
current state will be called. Decorated state functions can receive the
211+
following parameters (all of which are optional):
203212
204213
- ``tm`` - The number of seconds since autonomous has started
205214
- ``state_tm`` - The number of seconds since this state has been active
@@ -209,20 +218,30 @@ class StateMachine(metaclass=OrderedClass):
209218
will be set to True at the start of each state.
210219
211220
To be consistent with the magicbot philosophy, in order for the
212-
state machine to execute its states you must call the
213-
:func:`engage` function upon each execution of the main
214-
robot control loop. If you do not call this function, then
215-
execution will cease unless the current executing state is
216-
marked as ``must_finish``.
221+
state machine to execute its states you must call the :func:`engage`
222+
function upon each execution of the main robot control loop. If you do
223+
not call this function, then execution of the FSM will cease.
224+
225+
.. note:: If you wish for the FSM to continue executing state functions
226+
regardless whether ``engage()`` is called, you must set the
227+
``must_finish`` parameter in your state decorator to be True.
217228
218-
When execution ceases, the :func:`done` function will be called
219-
unless execution was stopped by calling the ``done`` function.
229+
When execution ceases (because ``engage()`` was not called), the
230+
:func:`done` function will be called and the FSM will be reset to the
231+
starting state. The state functions will not be called again unless
232+
``engage`` is called.
220233
221-
As a magicbot component, this contains an ``execute`` function that
234+
As a magicbot component, StateMachine contains an ``execute`` function that
222235
will be called on each control loop. All state execution occurs from
223-
within that function call. If you call other components from this
224-
component, you should ensure that your component occurs *before*
225-
the other components in your Robot class.
236+
within that function call. If you call other components from a
237+
StateMachine component, you should ensure that your component is defined
238+
*before* the other components in your Robot class.
239+
240+
.. warning:: As StateMachine already contains an execute function,
241+
there is no need to define your own ``execute`` function for
242+
a state machine component -- if you override ``execute``,
243+
then the state machine may not work correctly. Instead,
244+
use the :func:`@default_state <.default_state>` decorator.
226245
227246
Here's a very simple example of how you might implement a shooter
228247
automation component that moves a ball into a shooter when the
@@ -240,16 +259,25 @@ def fire(self):
240259
241260
@state(first=True)
242261
def begin_firing(self):
262+
"""This function will only be called IFF fire is called and
263+
the FSM isn't currently in the 'firing' state. If fire
264+
was not called, this function will not execute."""
243265
self.shooter.enable()
244266
if self.shooter.ready():
245267
self.next_state('firing')
246268
247269
@timed_state(duration=1.0, must_finish=True)
248270
def firing(self):
249-
"""This state will continue executing even if engage isn't called"""
271+
"""Because must_finish=True, once the FSM has reached this
272+
state, this state will continue executing even if engage
273+
isn't called"""
250274
self.shooter.enable()
251275
self.ball_pusher.push()
252-
276+
277+
#
278+
# Note that there is no execute function defined as part of
279+
# this component
280+
#
253281
...
254282
255283
class MyRobot(magicbot.MagicRobot):

0 commit comments

Comments
 (0)