Why PROS?

VEX robots run on a V5 Brainโ€”a 32-bit ARM processor running at 400 MHz. You can program it with VEXcode (a beginner-friendly IDE), but for competition-level code teams use PROS (Purdue Robotics Operating System).

PROS gives you:

Why LemLib?

LemLib is an open-source motion-control library built on top of PROS. It provides:

In this codebase, the Chassis class extends lemlib::Chassis to add custom distance-reset methods (covered in depth later).

Installation

  1. Install PROS CLI.
    Download the installer for your OS from pros.cs.purdue.edu or install via pip:
    pip install pros-cli
  2. Install the VS Code extension.
    Search for "PROS" in the VS Code Extensions marketplace and install it. It wraps the CLI and gives you one-click upload.
  3. Create a new project.
    pros conduct new-project my-robot --target v5 --version latest
    This scaffolds:
    my-robot/
    โ”œโ”€โ”€ include/
    โ”‚   โ”œโ”€โ”€ main.h       โ† PROS entry-point header
    โ”‚   โ””โ”€โ”€ api.h        โ† full PROS API
    โ”œโ”€โ”€ src/
    โ”‚   โ””โ”€โ”€ main.cpp     โ† initialize, autonomous, opcontrol stubs
    โ”œโ”€โ”€ Makefile
    โ””โ”€โ”€ project.pros
  4. Add the LemLib template.
    cd my-robot
    pros conduct add-depot https://lemlib.github.io/LemLib/depot.json
    pros conduct apply LemLib
    This downloads LemLib headers into include/lemlib/ and the library binary into firmware/.
  5. Build and upload.
    pros make          # compile
    pros upload        # send to Brain over USB
    Or use the PROS VS Code extension's toolbar buttons.

Project Entry Points

PROS defines four callback functions that you fill in:

FunctionWhen it runsTypical use
initialize()Immediately on power-onCalibrate sensors, start background tasks, show LCD
disabled()Robot disabled by FMS/switchUsually empty
competition_initialize()Connected to FMS, before autonAuton selector
autonomous()15-second auton periodRun the selected auton routine
opcontrol()1:45 driver control periodRead controller, drive motors

Here is the minimal initialize() from this robot:

src/main.cppvoid initialize() {
  pros::lcd::initialize();   // Start brain LCD display
  chassis.calibrate();        // Zero IMU + tracking wheels
  pros::delay(100);

  // GPS sensor physical offset from robot center (converted m โ†’ inches)
  gps.set_offset(.75/39.37008, 4.5/39.37008);
  chassis.setPose(0, 0, 0);  // Starting position is the origin

  optical.set_integration_time(20); // Fast color sampling (ms)
  optical.set_led_pwm(100);

  // Background task: print robot state to LCD every 50 ms
  pros::Task screen_task([&]() {
    while (true) {
      pros::lcd::print(2, selectedAuton.c_str());
      pros::lcd::print(5, "X: %f", chassis.getPose().x);
      pros::lcd::print(6, "Y: %f", chassis.getPose().y);
      pros::lcd::print(7, "Theta: %f", chassis.getPose().theta);
      pros::delay(50);
    }
  });

  pros::lcd::register_btn1_cb(on_center_button); // Auton selector button
}
โœ…
Always call chassis.calibrate() in initialize(). This zeros the inertial sensor and tracking wheel encoders. Skipping it means your heading will be wrong from the very first movement.