Exit Code 2 Help

Hello @holbrook, if you are online, can you help us figure out what “putting the code inside of a function” means? We do not know what the function could be and how to use it.

(this post turned out pretty long but I think some overview of the structure of a VEXcode C++ competition program would be helpful in this case)

Let’s start over from scratch - if you open the C++ competition template in VEXcode V5, this is the code you’ll see:

// Include the V5 Library
#include "vex.h"

// Allows for easier use of the VEX Library
using namespace vex;

// Begin project code

void preAutonomous(void) {
  // actions to do when the program starts
  Brain.Screen.clearScreen();
  Brain.Screen.print("pre auton code");
  wait(1, seconds);
}

void autonomous(void) {
  Brain.Screen.clearScreen();
  Brain.Screen.print("autonomous code");
  // place automonous code here
}

void userControl(void) {
  Brain.Screen.clearScreen();
  // place driver control in this while loop
  while (true) {
    wait(20, msec);
  }
}

int main() {
  // create competition instance
  competition Competition;

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

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

  // Prevent main from exiting with an infinite loop.
  while (true) {
    wait(100, msec);
  }
}

This code contains a series of “function definitions”. A “function” is a section of code that’s packaged up so that it can be executed elsewhere in a program. Functions can take 0 or more values as input, execute some code which may or may not use those input values, and then optionally return some output value. In C++, a function definition takes the following form:

return_type function_name(type1 param1 type2 param2 [...]){
    //body of function
}

where:

  • return_type is the type the function will return
  • function_name is the name of the function (which will be used to call it later)
  • type1 param1 is the type and name of the first parameter
  • type2 param2 is the type and name of the second parameter (and so on, functions can have arbitrarily many parameters)
  • //body of function is some code that defines what the function does, ending with a return statement if the function returns something.

For example, here’s a function that calculates the average of two numbers:

float avg2(float a, float b){
    return (a+b)/2.0;
}

Then, later in our program, we can call the function like this:

float foo = avg2(1.0, 3.0)

After executing that line of code, the variable foo will have a value of whatever the function returned, in this case \frac{(1+3)}{2} = 2.

Now let’s look back at our competition template file. Hopefully you should now see that most of the template is four function definitions: preAutonomous, autonomous, userControl, and main. Let’s look at the definition for preAutonomous:

void preAutonomous(void) {
  // actions to do when the program starts
  Brain.Screen.clearScreen();
  Brain.Screen.print("pre auton code");
  wait(1, seconds);
}

The return type of void indicates that this function does not return anything – we’re just using this function as a convenient way to package multiple lines of code into one single call. The void in the parameter list similarly indicates that the function does not take any parameters. (Incidentally, that second void is optional, you could also have nothing at all between the parens, but explicitly indicating that the function takes no parameters makes your code a bit easier to understand).

Looking at the body of the function, you can see that preAutonomous is meant to contain code that should run right at the beginning of the program. In the template, it just clears the brain’s screen and then prints “pre auton code” on it, but you could add your own code here, for example to calibrate a sensor, reset the value of an encoder, display your own text or graphics on the screen, etc.

The definitions of autonomous and userControl are similar – you can see from the comments that autonomous is meant to contain the code your robot runs during the autonomous period, while userControl should contain the code your robot runs during the driver control period, with an infinite while loop reading joystick values and button pressed from your controller and telling motors to spin at the appropriate speeds based on those inputs.

The fourth function, main, has a special significance. Every C++ program has a function called main with return type int. As far as program flow is concerned, main is your program. main gets called automatically at the beginning of your program, and when the code in main finishes running, your program exits. Therefore, if you want a piece of code to run at any point during your program, it either needs to be in main, or be in a function that gets called by main (or be in a function that gets called by a function that gets called by main, and so on) (with some exceptions – more on that in a bit).

With that in mind, let’s look at the content of main in our competition template:

int main() {
  // create competition instance
  competition Competition;

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

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

  // Prevent main from exiting with an infinite loop.
  while (true) {
    wait(100, msec);
  }
}

The first thing main does is create an object of the competition class called Competition (and yes, those are two different names, case is important). Then, it calls the functions autonomous and drivercontrol, which are both members of the competition class. More on classes in C++ here, but in short, what these lines are doing is telling the robot “run the autonomous function during the autonomous period, and run the userControl function during the driver control period”. The brain’s firmware will then work together with the field control system to start the right code at the right time.

After doing that setup, main calls the preAutonomous function to do whatever setup is needed, and then enters an infinite while loop to keep itself running – remember that we need to keep main running, even if it’s not doing anything, because when main ends the whole program will stop.

So now we have some idea of how the template works – where should your code go?

  • Code that should run at the start of your program goes in the preAutonomous function.
  • Code that should run during the autonomous period should go in the autonomous function.
  • Code that should run during driver control should go in the userControl function.
  • Any additional custom functions that get called by any of the above code should go at the “root level” of the program, i.e., not inside any function.
  • Global variables can also go at the root level of the program.

The fundamental problem with your code is that you did not maintain the structure of the competition template. In particular, the definition of main in your code had an extraneous semicolon, and was also inside another function, which is not where it should go. Since every C++ program needs a main, having this function incorrectly defined will result in your program failing to compile.

The solution will be to start over from a new competition template, adding the functionality you want by putting code in the appropriate places.

10 Likes