Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   Suggestion for next year's WPILib (http://www.chiefdelphi.com/forums/showthread.php?t=84628)

Radical Pi 24-03-2010 19:12

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?

Joe Hershberger 25-03-2010 23:16

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

mikets 26-03-2010 01:05

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?

Greg McKaskle 26-03-2010 08:23

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

dmlawrence 26-03-2010 22:04

Re: Suggestion for next year's WPILib
 
Quote:

Originally Posted by Radical Pi (Post 942745)
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.

Couldn't this be done in the current system using some well-placed exception handling?



Quote:

Originally Posted by mikets
It's good in theory but I do worry students may not understand multi-threaded programming.

From the perspective of a student, I think it's completely doable to teach multithreading. Maybe not easy -- but if it was easy it wouldn't be FIRST...

mikets 27-03-2010 00:36

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.

Zme 27-03-2010 20:06

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

Radical Pi 27-03-2010 23:40

Re: Suggestion for next year's WPILib
 
Quote:

Originally Posted by Zme (Post 943822)
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.

If the library is written right the robot would be disabled as soon as the task was killed, and then teleop takes over control for enable.

gvarndell 29-03-2010 06:11

Re: Suggestion for next year's WPILib
 
Quote:

Originally Posted by mikets (Post 943331)
BTW, is it true that semaphores in vxWorks is not counting semaphores? I can't acquire the semaphore again in the same thread?

Yes, vxWorks has counting semaphores -- had them forever.
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.

Slix 29-03-2010 15:26

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.

Greg McKaskle 29-03-2010 19:23

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

mikets 29-03-2010 21:53

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.

slavik262 31-03-2010 09:33

Re: Suggestion for next year's WPILib
 
Quote:

Originally Posted by Greg McKaskle (Post 945253)
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

It's not just VxWorks, but pretty much any OS - killing off a thread without giving it a chance to release any resources it might be using is generally bad. It's not that difficult, however, to make a thread that just loops until you send a message to it to exit. Then to kill the thread, you just send the exit message, the thread gets out of its main loop, cleans up, and exits.

Also, for a nice explanation of the VxWorks multitasking model, share and enjoy.

Jared Russell 31-03-2010 10:05

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()
{
  for( int i = 0; i < mActions.length; i++ )
  {
    mCurrentAction = i;
    if( !mCancelled )
    {
      mActions[i].execute();
    }
  }
}

public synchronized void cancel()
{
  mCancelled = true;
  mActions[mCurrentAction].cancel();
}

Ain't polymorphism grand? (Even though this is Java, the same technique would work fine in C++).

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.

mikets 31-03-2010 10:35

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)
{
    case 0:
        // Do something such as drive forward 3 ft.
        // At the end of the drive, it will generate an event.
        nextstate = 1;
        WaitForEvents(event, nextstate);
        break;
    case 1:
        ...
        break;
}

The WaitForEvents is not blocking, so the code returns for executing other stuff until an event unblocks it.


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