Passing Parameters to Tasks

Does anybody know how to pass parameters to a task? For example, in a function you can do this:
void runMotors(int power){
motor[wheel] = power;
}

But that does not work in a task. I have been getting by with using global variables like this:

int power = 0;
task runMotors(){
motor[wheel] = power;
}
task main(){
power = 80;
StartTask(runMotors);
}

Passing parameters becomes quite helpful when you have multiple tasks, so does anyone know how to use parameters with tasks? Thanks.

For what I have tried, you can’t. But I hope that I am wrong, maybe I am? I have had to use many global variables as well, which is alright, but in autonomous to call a single drive forwards task, I have to set about three variables, then start the task. This is four lines of code instead of just one, if we could set parameters.

~Jordan

unfortunately, I think that you are correct. I was really hoping that I wouldn’t have to use the 42 variables that I now have to. Anyway, lets hope that some way of passing parameters to tasks may be implemented in the future.

You also need to be careful that the global variables don’t get corrupted if two or more tasks update the same variable. One way around this problem is to use semaphore flags when updating these variables.

The GNU C/C++ compilers for the ARM provide threads, semaphores and mutual exclusion operators that prevent data corruption of critical sections. Other languages including Ada, JAVA and C# also provide threads and semaphores.

In my opinion, the best language for multitasking is the Adacore GNAT Ada 2005, which supports parameter passing options including Task Rendezvous accept statements and Protected Records. I mention this option since the LEGO Mindstorms (NXT) support this compiler, which is perfect for robotics since it also provides many software safety features including runtime range checking and exception handling. I am hoping that Adacore will someday port the GNAT Ada compiler to the VEX ARM Microcontroller.

  1. Create a function having desired parameters.
  2. Set “private” globals in function to parameter values.
  3. Spawn task.
  4. Read “private” globals in task.

Not perfect, but it works.

You might also consider adding supervisory options to the function call such as blockng until the task completes (standard function behavior) or killing the task if it fails to complete within a timeout period.

@ tswift1: Thank you for that information. Also, I’m pretty sure that the new version of robotc prevents two tasks from trying to acess the same data and corrupting it.

@ BillyW: Thanks, but that requires the same number of lines. But it is a good idea if you want to keep the tasks seperate including variables. Also, what do you mean by blcoking? Stopping other tasks from executing while one is? Doesn’t that defeat the purpose of a task? The timeout is a good idea. I will probably implement that. Thanks

Yes I have different global variables for every type of task that would ever be running at the same time as another. For example I could have speed variables, and name them “SpeedDrive”, “SpeedArm”, and “SpeedClaw”. (Just an example, not what I am really using.)

~Jordan

The globals are set inside the function, not in the code prior to calling the function–meaning that it is only the same number of lines if you call it once.

A quick search found this on Wikipedia:
Blocking (scheduling), means one task is prevented from continuing until another has completed.
Blocking (computing), not returning from a function until the function has completed or resulted in an error.

Or, as I said parenthetically above: blocking is the equivalent of standard function behavior.

Why would this be desirable? Take, for instance, a function that controls the movement of your robot. In some instances, you might want to have that function run simultaneously with another activity (such as raising an arm). In others, you might want to wait until the movement is complete before performing the next action (such as dropping rings). In the first case, you would use a task. In the second, just a standard blocking function. Code maintenance is much cleaner if you only have one function responsible for a particular action; this can be accomplished by adding a blocking option as a parameter to the wrapper function.

Ok. Thanks for clarifying. Here is how I would handle the blocking mechanism.


int power = 127;
bool blockOtherfunctions = true;
task moveArm(){
  if(blockOtherTasks) hogCPU();
  while(vexRT[Btn6]){
    motor[arm] = power;
  }
  releaseCPU();
}

Does anybody have a better way?

Here’s some semi-pseudo RobotC code to make the arm behave in a semi-autonomous manner. Here, a driver can pick up a stack of tubes and depending on which goal he intends to score, can press the appropriate button once and proceed to drive to that goal. The arm will continue towards its selected position with no further input from the driver. The driver only need concentrate on getting to the selected goal. Once at the goal he can then pressed the manual controls to lower arm. Also at any time when the arm is moving to the new position, pressing the manual will drop it into manual mode. Of course with all those buttons on the Cortex, you could for example accurately score tubes as well by moving slowly back while lowering arm. Here’s the basic structure of this algorithm.

int commanded_arm_position; //global parameter for task

//this task uses arm motor and potentiometer on shaft
//to create a "servo" where global "commanded_arm_position"
//variable is the parameter to this task.  Motors will drive the
//arm/shaft so that the arm_potentiometer value equals the
//commanded_arm_control variable. Probably best to implement this
//using P or PI control

task arm_control()
{
 while(1) //infinite loop to drive arm to position & maintain it
 {
   if (commanded_arm_control > Sensor(arm_potentiometer) motor[arm]=127; //drive arm up
  else if (commanded_arm_control < Sensor(arm_potentiometer) motor[arm]=-127; //drive arm down
  else motor[arm]=0;  //Stop
  }
}

//this is the competition mode user_control task where the driver controls the
//drive train but just press certain predefined buttons on the controller to 
//autonomously move the arm to the desired positions

task user_control()
{
 int arm_position=400;               //This value a function on how you mount the potentiometer

 commanded_arm_position=400;  // 400 is potentiometer value when arm is down
                                            //900 is the upper limit of arm position
 startTask (arm_control);

 while(1)
 {

  ... code to set appropriate joystick values to drive motors
  ... code to controls claws

  //code to control arm position manually
  //if up or down button pressed, increment/decrement arm_position variable

  if (arm_up_button_pressed ) arm_position++; //Need to limit between 400 & 900
  if (arm_dn_button_pressed ) arm_position--;

  //code to make arm move to preset arm positions
  //Depending on which button pressed (Cortex Joystick controller)
  //Jam arm_position with appropriate Potentiometer values

  if (arm_preset_ground) arm_position=400; ground level ready to pickup
  if (arm_preset_low_goal_de) arm_position=500; just at low goal for de-scoring
  if (arm_preset_low_goal_sc) arm_position=600; just above low goal for scoring
  if (arm_preset_high_goa_del) arm_position=800; just at high goal for de-scoring
  if (arm_preset_high_goal_sc) arm_position=900;just above high goal for scoring

  //Send value to task arm_control() to move arm
  //independent of drive or claw functions

  commanded_arm_position = arm_position;
 }
}

This is useful code to have but how may I ask does this have to do with the topic “Passing Parameters to Tasks”?