We’ve been using LCD menu code from VEX Forum member Ephemeral_Being for quite some time now; we are eternally grateful for his contribution. In this post I walk through each step of what his code does and how you can use it on your robot.

Benefits Over Other Algorithms

Why do we love this code? Unlike most other LCD menu code that I’ve encountered, this one give 100% unambiguous feedback about the option you have selected, AND allows you to change your mind if you pressed the wrong thing. It is still “live” for the entire pre-autonomous period, and automatically shuts off when auton starts.

It’s also easy to modify for your own robot with minimal effort, and uses simple if-else statements to do the work.

It’s Not Just for Auton Selectors!

You can also set one of your menu options to display the value of a sensor (in lieu of it assigning an auton pattern). We have used this option in the past to make sure that a given sensor was reset to 0 before the match started; another time, we had it display the value from an ultrasonic sensor, which helped the drive team line up the robot when placing it on the field. This ultrasonic option is shown below as the last menu choice.

Using the LCD Menu Code

In the example presented here, let’s say that I want to have 3 auton driving patterns: auton1, auton2, and the third one I call noAuton. In the past, we’ve been with alliance partners that had fantastic, high-scoring auton; they asked us to make our robot sit still during those 15 seconds so that we would not collide with them accidentally. So, it’s nice to be able to turn off auton without re-downloading a program in the pits (and then downloading another one later, when you want to turn it back on for the next match).

One of the menu options my team has always included in the menu has been our programming skills code. That way, there’s no need to download a new program while at the competition; everything is already on the robot, ready for use (particularly helpful when there’s not a lot of time between matches to do your skills runs!).

For this whole algorithm to work, your robot must be connected to field control (or a competition switch) that is set to “Disabled.”

1. Define a Global Variable

Before your pre-autonomous section, define a global variable that will store the information about which driving pattern has been selected. It must be a global variable so that it can be set in pre-auton and referenced in auton.

// Define it and set it here to your default pattern. 
// If someone forgets to press a button, the #1
// pattern will execute
int autonProgram = 1;

2. Set Up Your Auton Patterns

First, put each of your auton driving patterns into a separate function, placed before the pre-autonomous section of the competition template, like so:

void auton1() {
 // all of your pattern #1 auton
 // driving here
}
void auton2() {
 // all of your pattern #2 auton
 // driving here
}
void noAuton() {
 // optional; turns off auton completely
 // It’s just an empty function, with no code
}
// add other auton patterns here, each in its own function

3. Pre-Autonomous Code: The Workhorse

In your pre-autonomous section, you’d have the following code. Stuff below is explained with comments for auton1; auton2 and noAuton are not commented. I use extensive comments below in lieu of descriptive text here.

Important item to remember: The screen can only display 16 characters on each line. Make sure your message—including spaces—does not exceed 16 characters.

void pre_auton() {
   // Set bDisplayCompetitionStatusOnLcd to false if you don't
   // want the LCDused by the competition include file, for 
   // example, you might want to display your team name on 
   // the LCD in this function.
   bDisplayCompetitionStatusOnLcd = false;

   // Leave this value alone; counting starts at 1
   int lcdScreenMin = 1;
   // Total # menu items
   int lcdScreenMax = 4;

   // Counter for what to display on the screen
   int lcdScreen = 1;

   //Turns on the Backlight
   bLCDBacklight = true;

   // Leave these values alone
   // In RobotC:
   // when the left button is pressed, nLCDButtons = 1
   // when middle button is pressed, nLCDButtons = 2
   // when right button is pressed, nLCDButtons = 4
   const short leftButton = 1;
   const short centerButton = 2;
   const short rightButton = 4;

   // This main loop will run as long at the competition
   // switch is set to “Disabled”; When the system is
   // set to “Enable” this loop will automatically stop.
   while (bIfiRobotDisabled == 1) {

   // This section checks whether left & right buttons are
   // pressed, and either increments or decrements the 
   // lcdScreen counter; if the counter is at the max or min
   // it will loop around to the other end

     // left button
     if (nLCDButtons == leftButton) {
       if (lcdScreenMin == lcdScreen) {
         lcdScreen = lcdScreenMax;
         wait1Msec(250);
       } 
       else {
         lcdScreen--;
         wait1Msec(250);
       }
     }
   
     // right button
     if (nLCDButtons == rightButton) { 
        if (lcdScreenMax == lcdScreen) {
          lcdScreen = lcdScreenMin;
          wait1Msec(250);
        }
        else {
          lcdScreen++;
          wait1Msec(250);
        }
     }

   // The rest of pre-auton checks to see whether the middle
   // button is pressed

   // Each menu item below has 2 blocks of code, depending on
   // whether you've already selected this option, or not

   // If you have not already selected this option as 
   // your choice, it will display the text normally, and will
   // then check to see if you're pressing the middle button. 
     if (lcdScreen == 1 && autonProgram != 1) {
        displayLCDCenteredString (0, "Default Auton");
        // put more text on 2nd line if you want
        displayLCDCenteredString (1, ""); 

        // When you press the middle button, the screen says,  
        // “Blah blah has / been selected!” for 1.5 seconds
        // and also sets the autonProgram variable
        if (nLCDButtons == centerButton) {
          autonProgram = lcdScreen; 
          displayLCDCenteredString (0, "DefaultAuton Has");
          displayLCDCenteredString (1, "Been Selected!");
          wait1Msec(1500);
        }
     }

     // If you have already selected this item, the menu 
     // text will have [square brackets] around it  
     // to indicate that this is the option you’ve chosen.
     else if (lcdScreen == 1 && autonProgram == 1) {
        displayLCDCenteredString (0, "[Default Auton]"); 
        displayLCDCenteredString (1, "");
     }
    
 //------------------------------------------------------------

     else if (lcdScreen == 2 && autonProgram != 2) {
        displayLCDCenteredString (0, "Skills"); 
        displayLCDCenteredString (1, “Challenge”); 
        if (nLCDButtons == centerButton) {
          autonProgram = lcdScreen; 
          displayLCDCenteredString (0, "Skills Has");
          displayLCDCenteredString (1, "Been Selected!");
          wait1Msec(1500);
        }
     } 
     else if (lcdScreen == 2 && autonProgram == 2) {
        displayLCDCenteredString (0, "[Skills"); 
        displayLCDCenteredString (1, “Challenge]”);
     }
 
 //-------------------------------------------------------------

     else if (lcdScreen == 3 && autonProgram != 3) {
        displayLCDCenteredString (0, "No-Auton"); 
        displayLCDCenteredString (1, "");
        if (nLCDButtons == centerButton) {
          autonProgram = lcdScreen; 
          displayLCDCenteredString (0, "No-Auton Has");
          displayLCDCenteredString (1, "Been Selected!");
          wait1Msec(1500);
        }
     } 
     else if (lcdScreen == 3 && autonProgram == 3) {
        displayLCDCenteredString (0, "[No-Auton]");
        displayLCDCenteredString (1, ""); 
     }
 //------------------------------------------------------------

     // this last menu option does not set the autonProgram
     // variable, but rather displays the value of a sensor 
     // that is useful for the drive team to see in pre-auton
     else if (lcdScreen == 4 ) {
        displayLCDCenteredString (0,"Ultrasonic Val");
        displayLCDNumber(1, 0,SensorValue[myUltrasonic], -1);
     }
   } // end of while-disabled loop
} // end of pre-auton

4. Your Autonomous Code

Your autonomous section will be very short if you use this setup. It merely checks to see what the autonProgram variable has been set to, and executes the appropriate pattern from your functions above.

task autonomous() {
   // turn off backlight for match play
   bLCDBacklight = false;

   if(autonProgram == 1){
     auton1();
   }
   else if(autonProgram == 2){
     auton2();
   }
   else if(autonProgram == 3){
     noAuton();
   }
}

♦        ♦        ♦

Again, Why We Love This Code

HeartI hope that you find the above description helpful and hope that you give it a try.

  • It’s as close to plug-and-play as you can get (just add your menu items above, and copy/paste to make more options).
  • It’s as close to fool-proof as you can get (it will execute your default pattern if you forget to press a button).
  • It uses simple if/else-if statements and does NOT require
    • fancy data structures,
    • “wait for press”/”wait for release” functions (simple wait1Msec statements are used instead), or
    • case/switch coding.
  • It allows you to change your mind or correct an accidental button-press.
  • It allows you to display sensor values that are useful for the drive team to know.
  • And, you don’t actually care if the code is hogging the CPU or not, since it’s pre-autonomous, and the robot isn’t being asked to do anything else.

To find Ephemeral_Being‘s RobotC code, see the first response to this post (NOTE: he has a small error in this code for the while-disabled statement. Be sure to use the code shown here for that statement; you’ll see the correction if you read later in the thread). Ephemeral_Being’s easyC and PROS files can be downloaded from this other VEX Forum thread.

For more information about the LCD screen itself and how to use it on your robot, please see my LCD screen post.

LCD Screen humor

Share this post: