OCCRA
Go to Post When we learn physics, we almost always "ignore friction". The real world never does... - Mike Betts [more]
Home
Go Back   Chief Delphi > Technical > Programming > Python
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Reply
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 10-01-2017, 02:18 PM
mylodon mylodon is offline
Registered User
FRC #3223
 
Join Date: May 2016
Rookie Year: 2013
Location: Washington
Posts: 12
mylodon is an unknown quantity at this point
magicbot StateMachine

How is a StateMachine component meant to be used in a higher level component?

For example, I have a state machine that gets kicked off by a joystick button press, and then runs to completion unless pressed by another button. I would expect my robot code to look something like

Code:
  def teleopPeriodic(self):
    if self.joystick.getRawButton(1) and not self.state_machine.is_executing:
      self.state_machine.engage()
    if self.joystick.getRawButton(2):
      self.state_machine.done()
    self.state_machine.execute()
but it doesn't seem to be working that way and I can't seem to find really any example in the docs.
Reply With Quote
  #2   Spotlight this post!  
Unread 10-01-2017, 04:11 PM
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #6367 (), FRC #7240 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,391
virtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond repute
Re: magicbot StateMachine

First, you don't need to call execute -- execute is always called for you by the MagicRobot class (this is how magicbot components work, after all. Perhaps the docs could be clearer on that point).

To get the kind of behavior you're talking about, I would specify must_finish in the state decorator, something like so:

Code:
class MyComponent(StateMachine):
    
    @state(first=True, must_finish=True)
    def do_a_thing(self):
        # do something here
        pass
Then you could call it from MagicRobot via:

Code:
def teleopPeriodic(self):
  if self.joystick.getRawButton(1):
    self.state_machine.engage()
  if self.joystick.getRawButton(2):
    self.state_machine.done()
Once the state machine is engaged, it will continue being executed (eg, do_a_thing is called) until done() is called, at which time do_a_thing will stop being called.
__________________
Maintainer of RobotPy (Python for FRC) & WPILib Contributor
Creator of pyfrc (Robot Simulator + utilities for Python), pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript), and lots more...

Team #1418 (remote mentor): Newton Quarterfinalists, 2016 Chesapeake District Champion, 2x Innovation in Control award, 2x district event winner
Team #1418: 2015 DC Regional Innovation In Control Award, #2 seed; 2014 VA Industrial Design Award; 2014 Finalists in DC & VA
Team #2423: 2012 & 2013 Boston Regional Innovation in Control Award


Resources: FIRSTWiki (relaunched!) | My Software Stuff
Reply With Quote
  #3   Spotlight this post!  
Unread 10-01-2017, 07:01 PM
mylodon mylodon is offline
Registered User
FRC #3223
 
Join Date: May 2016
Rookie Year: 2013
Location: Washington
Posts: 12
mylodon is an unknown quantity at this point
Re: magicbot StateMachine

Ok. I have 5 states currently, and so each must be decorated with must_finish=True. That works.

What's the significance of must_finish=False? It seems not so useful.

My first attempt was without must_finish=True on anything:

Code:
def teleopPeriodic(self):
  self.state_machine.engage()
it ran through the state machine nicely, but when it reached the end state, it reset to the start state and went through the state machine again. This doesn't seem useful, if I wanted my state machine to loop, I'd build the loop into the state machine.

My expectations for a state machine api:

execute - run the state machine for a single cycle unless it is in the end state, otherwise do nothing
is_finished - true iff in the end state
reset - set the current state to the start state

Compared to that, it seems engage is a combination of execute and reset, and there is no is_finished.
Reply With Quote
  #4   Spotlight this post!  
Unread 10-01-2017, 09:59 PM
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #6367 (), FRC #7240 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,391
virtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond reputevirtuald has a reputation beyond repute
Re: magicbot StateMachine

Quote:
Originally Posted by mylodon View Post
What's the significance of must_finish=False? It seems not so useful.
That's a fair criticism. The state machine stuff was originally created for autonomous modes (and honestly, that's really where I find it useful, I'm still working on making it more useful in teleop), so the state machine behaves as if someone was constantly calling engage() until done is called. That behavior is closer to what one expects.

In teleop, my philosophy is that "nothing should happen unless I tell it to happen", and so the state machine follows that. If you don't call engage, then the state machine won't do it's things. In my opinion this generally makes it easier to reason about what's happening when debugging. Often the most confusing types of bugs occur when there's some kind of stale state left in the system and you're trying to figure out why it is still doing that thing.

Quote:
it ran through the state machine nicely, but when it reached the end state, it reset to the start state and went through the state machine again. This doesn't seem useful, if I wanted my state machine to loop, I'd build the loop into the state machine.
Hm. I see how that could happen. The looping is arguably buggy behavior. Please file an issue on github (or even better, make a pull request with a fix).

Quote:
My expectations for a state machine api:

execute - run the state machine for a single cycle unless it is in the end state, otherwise do nothing
is_finished - true iff in the end state
reset - set the current state to the start state

Compared to that, it seems engage is a combination of execute and reset, and there is no is_finished.
execute is one of the functions required by the magicbot component definitions (and the component API was defined before the state machine stuff I think), so it is always called every loop, thus it can't be used in the way that you specify. Instead, it manages the actual execution of the states if the machine is engaged.

engage is similar to what you want in execute, with the exception that the state machine effectively turns itself off if you don't call it. If the state machine is 'turned off', then the function with the @default_state decorator is called.

reset could be implemented, it would be equivalent to:

Code:
def reset(self):
    first_state = look up the first state()
    self.next(first_state)
Because the state machine can branch in arbitrary paths because you can call the next() function to move to a named state, technically, there's no end state, so is_finished isn't really meaningful. It would be vaguely equivalent to 'not my_state_machine.is_executing'.

The RobotPy project is intended to be a community project, so if it doesn't do what you want then I'm certainly open to improvements. Pull requests on github are especially encouraged.
__________________
Maintainer of RobotPy (Python for FRC) & WPILib Contributor
Creator of pyfrc (Robot Simulator + utilities for Python), pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript), and lots more...

Team #1418 (remote mentor): Newton Quarterfinalists, 2016 Chesapeake District Champion, 2x Innovation in Control award, 2x district event winner
Team #1418: 2015 DC Regional Innovation In Control Award, #2 seed; 2014 VA Industrial Design Award; 2014 Finalists in DC & VA
Team #2423: 2012 & 2013 Boston Regional Innovation in Control Award


Resources: FIRSTWiki (relaunched!) | My Software Stuff
Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 07:22 PM.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi