Playbook: Multi-Threading
Figure 1: Keys
1 - Back
2 - Enter
3 - Up / Down / Left / Right
Multi-threaded programs can perform several actions at once. And I'm not talking about just moving two motors at the same time. I'm talking about different parts of the program executing simultaneously. It is possible to write programs where one function will continuously monitor some condition(s) of the robot and take actions if certain conditions are met. This monitoring can occur completely independently of the main program being executed.
Many of you have already used these features without realizing it. For example, pressing the back button (see below) will terminate the current program.
What is a Thread?
Think of a thread as the string of commands that are being executed. Multiple threads mean that multiple strings of commands are executed simultaneously. When you start a program on a robot or a computer you are starting an "application" (also known as a "process"). You can see a list of processes that are currently running on the computer by pressing CTRL-ALT-DEL and accessing the task manager. Processes in that list can be sorted by time, memory, and CPU usage to give you an idea of which processes are using the most resources of the computer.
"Processes" written by beginning programmers, typically have just one thread. More advanced programmers use multiple threads (each of which shares the same memory (variables) allocated for the one process in which they are running. These threads share the process's resources, but are able to execute independently.
Advantage of Multi-Threaded Programs
Increased Responsiveness Multi-threading can help an application to be more responsive to input. In a single-threaded program, if the main execution thread blocks on a long-running task, the entire application must wait until the long-running task is completed before it can do something else. By moving such "user interface" tasks to a worker thread that runs concurrently with the main execution thread, it is possible for the application to remain responsive to user input while executing tasks in the background.
Program Interrupter
What if, for example, you wanted the program to return to your main menu when you press the "Left" key? Is there a way to get the program to return to your main menu when you press the "Left" key? Could you get the program to simply pause where it is at when you press the "Up/Down" key and resume operation when you press the "Enter" key?
These additional functions can be added to your program through the use of multi-threading.
/**************************************************************
This task monitors the Left/Right buttons and returns terminates
***************************************************************/
task leftRightButtonHandler() {
OkToMove = true;
while(true) {
if (getButtonPress(buttonLeft) && getButtonPress(buttonRight)) {
setLEDColor(ledRedFlash);
playSoundFile("Goodbye"); wait1Msec(1000); stopAllTasks();
}
if (OkToMove && (getButtonPress(buttonLeft) || getButtonPress(buttonRight)) ) {
OkToMove = false;
motor[motorB]=0;
motor[motorC]=0;
setLEDColor(ledRed);
}
sleep(100);
}
}
This
task has been named: leftRightButtonHandler() for obvious reasons--it "Handles" the left and right button presses. This task is called from the main task like below:
/**************************************************************
This is the main task and it will start the leftRightButtonHandler() task immediately.
When you press the left or right button, the robot will stop moving
and program control will be returned to the main while loop.
***************************************************************/
bool OkToMove=true;
task main() {
startTask(leftRightButtonHandler);
while(true) {
stopMoving();
untilTouch();
setLEDColor(ledGreenFlash);
OkToMove=true;
while(OkToMove) {
driveForward();
}
}
}
Stall Detector
long lastEncoderValue=0;
long stallCounter=0;
bool stalled=false;
bool moving=false;
task checkForMotorStall() {
while(true) {
sleep(100);
hogCPU();
if(abs(lastEncoderValue - nMotorEncoder[port]) < 5) {
if(abs(motor[port]) > 0 ) stallCounter++;
stallCounter++;
if(stallCounter>5) { stalled = true; moving = false; }
lastEncoderValue = nMotorEncoder[port];
} else {
stallCounter=0;
stalled=false;
moving=true;
}
releaseCPU();
}
}
90 Second Time Limit / 150 Second Time Limit
Vex IQ challenges have a 90 second time limit. The First Lego League (FLL) challenges have a 150 second time limit. Can you create a "self-destruct" timer so that after the set time limit, the robot simply stops working? This could be a tool for practices to make sure you accomplish the missions within the time limits.
task stopAfter(int seconds) {
sleep(1000 * seconds);
stopAllTasks();
}
task main() {
stopAfter(90);
// blah blah blah
}