Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Python (http://www.chiefdelphi.com/forums/forumdisplay.php?f=187)
-   -   Infinite loop means no control (http://www.chiefdelphi.com/forums/showthread.php?t=104464)

tux 11-03-2012 12:55

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.

tux 11-03-2012 18:54

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.

virtuald 11-03-2012 21:47

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.

Ether 12-03-2012 09:58

Re: Infinite loop means no control
 
Quote:

Originally Posted by tux (Post 1142108)
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?



tux 12-03-2012 21:33

Re: Infinite loop means no control
 
Quote:

Originally Posted by virtuald (Post 1142454)
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.

nightpool 20-10-2012 11:41

Re: Infinite loop means no control
 
Quote:

Originally Posted by Ether (Post 1142746)
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.

thetntm 12-02-2013 21:47

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.

virtuald 14-02-2013 00:48

Re: Infinite loop means no control
 
Quote:

Originally Posted by thetntm (Post 1232467)
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. :p

tux 16-02-2013 18:30

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.


All times are GMT -5. The time now is 19:51.

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