PROS Mutitasking

I am currently trying to multitask by using tasks in PROS. So before in robotC, i could just declare a task by:

task my_task(){
cout>>“hello world”;
}

and start it by:

start task(my_task);

Now in PROS, tasks gets more misunderstanding.
Can anyone explain to me how could i use tasks in pros and how do they work?
Is it that tasks in PROS has parameters?
Thanks a lot.

Have you read the tutorial on multitasking?

2 Likes

Yes. I doesn’t really make sense to me.

task_t task_create ( task_fn_t function,
void* parameters,
uint8_t prio,
uint16_t stack_depth,
const char* name )

Not sure about all the messy parameters to create a task

What is your confusion? Did you read the specific portion of creating tasks?

2 Likes

yes i read it.
What does priority and depth mean?
I thought all tasks could run in parallel.

Tasks don’t truly run in parallel. Only one runs at a time. Tasks get swapped out by the scheduler. Every millisecond, the scheduler stops the current task and decides whether to schedule a different task. It could decide to resume the same task or let another task run.

Priority helps the scheduler decide what to run next. A high priority task will always be allowed to run before a low priority task. Most users shouldn’t worry about task priorities - just set it to TASK_PRIORITY_DEFAULT.

Stack space is used by a task to call functions and store variables. Similarly, most users shouldn’t need to worry about running out of stack space, just set it to TASK_STACK_DEPTH_DEFAULT.

Edit:

We say that tasks run in parallel because each task operates independently from one another and tasks are swapped out so quickly that it appears to run in parallel.

3 Likes

Wow thanks a lot now I understand

so on the website it says this:

task_t my_task = task_create(my_task_fn, (void*)“PROS”, TASK_PRIORITY_DEFAULT,
TASK_STACK_DEPTH_DEFAULT, “My Task”);

if i want to have an integer parameter called speed and a boolean parameter called reverse, how do i declare the task?
also, after i created the task, how do i add in procedures in the task? eg. cout << “hello world”;?

A task is just a function that returns nothing and has a void* argument parameter. You can do “whatever” you want inside the function. ROBOTC taught you that tasks were special things, but they’re not really. In this particular example, you can think of a task function as a function that runs on its own, independent of the task you started it in.

In order to pass in multiple arguments to a task, you could either a) use a global variable or b) give the task a pointer to a struct containing the arguments. a) is typically considered bad practice so I’ll show how to do b) below.

Here’s the example in C:

typedef struct {
  int speed;
  bool reverse;
} my_task_arg;

void my_task_fn(void* argument) {
  // Following two lines get the members of the my_task_arg struct
  int speed = ((my_task_arg*)argument)->speed;
  bool reverse = ((my_task_arg*)argument)->reverse;
  printf("Speed is: %d; reverse is: %d\n", speed, reverse);
}

void opcontrol() {
  my_task_arg* argument = malloc(sizeof(my_task_arg));
  argument->speed = 100;
  argument->reverse = false;
  // just separating arguments over new lines for ease of reading on the forum
  task_t my_task = task_create(my_task_fn, argument, 
                               TASK_PRIORITY_DEFAULT, 
                               TASK_STACK_DEPTH_DEFAULT, 
                               "My Task");
}

And equivalent example in C++

typedef struct {
  int speed;
  bool reverse;
} my_task_arg;

void my_task_fn(void* argument) {
  // Following two lines get the members of the my_task_arg struct
  int speed = ((my_task_arg*)argument)->speed;
  bool reverse = ((my_task_arg*)argument)->reverse;
  std::cout << "Speed is " << speed << "; reverse is: " << reverse << std::endl;
}

void opcontrol() {
  my_task_arg* argument = new my_task_arg();
  argument->speed = 100;
  argument->reverse = false;
  pros::Task my_task(my_task_fn, argument);
}
1 Like

A post was split to a new topic: PROS possible mutex bug

But isn’t that what makes them special.
tasks are not functions.

2 Likes

Tasks themselves aren’t functions, but they run a piece of code that you implement as a function. I think plenty of users made the task keyword into something special.

There’s nothing stopping from doing something like:

void my_function(void* argument) {
   printf("I'm running %s\n", (char*)argument);
}

void opcontrol() {
  my_function("in operator control");
  task_create(my_function, "in my own task", TASK_PRIORITY_DEFAULT, 
              TASK_STACK_DEPTH_DEFAULT, "Example");
}

Only ROBOTC made you have the distinction.

2 Likes

Nope, but, in my opinion at least, it’s a really bad habit (not to mention the cpu overhead of doing that)
(and for me it’s nothing to do with ROBOTC. I used many RTOS before ever touching ROBOTC and you just don’t do things like that)

2 Likes

I mean yeah, it’s bad practice.

image

1 Like

Elliot, we can talk about this somewhere else otherwise we will have to flag our posts as being off topic. My only point was, use functions where appropriate and create a new task where appropriate.

4 Likes

BTW what does “in my own task” and “Example” do? when will print it and where or what is the usage of the two strings?

It’s the arguments to task_create as was in the examples above. The first string is the argument to the task entry function (my_function). The second string is the name of the task. It won’t normally be printed unless you explicitly ask to get the current task name.

The C Programming Language book is a great place to learn everything you need to know about C. I’m pretty sure you can find PDFs of the book online. This is the book Purdue and I’m sure nearly every other CS department uses to introduce C to their students. I’d recommend using it as an as-needed reference: when you run into something you haven’t seen before, you can look up the chapter/section that talks about the thing.

1 Like

So i was creating a program to multitask when checking if the encoders of the motors had reached the target.
This is the calling program

void pilot(short FLcm, short FL, short FRcm, short FR, short RLcm, short RL, short RRcm, short RR){
stopMove();
leftFront. tareposition();
rightFront.tareposition();
leftRear. tareposition();
rightRear. tareposition();
moveFLtick = ( (FLcm / (WHEEL_DIAMETER * 3.14159) ) * 900);
moveFRtick = ( (FRcm / (WHEEL_DIAMETER * 3.14159) ) * 900);
moveRLtick = ( (RLcm / (WHEEL_DIAMETER * 3.14159) ) * 900);
moveRRtick = ( (RRcm / (WHEEL_DIAMETER * 3.14159) ) * 900);
moveFLspeed = FL;
moveFRspeed = FR;
moveRLspeed = RL;
moveRRspeed = RR;
task_create(pilotService, “PROS”, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, “pilotService”);
pilotService();
}

leftFront, rightFront, leftRear, rightRear are motor names
stopMove() is just to set drive to 0 power and reset move tick
move ticks and move speeds are declared out of this function

this is the task:

void pilotService(void*){
short FLPosition, FRPosition, RLPosition, RRPosition;
while(true){
FLPosition = leftFront. get_position();
FRPosition = leftRear. get_position();
RLPosition = rightFront.get_position();
RRPosition = rightRear. get_position();
if(FLPosition<moveFLtick||FRPosition<moveFRtick||RLPosition<RLPosition||RRPosition<moveRRtick){
pros::delay(25);
}
else{
break;
}
}
}

not sure what “PROS” in task_create() does
also not sure of what void* in pilotService do (i know what pointers are)

Check out the API reference

The void pointer parameter in a task function provides a way to pass data to the task when it is first created. See Elliot’s example from earlier in this thread