![]() |
Suggestion for next year's WPILib
A little idea I came up with after hearing how the LabVIEW teams have Autonomous handled. Basically in LabVIEW the Autonomous function is called asynchronously, and then terminated by the communications code at the end of autonomous.
I was thinking, why can't C++ teams do this as well? If the Autonomous function was simply called as a new Task, then it can easily be terminated by the main task when autonomous ends, avoiding the whole problem of autonomous code holding teleop from executing. Additionally, if the autonomous code happens to run into a fatal error and die, the robot would be given a second chance. Since only the autonomous task would be terminated and not the main robot task, the teleop code will still be started on time and the robot is given a sort of second chance. Most of the code to do this is already in WPILib. The Task class is already there to create the task. All that would need to be done is a few teaks to the SimpleRobot class and everything would work. Comments? |
Re: Suggestion for next year's WPILib
This is quite doable. We talked about doing it that way from the start, but through some (probably unwarranted) paranoia, the approach was not taken. Perhaps it could be an option at the least.
-Joe |
Re: Suggestion for next year's WPILib
It's good in theory but I do worry students may not understand multi-threaded programming. They need to learn inter-thread synchronization and exclusive access (e.g. semaphores). BTW, is it true that semaphores in vxWorks is not counting semaphores? I can't acquire the semaphore again in the same thread?
|
Re: Suggestion for next year's WPILib
I believe that VxWorks has all the semaphore types you could possibly want. If you are using ones wrapped by WPILib, they may be Boolean(noncounting), I don't have access to the code. Take a look.
Greg McKaskle |
Re: Suggestion for next year's WPILib
Quote:
Quote:
|
Re: Suggestion for next year's WPILib
I guess they could make it an alternative just like the alternatives of using SimpleRobot vs IterativeRobot or LabView vs C++ vs Java. People who's comfortable of doing multi-threaded programming could use it but other may want to stay with simpler programming practice. For example, improper use of semphores may cause deadlock and deadlock is not fun to debug.
|
Re: Suggestion for next year's WPILib
personally, with how our team has set things up if the robot doesn't exit autonomous then its because it was not meant to, by having it run in its own task (as much as i love starting new tasks every couple of lines) it adds layers of complexity to the code setup.
Also from what i have observed it seems to me (read: what could be happening but is most likely me misinterpreting things) that when a task hits a fault it can kill a lot more than just that task, for example: at the beginning of the season we had 2 camera tasks operating on the robot, they conflicted once and caused a rather large and ugly block of text to stream into the console out (memory access violation). The robot then proceeded to stop and we were forced to reboot to get things going again. Now this may have been something completely different, maybe the robot was waiting for a semaphore to be released by the now dead task for example. Also, a little more recently we observed that sometimes, just sometimes (it is very very annoying to track down as it is random) when starting and stopping tasks quickly or just doing it a lot the main robot task got ended (robot code light went off, task got stopped), because our watchdog expiration time was a bit high (someone got really annoyed with it one day) the robot kept going with the last sent motor values,in one case this sent it careening into a mentor, while no one was hurt and we all got a good laugh about it this is not good, and can cause things to break if the design requires something to stop at a certain place and the motor keeps running. on the plus side of things however it gives everyone a chance to learn about multi-threading and semaphore, which is very interesting to learn. is it overly difficult for students? I don't think so, but again that isn't saying a lot. for those that are intimidated by large, poorly edited blocks of text /and or in a hurry i'll summarize: Good idea as it gives teams chances to learn and grow. BUT: having more tasks=more complexity (usually) and with this comes a higher chance that something will go horribly horribly wrong |
Re: Suggestion for next year's WPILib
Quote:
|
Re: Suggestion for next year's WPILib
Quote:
See either the application or the kernel programmer's guides for more info. Just gotta plug this one more time, Wind River Workbench has Help, and it's searchable -- give it a try. |
Re: Suggestion for next year's WPILib
If implemented properly, programmers shouldn't even need to make their code thread-safe... at least, if I understand it properly... (I'm newish to C++ and completely new to WPILib)
Inside StartCompetition(), the main task would start an autonomous task that runs Autonomous(). Then, the main task would wait until IsAutonomous() is no longer true. After that happens, it would stop the autonomous task and go on. Since the only thing that the main task would do is check IsAutonomous(), then the autonomous task could run without any worries about race conditions (so all that teams must know about Autonomous() is that it might stop in the middle of their code). There is a problem though.. I haven't tested what stopping a task does. Does the task still unwind the call stack and call all destructors, or does it just stop immediately? If destructors are run, then does Task::Stop() block until the task is really dead? (The main task shouldn't continue until the autonomous task is truly dead so that there are no possible race conditions). If destructors aren't run, then the program becomes pretty unpredictable and there is no way to run any cleanup code. Not sure if above is completely correct.. EDIT: I was checking the WindRiver manual for information about how tasks are deleted. Unfortunately, it seems that stopping a task does not unwind the call stack. Stopping a task ends it right where it is. (It also doesn't release any semaphores; I could not tell whether Synchronized protects against that) It would be ideal if stopping a task threw an exception in the task so that all destructors would be called, but since that doesn't seem possible, then some AutonomousEnd() function or something should be called right after the task is stopped to allow for some cleanup code... Better than nothing. |
Re: Suggestion for next year's WPILib
I won't profess to know VxWorks inside and out, but killing threads is commonly a dangerous task if you do not control what the task is up to and allow it to get to a good place first. This is why LV Abort is somewhat cooperative and doesn't simply kill threads. It is still reasonable to do this within WPILib, just not as simple to pull off.
Greg McKaskle |
Re: Suggestion for next year's WPILib
I agree with Greg. A task either died unexpectedly or got killed is not a planned event. Therefore, the state of the whole program could be in jeopardy. If the task had allocated global resources, they were not released. If you restart the task, you may end up with duplicate resouces. The result could be totally unpredictable. In fact our code avoids spinning new threads unless the task is timing critical (need accurate timed execution). Even with most of the time critical scenarios, we found ways to do things coorpoeratively instead of needing to create new threads. I assume the threads in vxWorks are scheduled preemptively. Preemptive multi-tasking can interrupt you at any point in your code. That's why you need semaphores to protect a certain code region from being re-entered. Dealing with semaphore improperly will cause deadlock. That's not easy to debug especially if the deadlock is caused by some race conditions that don't reproduce predictably.
BTW, does anybody know the interval of a time slice in vxWorks? I found that if I created a Notifier with a given period, say 5 ms, my Notifier got called in 20+ ms instead. I suspect it has something to do with the timer tick interval in vxWorks. Am I correct? If so, what is that interval, 20 ms? Thanks. |
Re: Suggestion for next year's WPILib
Quote:
Also, for a nice explanation of the VxWorks multitasking model, share and enjoy. |
Re: Suggestion for next year's WPILib
This is exactly how we did our autonomous code this year (in Java). Basically, we decided that the "iterative"-style template makes the most intuitive sense for teleoperation, but that the "simple robot"-style sequential template leads to easier-to-understand-and-debug autonomous operation.
As a result, we used the iterative template, but created a separate class - AutonomousThread - that is kicked off by autonomousInit() (and killed by disabledInit() or teleopInit() ). Here's where it gets cool - when the AutonomousThread starts, it is passed an array of type "Action", which is a custom interface that we made. Each Action has an "execute()" and a "cancel()" method. The convention is that every Action will return from "execute()" when it is done (e.g. DriveDistance would return when the robot has covered the desired distance) or when it has been canceled. We implemented "cancel()" as a method that would set a flag inside the Action that would then be polled within the "execute()" loop, since there really isn't a good/safe way to kill threads from afar otherwise. So AutonomousThread looks a little bit like this: Code:
public void run()Now, where it gets REALLY cool is where you can serialize Actions to a file on a PC, FTP it to the cRIO, and load a new autonomous mode without re-deploying... If there is sufficient interest, I'll post our team's code at the end of the season. |
Re: Suggestion for next year's WPILib
Killing a thread is not too much a concern because it could be a controlled event (i.e. you can write code to monitor a termination event and clean up). It is the unexpected termination such as a fault that could be a problem although one can also use structured exception handling to do the clean up. However, it can clean up properly only if the code is expecting the fault (i.e. putting the code in the try block). In either case, if there are bugs in the code that do not expect a certain scenario, you can still hang the thread or fault without catching it.
Our code is also based on Iterative robot but we don't start a new thread. Instead, we have a structure that does cooperative multi-tasking. We also develop an event notification system and a generic state machine that makes the autonomous code almost script like. We could go further and write a parser to read a script from file too, but don't have time to do it this season. The autonomous code looks something like this: Code:
switch (state) |
| All times are GMT -5. The time now is 12:32. |
Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi