Lesson 25 - Multitasking

Why and What is Multitasking?

Let’s pretend we have the following code snippet where we have two adjacent while loops. Will the second while loop on line 7 even execute? No. 


void opcontrol(){
while(true){ ... }

while(true){ ... }
}


But what if we wanted two while loops to occur concurrently? For example, let’s say we wanted to have a separate while loop computing values that will be used in the opcontrol() function’s while loop? 


In VRC, the aforementioned scenario is quite typical: usually, there are control loops operating in the background to ensure the robot reaches a desired state. For example, if you want to make your lift go to a preset height while driving your chassis, both of those will need a separate while loop. In order for them to run concurrently, one will need to be in a side “task”.


We go about having separate while loops running in the background through something called “Tasks.” In the rest of the programming world, there is a lot more to parallel programming and it gets complicated pretty quickly. Fortunately, the knowledge needed to effectively utilize tasks in VRC coding applications is relatively little. 



Creating, Pausing, Resuming, and Stopping Tasks

To create a task that will run in the background, we would do the following: 

  1. Create a function that takes in pointers as parameters. We will actually not consider any parameters for this example since we did not cover passing pointers into functions. We actually need a void* in the parameter of our function to explicitly indicate that we do not pass any parameters.

  2. Use pros::Task task_name(function_name); to have the task immediately beginning running. 

  3. Whenever you wish to suspend the task (it will no longer run), use task_name.suspend()

  4. To resume a suspended task, use task_name.resume()

  5. To completely stop and remove a task from the queue, use  task_name.remove(); 


Here is an example involving tasks: 


#include "main.h"

pros::Motor right_motor(1);
pros::Motor left_motor(2);

5| void assign_loop_motor_power(void*){
while(true){
// Suppose 'calculate_power()' is a function that gets power.
right_motor.move(calculate_power());
left_motor.move(calculate_power());
pros::delay(25);
}
}


15| void opcontrol(){
// The function 'assign_loop_motor_power(void*)' will run in the background.
// Moreover, the while loop within the function 'assign_loop_motor_power(void*)' will not interrupt the reading of the rest of the code.

21| pros::Task lift_pwr_assignment(assign_loop_motor_power);

while(true){
// Normal driver control code goes here.
}
}


Line 5 contains the function that we wish to have as a task. I.e., we want the function to run in the background concurrently. 


Line 17. Usercontrol function. 


Line 21. Creating the task



Importance of Delay

NOTE: Make sure to include a pros::delay(25); at the end of every while loop. This is paramount as the refresh rate will still be high but it will not hog resources.