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.
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.
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:
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.
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.
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
or myVariable:
to the end of your loops and if’s in auto and your all set.