Understanding Competition Methods & Template

In VEX Coding Studio, for V5, in the competition template, I have two questions:

  1. What are these two commands doing? Are they only identifying the functions for the field controller to call when in autonomous or drivercontrol parts of competition? If so, are these function names “autonomous” and “usercontrol” that are inside the parentheses arbitrary? (ie I can name any function to be used inside these parens? Or do they have to be these specific names?
    Competition.autonomous( autonomous );
    Competition.drivercontrol( usercontrol );

  2. Why does the main loop have an infinite wait loop at the end of it to prevent exiting? What resources would be wasted if I didn’t have a task::sleep() command in the loop, and why is this particular sleep length chosen?

vex::task::sleep(100);//Sleep the task for a short amount of time to prevent wasted resources.

I am referring to the main function from the competition template as listed below:

int main() {

//Run the pre-autonomous function. 
pre_auton();

//Set up callbacks for autonomous and driver control periods.
Competition.autonomous( autonomous );
Competition.drivercontrol( usercontrol );

//Prevent main from exiting with an infinite loop.                        
while(1) {
  vex::task::sleep(100);//Sleep the task for a short amount of time to prevent wasted resources.
}    

}

1 Like

those two statements run the autonomous and user control sections higher up in the program so that the competition switch can register them. As for the other sleep task not really sure but I know that its something for lower level vcs but you need it for every program in vcs

Thanks.
What does it mean for the competition switch to register the functions named between the parentheses? Is it just copying those function names to call when in each competition mode? Does it matter what the functions are actually named?

Also, I would appreciate someone who knows why the infinite sleep loop is at the end of the main function and the usercontrol function, and why they have different sleep times. Clearly it is NOT needed for every program in vcs since autonomous function doesn’t have them, and I can write main functions that run fine from vcs to the Brain without these infinite loop sleeps.

I’ll write up a detailed explanation tomorrow.

Many thanks! Awaiting enlightenment! I really appreciate your expertise.

yea, sorry, I’m swamped with work, will get to it soon.

Ok, sorry for the delay in replying, not had much time this week for the forum.

VCS implements its competition control using an internal event system we have that’s part of the scheduler we use to run different tasks (threads and tasks are the same internally as far as VCS is concerned). The same event system is used when, for example, you register a callback on a controller button. When an instance of the competition class is created we register events for the three states a robot can be in during a match, disabled, autonomous and driver control.

The lines

//Set up callbacks for autonomous and driver control periods.
Competition.autonomous( autonomous );
Competition.drivercontrol( usercontrol );

are further registering tasks that will be started or stopped when these events trigger (in fact, if your functions are called exactly the same as autonomous or usercontrol they should be registered automatically). For example when the competition switch or field control enables the autonomous phase of the match, an event will be triggered that will then start the registered autonomous task. When the robot is disabled, both registered tasks will be stopped. (a future release of the underlying sdk will allow all tasks and other events you may have created to also be stopped)

There was a certain amount of discussion as to what should happen when the main task exits. Should the entire program stop, including any other tasks the program had created, or should only the main task stop leaving others to run. The present default operation would be to keep other tasks running, I think this is clearer for students and is more in line with how the cortex worked. However, we also have an option where returning from the main task would stop the whole program and return the v5 to the program start screen. So that we don’t cause confusion in the future if we change the default behavior, we generally include a while loop that stops the main task from returning in our example code. There is very little overhead involved in just having the main task sleep, the scheduler that VCS (or rather the sdk that VCS is compiling against) uses can handle many running tasks and events. If we did not have a call to sleep or yield in the while loop the program would be blocked and nothing else would run, this is a limitation of our scheduler. There is no particular reasoning behind the sleep duration it could easily have been chose to be 10mS or 100000mS, however, I often use this part of the program for things like display update and a 100mS delay works well for that.

3 Likes

Thank you jpearmain for finding time to answer these!

If I understand correctly, at the present time with the current sdk, there is not a way for me to selectively stop tasks that I have started. Hopefully, this feature will show up in a release soon.

I’d like to ask what are the reliable ways by which I can know that I’ve stopped all tasks that I’ve started in the current sdk or Brain control? I suspect that some of the strange behaviors that we’ve observed are artifacts from tasks running that we don’t know are still active. I’d like to know how to be sure that I have a clean slate.

You can do that.
I’ll write an explanation later.

I’m just going to throw this code up. It demonstrates a couple of things, how to start and stop tasks, how to monitor competition control to perform actions when the robot goes in and out of enabled. Ask questions as necessary.

#include "robot-config.h"
/*----------------------------------------------------------------------------*/
/*                                                                            */
/*    Module:       main.cpp                                                  */
/*    Author:       james                                                     */
/*    Created:      Tue Feb 26 2019                                           */
/*    Description:  V5 project                                                */
/*                                                                            */
/*----------------------------------------------------------------------------*/
using namespace vex;

// A global instance of vex::competition
vex::competition Competition;

// global variables to store task instances
vex::task armTask;
vex::task driveTask;

// a task started by usercontrol
int
armFunction() {
  int count = 0;
  
  while(true) {
    Brain.Screen.printAt( 10, 70, "Arm task        %6d", count++ );
    // Allow other tasks to run
    this_thread::sleep_for(10);
  }

  return(0);
}

// another task started by usercontrol
int
driveFunction() {
  int count = 0;
  
  while(true) {
    Brain.Screen.printAt( 10, 90, "Drive task      %6d", count++ );
    // Allow other tasks to run
    this_thread::sleep_for(10);
  }

  return(0);
}

//
// This task will monitor the competition status and stop
// other tasks created in usercontrol
int
compMonitor() {
  bool isEnabled;

  while(true) {
    if( Competition.isCompetitionSwitch() || Competition.isFieldControl() ) {
      if( Competition.isEnabled() ) {
        Brain.Screen.printAt( 10, 130, "Comp Enabled" );
        isEnabled = true; 
      }
      else
      if( !Competition.isEnabled() && isEnabled ) {
        Brain.Screen.printAt( 10, 130, "Stop tasks  " );
        armTask.stop();
        driveTask.stop();
        isEnabled = false;
      }
    }
    this_thread::sleep_for(20);
  }

  return(0);
}

/*---------------------------------------------------------------------------*/
/*                          Pre-Autonomous Functions                         */
/*---------------------------------------------------------------------------*/

void pre_auton( void ) {  
}

/*---------------------------------------------------------------------------*/
/*                              Autonomous Task                              */
/*---------------------------------------------------------------------------*/

void autonomous( void ) {
  int count = 0;
  while (1) {
    Brain.Screen.printAt( 10, 50, "Auton  running  %6d", count++ );
    vex::task::sleep(20); //Sleep the task for a short amount of time to prevent wasted resources. 
  }
}

/*---------------------------------------------------------------------------*/
/*                              User Control Task                            */
/*---------------------------------------------------------------------------*/

void usercontrol( void ) {
  int count = 0;

  // start some more tasks
  armTask   = vex::task( armFunction );
  driveTask = vex::task( driveFunction );

  // User control code here, inside the loop
  while (1) {
    Brain.Screen.printAt( 10, 50, "Driver running  %6d", count++ );
    vex::task::sleep(20); //Sleep the task for a short amount of time to prevent wasted resources. 
  }
}

// Main will set up the competition functions and callbacks.
int main() {
    int count = 0;

    //Set up callbacks for autonomous and driver control periods.
    Competition.autonomous( autonomous );
    Competition.drivercontrol( usercontrol );
    
    //Run the pre-autonomous function. 
    pre_auton();

    // start a task to monitor competition control
    vex::task compTask( compMonitor );
   
    //Prevent main from exiting with an infinite loop.                        
    while(1) {
      Brain.Screen.printAt( 10, 30, "Main  %d", count++ );
      vex::task::sleep(100);//Sleep the task for a short amount of time to prevent wasted resources.
    }    
}
5 Likes

I’m a little confused as to what that does

Namespace is a way to provide limited scope for a variable, function, etc. Similar to how a variable you declare in a function does not exist outside of that function, namespace gives you the ability to declare a variable/function/etc that has to be referenced specifically via that namespace.

Anything that you access via the vex:: syntax is in the vex namespace. Adding…

using namespace vex;

…allows you to not use vex:: to access those variables/functions in that namespace.

So with that using statement, you should be able to write:

motor.spin(fwd, 10, pct);

or

motor.spin(vex::directionType::fwd, 10, vex::velocityUnits::pct);

…and have either work the same.

Remove the statement and the first one will not compile since the compiler has no idea where to find the fwd and pct values.

A good way to figure out what a line of code does is to comment it out, compile, and read the errors.

In this case you get :

10:42:47 -- error -- In file included from cxx_entry.cpp:16:
./main.cpp:68:5: error: use of undeclared identifier 'this_thread'; did you mean 'vex::this_thread'?
    this_thread::sleep_for(20);
    ^~~~~~~~~~~
    vex::this_thread
../vexv5/include/vex_thread.h:151:13: note: 'vex::this_thread' declared here
  namespace this_thread {

With a little playing you can see that adding vex:: in front of the this_thread::sleep_for() statements allows it to compile again.

1 Like