Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example of chaining autonomous modes together #15

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add example of chaining autonomous modes together
virtuald committed Feb 9, 2016
commit 861fcdb202e32710492a3e8dd029daa38549bf1b
2 changes: 1 addition & 1 deletion robotpy_ext/autonomous/__init__.py
Original file line number Diff line number Diff line change
@@ -3,4 +3,4 @@
from .selector import AutonomousModeSelector

# Autonomous mode state machine
from .stateful_autonomous import state, timed_state, StatefulAutonomous
from .stateful_autonomous import state, state_alias, timed_state, StatefulAutonomous
56 changes: 55 additions & 1 deletion robotpy_ext/autonomous/stateful_autonomous.py
Original file line number Diff line number Diff line change
@@ -138,6 +138,39 @@ def state(f=None, first=False):
return _create_wrapper(f, first)


class state_alias:
'''
Not a decorator, used to alias a state so it can be referred to as
a different name::
class MyAuto(StatefulAutonomous):
@state()
def something(self):
pass
something_else = state_alias(something)
It can be used to set a state as first too (useful in derived classes)::
class MyAuto(StatefulAutonomous):
@state()
def something(self):
pass
class MyDerivedAuto(MyAuto):
something_else = state_alias(something, first=True)
'''

def __init__(self, state_fn, first=False):
self.first = first
self.aliased = state_fn

def __getattr__(self, name):
return getattr(self.aliased, name)

class StatefulAutonomous:
'''
@@ -306,6 +339,10 @@ def __build_states(self):
state = getattr(self.__class__, name)
if name.startswith('__') or not hasattr(state, 'first'):
continue

if isinstance(state, state_alias):
setattr(self, name, state.aliased)
name = state.aliased.name

# is this the first state to execute?
if state.first:
@@ -314,6 +351,9 @@ def __build_states(self):

self.__first = name
has_first = True

if isinstance(state, state_alias):
continue

# problem: how do we expire old entries?
# -> what if we just use json? more flexible, but then we can't tune it
@@ -407,9 +447,12 @@ def done(self):
self.next_state(None)

def next_state(self, name):
'''Call this function to transition to the next state
'''Call this function to transition to the next state.
:param name: Name of the state to transition to
.. note:: The state function will not be called immediately, it will
be called on the next iteration of the control loop.
'''
if name is not None:
self.__state = getattr(self.__class__, name)
@@ -420,12 +463,23 @@ def next_state(self, name):
return

self.__state.ran = False

def next_state_now(self, name):
'''Call this function to transition to the next state, and call the next
state function immediately. Prefer to use :meth:`next_state` instead.
:param name: Name of the state to transition to
'''
self.next_state(name)
self.on_iteration(self.__iter_tm)

def on_iteration(self, tm):
'''This function is called by the autonomous mode switcher, should
not be called by enduser code. It is called once per control
loop iteration.'''

self.__iter_tm = tm

# if you get an error here, then you probably overrode on_enable,
# but didn't call super().on_enable(). Don't do that.
try:
45 changes: 45 additions & 0 deletions samples/stateful_autonomous/autonomous/chained.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Demonstrates chaining multiple autonomous modes together
"""


from robotpy_ext.autonomous import StatefulAutonomous, state, state_alias, timed_state

class Auto1(StatefulAutonomous):
@timed_state(duration=1, next_state='do1_2')
def do1_1(self):
pass

@timed_state(duration=1, next_state='transition')
def do1_2(self):
pass


class Auto2(StatefulAutonomous):
@timed_state(duration=1, next_state='do2_2')
def do2_1(self):
pass

@timed_state(duration=1)
def do2_2(self):
pass


class ChainedMode(Auto1, Auto2):
'''Chains two autonomous modes together'''

MODE_NAME = "ChainedMode"

start = state_alias(Auto1.do1_1, first=True)
transition = state_alias(Auto2.do2_2)

class SingleMode(Auto1):
'''Runs one of the chained autonomous modes by itself'''

MODE_NAME = "Single"

start = state_alias(Auto1.do1_1, first=True)

@state()
def transition(self):
pass
1 change: 1 addition & 0 deletions samples/stateful_autonomous/robot.py
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ def robotInit(self):

# Simple two wheel drive
self.drive = wpilib.RobotDrive(0, 1)
self.drive.setSafetyEnabled(False)

# Items in this dictionary are available in your autonomous mode
# as attributes on your autonomous object