Go to Post You should take in to consideration who you are putting on to the field, not what. - NorviewsVeteran [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 11-03-2012, 12:55
tux tux is offline
Registered User
AKA: Lee Harr
FRC #3842 (Shock-a-Bots)
Team Role: Mentor
 
Join Date: Apr 2005
Rookie Year: 2005
Location: Rochester, NY
Posts: 91
tux is an unknown quantity at this point
Infinite loop means no control

Our regional finished up yesterday. Python worked out very well for us, but I just now realized that the autonomous code I wrote was causing us a serious problem.

Thursday and Friday, everything was working fine. On Saturday, one of our mechanisms that was used during autonomous mode broke down. In order to keep our thrower motor from running continuously during the match we just tied down the limit switch that normally stopped and started the motor.

The problem was that the autonomous code watched for that switch to be toggled twice -- once for each ball thrown. No toggle meant that the autonomous code just kept on running in a loop waiting for the switch to toggle.


The moral of the story is:

You absolutely must check which mode you are in during every loop. Failure to do so may mean that your program will not change modes when the field changes mode.

I think this is an issue no matter which programming method is used, but I'm not really sure. I know it caught me in python.
Reply With Quote
  #2   Spotlight this post!  
Unread 11-03-2012, 18:54
tux tux is offline
Registered User
AKA: Lee Harr
FRC #3842 (Shock-a-Bots)
Team Role: Mentor
 
Join Date: Apr 2005
Rookie Year: 2005
Location: Rochester, NY
Posts: 91
tux is an unknown quantity at this point
A better way?

I think what I am going to do is wrap wpilib.Wait in Python.

Loops are already required to call Wait regularly, so why not check for mode changes there?

What it could do is check and save the current mode and throw an exception any time the mode changes. That exception could then be caught at the top level mode dispatch tree.

In fact, I'd recommend something like this as the best way to go to insure that the correct section of code is always running.

Some people might say that you should not use exceptions to control program flow, but I think this will simplify programs significantly. I haven't tested anything yet, though, so I don't know what problems may come up.
Reply With Quote
  #3   Spotlight this post!  
Unread 11-03-2012, 21:47
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #1418 (), FRC #1973, FRC #4796, FRC #6367 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,032
virtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant future
Re: Infinite loop means no control

This is not a problem specific to python, this could happen with any programming language. If your code doesn't yield, then it will never be able to switch modes. We always program our robot in a loop that looks like this:

Code:
while self.IsEnabled() and self.IsOperatorControl():
    .. do stuff here
In particular, if you're using wpilib.Wait() for anything other than a delay at the end of the main loop so you're not using 100% CPU, or if you're in a loop waiting for some switch or condition to change without doing anything else... you're probably doing it wrong. Once again, this goes for any programming language, not just python. There are many other ways to wait for things to happen, and by blocking on a wait statement you cannot do anything else on that thread while waiting, which is generally bad.

You might try looking at the Commands/Events stuff that WPILib introduced this year, there's support for it in Python despite a lack of documentation (in all languages, really).

I will admit, there are a variety of examples that come with RobotPy, and I don't really like many of them. This might be part of the problem. Hopefully I (or someone) will find some time to clean them up at some point.
__________________
Maintainer of RobotPy - Python for FRC
Creator of pyfrc (Robot Simulator + utilities for Python) and pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript)

2017 Season: Teams #1973, #4796, #6369
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
  #4   Spotlight this post!  
Unread 12-03-2012, 09:58
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 7,995
Ether has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond repute
Re: Infinite loop means no control

Quote:
Originally Posted by tux View Post
No toggle meant that the autonomous code just kept on running in a loop waiting for the switch to toggle.
...
You absolutely must check which mode you are in during every loop. Failure to do so may mean that your program will not change modes when the field changes mode.
...
I think this is an issue no matter which programming method is used, but I'm not really sure.
I'm not a LabVIEW guru, but I was under the impression that "getting stuck in autonomous" is not an issue with the FRC LabVIEW framework, because it automatically shuts down autonomous at the end of the autonomous period.

Could a knowledgeable LabVIEW person please comment?


Reply With Quote
  #5   Spotlight this post!  
Unread 12-03-2012, 21:33
tux tux is offline
Registered User
AKA: Lee Harr
FRC #3842 (Shock-a-Bots)
Team Role: Mentor
 
Join Date: Apr 2005
Rookie Year: 2005
Location: Rochester, NY
Posts: 91
tux is an unknown quantity at this point
Re: Infinite loop means no control

Quote:
Originally Posted by virtuald View Post
if you're in a loop waiting for some switch or condition to change without doing anything else... you're probably doing it wrong.
But it made the autonomous code so simple. And it worked great ... until the mechanism broke down.


I could do:

Code:
while not throwerToReady():
    Wait(0.01)

throw():

If you have to go through the whole loop each time, you must have to create some kind of state machine.

By tooling Wait to watch for mode changes the simple style could work.
Reply With Quote
  #6   Spotlight this post!  
Unread 20-10-2012, 11:41
nightpool's Avatar
nightpool nightpool is offline
robotRectifier
AKA: Evan
no team (formerly of CORE 2062)
Team Role: Alumni
 
Join Date: Oct 2011
Rookie Year: 2011
Location: Waukesha, WI
Posts: 81
nightpool is on a distinguished road
Re: Infinite loop means no control

Quote:
Originally Posted by Ether View Post
I'm not a LabVIEW guru, but I was under the impression that "getting stuck in autonomous" is not an issue with the FRC LabVIEW framework, because it automatically shuts down autonomous at the end of the autonomous period.

Could a knowledgeable LabVIEW person please comment?
From my reading of the LabVIEW framework, this is right. LabVIEW starts the Autonomous VI as a separate task, and then kills it when autonomous mode ends. This is possible with C++/Python/Java too, but most teams opt to avoid the confusion of threading and just stick with single-threaded code. In fact, my team had an issue with LabVIEW last year that we traced to a race condition happening around the transition into autonomous.
__________________
Proud alum of CORE 2062.
www.core2062.com
Reply With Quote
  #7   Spotlight this post!  
Unread 12-02-2013, 21:47
thetntm's Avatar
thetntm thetntm is offline
Registered User
FRC #4019
 
Join Date: Jan 2013
Location: california
Posts: 7
thetntm is an unknown quantity at this point
Re: Infinite loop means no control

all teams should have a method for exiting auto mode manually in case you get stuck in auto and can't switch to manual.
just get the state of a button in an if statement and have a variable turn true. add
Code:
or myVariable:
to the end of your loops and if's in auto and your all set.
__________________
there are 2 kinds of people in this world, those worth remembering, and ...
Reply With Quote
  #8   Spotlight this post!  
Unread 14-02-2013, 00:48
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #1418 (), FRC #1973, FRC #4796, FRC #6367 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,032
virtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant future
Re: Infinite loop means no control

Quote:
Originally Posted by thetntm View Post
all teams should have a method for exiting auto mode manually in case you get stuck in auto and can't switch to manual.
just get the state of a button in an if statement and have a variable turn true. add
Code:
or myVariable:
to the end of your loops and if's in auto and your all set.
Or even better, just make sure you don't ever use loops in your robot code.
__________________
Maintainer of RobotPy - Python for FRC
Creator of pyfrc (Robot Simulator + utilities for Python) and pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript)

2017 Season: Teams #1973, #4796, #6369
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
  #9   Spotlight this post!  
Unread 16-02-2013, 18:30
tux tux is offline
Registered User
AKA: Lee Harr
FRC #3842 (Shock-a-Bots)
Team Role: Mentor
 
Join Date: Apr 2005
Rookie Year: 2005
Location: Rochester, NY
Posts: 91
tux is an unknown quantity at this point
Re: Infinite loop means no control

I implemented my plan to throw an exception on every mode change and it is working pretty well.

I wrapped wpilib.Wait
Code:
from mode import check_mode

def wait():
    check_mode()
    wpilib.Wait(0.01)

and mode.py looks like this:
Code:
MODE_DIS = 0 # Disabled
MODE_AUTO = 1 # Autonomous
MODE_TELE = 2 # Teleoperated
mode = None


class ModeChange(Exception):
    'Exception raised when mode changes.'
    pass


def check_mode():
    'Check for a change in mode. Raise an exception if changed.'

    global mode

    if wpilib.IsDisabled():
        if mode != MODE_DIS:
            mode = MODE_DIS
            raise ModeChange
        return

    if wpilib.IsAutonomous():
        if mode != MODE_AUTO:
            mode = MODE_AUTO
            raise ModeChange

    if wpilib.IsOperatorControl():
        if mode != MODE_TELE:
            mode = MODE_TELE
            raise ModeChange

As long as any looping code calls this custom wait function, as soon as the mode changes an exception will be thrown.

In robot.py I catch the mode change and any other exception that happens to be thrown.
Code:
def run():
    while True:

        try:
            if wpilib.IsDisabled():
                print('Running disabled()')
                while wpilib.IsDisabled():
                    disabled()
                    wait()

            elif wpilib.IsAutonomous():
                print('Running autonomous()')
                while wpilib.IsAutonomous() and wpilib.IsEnabled():
                    autonomous()
                    wait()

            elif wpilib.IsOperatorControl():
                print('Running teleop()')
                while wpilib.IsOperatorControl() and wpilib.IsEnabled():
                    teleop()
                    wait()

            wait()

        except ModeChange:
            pass

        except KeyboardInterrupt:
            raise

        except:
            disable()
            print('ERROR')
            import traceback
            traceback.print_exc()

Seems to be working well, but if anyone sees a potential problem, I'd be glad to hear about it.


I like the idea about having an emergency autonomous escape button. With the code I have, it could just be a button that raises an exception.
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 21:36.

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


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