ROBOTC LCD autonomous selection


#1

We seem to have a lot of questions this year on how to use the LCD to select different autonomous routines for your robot. I’m going to present several examples, each of which is going to increase in complexity, the first three of which are here, there may be more later.

Most code that uses the LCD to allow autonomous selection has common features.

  1. Choices are presented to the user, these can be simple or a complex series of menus.

  2. The code must monitor button presses and releases on the LCD display.

  3. The code must be aware of the competition state so that the autonomous task may run.

Item 2 is one of the most basic functions that the code must perform. A user will press an LCD button, this is detected and causes the code to take some action, the code then must generally wait for the button to be released so the action does not happen multiples times in quick succession. To help simplify the LCD selection code I decided to create a wrapper for this most basic function that combines LCD button press detection and also waiting for button release. It also needs to be aware of the competition state so that it does not block (that means wait in a loop forever). This function is saved in its own file and “included” in the code for the three demo’s, here is the function.

// Wrap code with definition so it's not included more than once
#ifndef  _GETLCDBUTTONS
#define  _GETLCDBUTTONS

// Some utility strings
#define LEFT_ARROW  247
#define RIGHT_ARROW 246
static  char l_arr_str[4] = { LEFT_ARROW,  LEFT_ARROW,  LEFT_ARROW,  0};
static  char r_arr_str[4] = { RIGHT_ARROW, RIGHT_ARROW, RIGHT_ARROW, 0};

/*-----------------------------------------------------------------------------*/
/*  This function is used to get the LCD hutton status but also acts as a      */
/*  "wait for button release" feature.                                         */
/*  Use it in place of nLcdButtons.                                            */
/*  The function blocks until a button is pressed.                             */
/*-----------------------------------------------------------------------------*/

// Little macro to keep code cleaner, masks both disable/ebable and auton/driver
#define vexCompetitionState (nVexRCReceiveState & (vrDisabled | vrAutonomousMode))

TControllerButtons
getLcdButtons()
{
    TVexReceiverState   competitionState = vexCompetitionState;
    TControllerButtons  buttons;
    
    // This function will block until either
    // 1. A button is pressd on the LCD
    //    If a button is pressed when the function starts then that button
    //    must be released before a new button is detected.
    // 2. Robot competition state changes
    
    // Wait for all buttons to be released
    while( nLCDButtons != kButtonNone ) {
        // check competition state, bail if it changes
        if( vexCompetitionState != competitionState )
            return( kButtonNone );
        wait1Msec(10);
        }
    
    // block until an LCD button is pressed
    do  {
        // we use a copy of the lcd buttons to avoid their state changing
        // between the test and returning the status
        buttons = nLCDButtons;
        
        // check competition state, bail if it changes
        if( vexCompetitionState != competitionState )
            return( kButtonNone );

        wait1Msec(10);
        } while( buttons == kButtonNone );

    return( buttons );
}

#endif  // _GETLCDBUTTONS

The functionality of this code, in pseudo code form, is as follows.

Wait for all buttons to be released unless
    the robot is enabled which causes exit

Wait for a button press unless
   the robot is enabled which causes exit

return the pressed button

Demo 1

This allows selection of one of three autonomous routines, the three LCD buttons are used to make that selection. The code separates the display of the choices and selected routine from the selection of that routine.

/*-----------------------------------------------------------------------------*/
/*  LCD autonomous demo 1                                                      */
/*  Copyright (c) 2013 James Pearman                                           */
/*  This is unlicensed software - you may modify and use as you wish           */
/*-----------------------------------------------------------------------------*/

//Competition Control and Duration Settings
#pragma competitionControl(Competition)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!

// Include the lcd button get utility function
#include "getlcdbuttons.c"

// global hold the auton selection
static int MyAutonomous = 0;

/*-----------------------------------------------------------------------------*/
/*  Display autonomous selection                                               */
/*-----------------------------------------------------------------------------*/
void
LcdSetAutonomous( int value )
{
    // Simple selection display
    if( value == 0 ) {
        displayLCDString(0, 0, "auton 0");
        displayLCDString(1, 0, "[00]   01    02 ");
        }
    if( value == 1 ) {
        displayLCDString(0, 0, "auton 1");
        displayLCDString(1, 0, " 00   [01]   02 ");
        }
    if( value == 2 ) {
        displayLCDString(0, 0, "auton 2");
        displayLCDString(1, 0, " 00    01   [02]");
        }
        
    // Save autonomous mode for later
    MyAutonomous = value;
}

/*-----------------------------------------------------------------------------*/
/*  Select one of three autonomous choices                                     */
/*-----------------------------------------------------------------------------*/

void
LcdAutonomousSelection()
{
    TControllerButtons  button;
    
    // Clear LCD and turn on backlight
    clearLCDLine(0);
    clearLCDLine(1);
    bLCDBacklight = true;
    
    // diaplay default choice
    LcdSetAutonomous(0);
    
    while( bIfiRobotDisabled )
        {
        // this function blocks until button is pressed
        button = getLcdButtons();    
        
        // Display and select the autonomous routine
        if( button == kButtonLeft )
            LcdSetAutonomous(0);
        
        if( button == kButtonCenter )
            LcdSetAutonomous(1);
        
        if( button == kButtonRight )
            LcdSetAutonomous(2);
        
        // Don't hog the cpu !
        wait1Msec(10);
        }
}

void pre_auton()
{
    bStopTasksBetweenModes = true;

    LcdAutonomousSelection();
}


task autonomous()
{
    switch( MyAutonomous ) {
        case    0:
            // run auton code
            break;
        
        case    1:
            // run some other auton code
            break;
        
        default:
            break;
        }
}

task usercontrol()
{
    while (true) {
        wait1Msec(10);
        }
}

A global called MyAutonomous stores the selected choice, you would run a different autonomous routine depending if it was 0, 1 or 2. The selection function is called in pre_auton() and will run until the robot is enabled, it does not run again unless the cortex is power cycled.

Demo 2 will be in the next post

The three programs are attached as a zip file so you don’t have to cut and paste from the forum.
lcdDemos.zip (4.89 KB)


LCD Screen Fool Proof
#2

Demo 2

Very similar to Demo_1 but allows more than three choices.

/*-----------------------------------------------------------------------------*/
/*  LCD autonomous demo 2                                                      */
/*  Copyright (c) 2013 James Pearman                                           */
/*  This is unlicensed software - you may modify and use as you wish           */
/*-----------------------------------------------------------------------------*/

//Competition Control and Duration Settings
#pragma competitionControl(Competition)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!

// Include the lcd button get utility function
#include "getlcdbuttons.c"

// global hold the auton selection
static int MyAutonomous = 0;

/*-----------------------------------------------------------------------------*/
/*  Display autonomous selection                                               */
/*-----------------------------------------------------------------------------*/

// max number of auton choices
#define MAX_CHOICE  3

void
LcdAutonomousSet( int value, bool select = false )
{
    // Cleat the lcd
    clearLCDLine(0);
    clearLCDLine(1);
    
    // Display the selection arrows
    displayLCDString(1,  0, l_arr_str);
    displayLCDString(1, 13, r_arr_str);

    // Save autonomous mode for later if selected
    if(select)
        MyAutonomous = value;

    // If this choice is selected then display ACTIVE
    if( MyAutonomous == value )
        displayLCDString(1, 5, "ACTIVE");
    else
        displayLCDString(1, 5, "select");
        
    // Show the autonomous names
    switch(value) {
        case    0:    
            displayLCDString(0, 0, "auton 0");
            break;
        case    1:    
            displayLCDString(0, 0, "auton 1");
            break;
        case    2:    
            displayLCDString(0, 0, "auton 2");
            break;
        case    3:    
            displayLCDString(0, 0, "auton 3");
            break;
        default:
            displayLCDString(0, 0, "Unknown");
            break;
        }      
}

/*-----------------------------------------------------------------------------*/
/*  Rotate through a number of choices and use center button to select         */
/*-----------------------------------------------------------------------------*/

void
LcdAutonomousSelection()
{
    TControllerButtons  button;
    int  choice = 0;
    
    // Turn on backlight
    bLCDBacklight = true;
    
    // diaplay default choice
    LcdAutonomousSet(0);
    
    while( bIfiRobotDisabled )
        {
        // this function blocks until button is pressed
        button = getLcdButtons();    
        
        // Display and select the autonomous routine
        if( ( button == kButtonLeft ) || ( button == kButtonRight ) ) {
            // previous choice
            if( button == kButtonLeft )
                if( --choice < 0 ) choice = MAX_CHOICE;
            // next choice
            if( button == kButtonRight )
                if( ++choice > MAX_CHOICE ) choice = 0;
            LcdAutonomousSet(choice);
            }

        // Select this choice    
        if( button == kButtonCenter )
            LcdAutonomousSet(choice, true );            
        
        // Don't hog the cpu !
        wait1Msec(10);
        }
}

void pre_auton()
{
    bStopTasksBetweenModes = true;

    LcdAutonomousSelection();
}


task autonomous()
{
    switch( MyAutonomous ) {
        case    0:
            // run auton code
            break;
        
        case    1:
            // run some other auton code
            break;
        
        default:
            break;
        }
}

task usercontrol()
{
    while (true) {
        wait1Msec(10);
        }
}

The LCD left and right button select different autonomous routines and the center button makes that routine active.


#3

Demo 3

This demo shows the beginnings of a menu system.

The left and right LCD buttons select different menu pages, the center LCD button changes the selection on that page. There is a page for the alliance color, a page for the starting position and finally a page for selecting the autonomous routine for that position. Obviously I don’t have any real auton code in these demo programs, just place holders you can fill in.

Three globals are used for storing this information.

static  vexAlliance         vAlliance = kAllianceBlue;
static  vexStartposition    vPosition = kStartHanging;
static  short               vAuton = 0;

These are than used in the autonomous task to first select function for red or blue, and then which of presumably many autonomous functions you have. This code still only runs once and is started in pre_auton().

/*-----------------------------------------------------------------------------*/
/*  LCD autonomous demo 3                                                      */
/*  Copyright (c) 2013 James Pearman                                           */
/*  This is unlicensed software - you may modify and use as you wish           */
/*-----------------------------------------------------------------------------*/

//Competition Control and Duration Settings
#pragma competitionControl(Competition)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!

// Include the lcd button get utility function
#include "getlcdbuttons.c"

/*-----------------------------------------------------------------------------*/
/*  Definition of the menus and global variables for the autonomous selection  */
/*-----------------------------------------------------------------------------*/

typedef enum {
    kAllianceBlue = 0,
    kAllianceRed
} vexAlliance;
    
typedef enum {
    kStartHanging = 0,
    kStartMiddle
} vexStartposition;

typedef enum {
    kMenuStart    = 0,
    
    kMenuAlliance = 0,
    kMenuStartpos,
    kMenuAutonSelect,
    
    kMenuMax
} vexLcdMenus;

static  vexAlliance         vAlliance = kAllianceBlue;
static  vexStartposition    vPosition = kStartHanging;
static  short               vAuton = 0;

/*-----------------------------------------------------------------------------*/
/*    Display menus and selections                                             */
/*-----------------------------------------------------------------------------*/

void
LcdAutonomousDisplay( vexLcdMenus menu )
{
    // Cleat the lcd
    clearLCDLine(0);
    clearLCDLine(1);
    
    // Display the selection arrows
    displayLCDString(1,  0, l_arr_str);
    displayLCDString(1, 13, r_arr_str);
    displayLCDString(1,  5, "CHANGE");
        
    // Show the autonomous names
    switch( menu ) {
        case    kMenuAlliance:    
            if( vAlliance == kAllianceBlue )
                displayLCDString(0, 0, "Alliance - BLUE");
            else
                displayLCDString(0, 0, "Alliance - RED");
            break;
        case    kMenuStartpos:    
            if( vPosition == kStartHanging )
                displayLCDString(0, 0, "Start - Hanging");
            else
                displayLCDString(0, 0, "Start - Middle");
            break;
        case    kMenuAutonSelect:
            switch( vAuton ) {
                case    0:
                    displayLCDString(0, 0, "Default");
                    break;
                case    1:
                    displayLCDString(0, 0, "Special 1");
                    break;
                default:
                    char    str[20];
                    sprintf(str,"Undefined %d", vAuton );
                    displayLCDString(0, 0, str);
                    break;
                }
            break;
            
        default:
            displayLCDString(0, 0, "Unknown");
            break;
        }      
}

/*-----------------------------------------------------------------------------*/
/*  Rotate through a number of menus and use center button to select choices   */
/*-----------------------------------------------------------------------------*/

void
LcdAutonomousSelection()
{
    TControllerButtons  button;
    vexLcdMenus  menu = 0;
    
    // Turn on backlight
    bLCDBacklight = true;
    
    // diaplay default choice
    LcdAutonomousDisplay(0);
    
    while( bIfiRobotDisabled )
        {
        // this function blocks until button is pressed
        button = getLcdButtons();    
        
        // Display and select the autonomous routine
        if( ( button == kButtonLeft ) || ( button == kButtonRight ) ) {
            // previous choice
            if( button == kButtonLeft )
                if( --menu < kMenuStart ) menu = kMenuMax-1;
            // next choice
            if( button == kButtonRight )
                if( ++menu >= kMenuMax ) menu = kMenuStart;
            }

        // Select this choice for the menu  
        if( button == kButtonCenter )
            {
            switch( menu ) {
                case    kMenuAlliance:
                    // alliance color
                    vAlliance = (vAlliance == kAllianceBlue) ? kAllianceRed : kAllianceBlue;
                    break;
                case    kMenuStartpos:
                    // start position
                    vPosition = (vPosition == kStartHanging) ? kStartMiddle : kStartHanging;
                    break;
                case    kMenuAutonSelect:
                    // specific autonomous routine for this position
                    if( ++vAuton == 3 )
                        vAuton = 0;
                    break;
                }

            }
   
        // redisplay
        LcdAutonomousDisplay(menu);
        
        // Don't hog the cpu !
        wait1Msec(10);
        }
}

void pre_auton()
{
    bStopTasksBetweenModes = true;

    LcdAutonomousSelection();
}

void
autonomousRed()
{
    // code is the same as the blue code
}

void
autonomousBlue()
{
    if( vPosition == kStartHanging ) {
        switch( vAuton ) {
            case    0:
                // run some autonomous code
                break;
            case    1:
                // run some other autonomous code
                break;
            default:
                break;
        }
    }
    else { // middle zone
        switch( vAuton ) {
            case    0:
                // run some autonomous code
                break;
            case    1:
                // run some other autonomous code
                break;
            default:
                break;
        }
    }   
}

task autonomous()
{
    if( vAlliance == kAllianceBlue )
        autonomousBlue();
    else
        autonomousRed();
}

task usercontrol()
{
    while (true) {
        wait1Msec(10);
        }
}

So that’s it for today, perhaps I will show an example using a task later in the week.


#4

Thanks for the great ideas on how to use the LCD to select Autonomous.


#5

Demo 4

One more today.

This is a revised version of Demo 3 that allows the LCD selection code be be available every time the robot goes to the disabled state. This is more useful for testing autonomous code as a routine can be run, the robot disabled, another routine selected and then tested.

One of the problems with the default ROBOTC competition template is that it wants to use the LCD when the robot is disabled, there are two ways around this, either modify Vex_Competition_Includes.c (not so good) or replace the default competition control code with user code. This demo uses the second method, a task is started in the pre_auton() function that mimics the competition control code in Vex_Competition_Includes.c. Every time the robot is disabled the LcdAutonomousSelection() is called which will then block until the robot is again enabled. The code also displays the autonomous or usercontrol status when the robot becomes enabled. The autonomous selection code is identical to demo 3.

I’m only showing the changes here, the 10000 character post limit won’t allow everything so I’m attaching the file.

/*-----------------------------------------------------------------------------*/
/*  LCD autonomous demo 4                                                      */
/*  Copyright (c) 2013 James Pearman                                           */
/*  This is unlicensed software - you may modify and use as you wish           */
/*-----------------------------------------------------------------------------*/

///// Code removed to fit the forum limits.

/*-----------------------------------------------------------------------------*/
/*  Display some status during Autonomous or driver controlled periods         */
/*-----------------------------------------------------------------------------*/

void
LcdDisplayStatus( long enabledTime )
{
    string str;

    sprintf(str,"VBatt %7.2f   ", nAvgBatteryLevel/1000.0 );
    displayLCDString(0, 0, str);
    if( bIfiAutonomousMode )
        sprintf(str, "Autonomous %.2f", (nPgmTime-enabledTime)/1000.0);
    else
        sprintf(str, "Driver     %.2f", (nPgmTime-enabledTime)/1000.0);
    displayLCDString(1, 0, str);
}

/*-----------------------------------------------------------------------------*/
/*  This task replaces the default competition control                         */
/*  It is started during pre_auton() and does not terminate                    */
/*  pre_auton also does not return and run the remaining code in the "main"    */
/*  task that is part of Vex_Competition_Includes.c                            */
/*                                                                             */
/*  This task does not stop other tasks when the robot is disable, that's up   */
/*  to the user to modify and add, using allTasksStop() is not recommended as  */
/*  it will also stop this task, allTasksStop stops everything except main     */
/*-----------------------------------------------------------------------------*/

task mainTask()
{
    long    enabledTime;
    
    while( true )
        {
        // When disabled run the autonomous selector
        if( bIfiRobotDisabled )    
            LcdAutonomousSelection();
        else   
            {
            // time we were enabled
            enabledTime = nPgmTime;
            
            // when enabled run either autonomous or usercontrol
            if (bIfiAutonomousMode)
                {
                StartTask(autonomous);
        
                // Waiting for autonomous phase to end
                while (bIfiAutonomousMode && !bIfiRobotDisabled) {
                    if (!bVEXNETActive) {
                        if (nVexRCReceiveState == vrNoXmiters) // the transmitters are powered off!!
                            allMotorsOff();
                        }

                    // Status display during autonomous
                    LcdDisplayStatus(enabledTime);

                    // Waiting for autonomous phase to end
                    wait1Msec(25);  
                    }
                    
                allMotorsOff();
                
                // Stop other taks here
                // if needed
                }
            else
                {
                StartTask(usercontrol);
        
                // Here we repeat loop waiting for user control to end and (optionally) start
                // of a new competition run
                while (!bIfiAutonomousMode && !bIfiRobotDisabled) {
                    if (nVexRCReceiveState == vrNoXmiters) // the transmitters are powered off!!
                        allMotorsOff();

                    // Status display during usercontrol
                    LcdDisplayStatus(enabledTime);
                    
                    wait1Msec(25);
                    }
                    
                allMotorsOff();

                // Stop other taks here
                // if needed
                }
            }
        }
}

/*-----------------------------------------------------------------------------*/
/* The pre_auton function does not return, "normal" competition control is     */
/* therefore disabled.                                                         */
/*-----------------------------------------------------------------------------*/

void pre_auton()
{
    // start our own main task
    startTask( mainTask );
    
    // now block - use our own comp control
    while(1) wait1Msec(1000);
}


lcdAutonDemo_4.c (9.63 KB)


#6

Is there any hanse you know how to display the battery power as a percentage?


#7

Well, we know that the vex batteries are 7.2 Volts, but can sometimes get up to 8V so what you can do, is take the current voltage, and divide it by 7.2 which will give you decimal, then multiply by 100, and add a % sign, and then you can build that value to be displayed on LCD screen.

Give this a try!


    displayLCDString(0, 0, "P:");
    sprintf(mainBattery, "%1.2f%c", (((float)nImmediateBatteryLevel / 1000.0) / 7.2)*100, '%'); //Build the value to be displayed
    displayNextLCDString(mainBattery);


#8

Would you want to divide by 7.2? When the battery is at 7.2 doesn’t it still have quite a bit of usable charge left?

I suppose one could argue 7.2 would be the “safe” way to go I guess, but it seems like you could use a lower voltage…although I don’t know at what voltage the VEX batteries are basically dead.


#9

I’d say about 5.2 V is the lowest I’ve gotten one, while still working.


#10

Not sure how useful displaying voltage as percentage really is, the voltage will drop when under load, however. You also really want to remove the low voltage point from the reading, it’s like an offset.

#define BATTERY_LOW     6.5
#define BATTERY_HIGH    8.0

task main()
{
    float   battery_remain;
    char    str[32];
    
    bLCDBacklight = true;
    clearLCDLine(0);
    
    while(1)
        {
        battery_remain = ((nImmediateBatteryLevel / 1000.0) - BATTERY_LOW) / (BATTERY_HIGH - BATTERY_LOW) * 100.0;

        sprintf(str,"%4.1f %4.1f", nImmediateBatteryLevel / 1000.0, battery_remain);  
        displayLCDString( 0, 1, str);
        
        wait1Msec(10);
        } 
}

Please start a new thread for this type of question next time, just keeps things a little cleaner.


#11

First, thank you very much for your knowledge and willingness to share/help. I’ve used the “getlcdbuttons.c” include and the Demo 2 code provided as a template to create our autonomous selection. It only has one issue. Once autonomous is run, there’s no way to get back to the selection screen. Upon disable, It goes to a “Disabled timer”. I’m assuming this is because the pre_auton task only runs on startup. This is troublesome in a couple situations. One is that with the 9v in the cortex often does not lose power even when turned off. Second is that during testing its often necessary to rerun it multiple times I would be ideal if it could be re-initialized upon disable (showing currently active). Is there a way to trigger the LcdAutonomousSelection() upon disable also?


#12

I have tried using your demo four in my robot. Everything functions perfectly until enabling autonomous. Upon being enabled the motors kind of glitch out and only move twice for fractions of a second. Is there anything I have done wrong to cause this? I have another autonomous switcher ready, but I really like the idea of menus and would like to use this one if at all possible. I have attached my code file below. If you could help it would be greatly appreciated! Thank you!
Amazable 6.0.zip (3.24 KB)


#13

See if this version of the main task is any better. The Demo 4 code did not stop the autonomous or user control tasks (this being old code will also throw a few warnings). Are you using a real competition switch?

task mainTask()
{
    long    enabledTime;

    while( true )
        {
        if( bIfiRobotDisabled )
            LcdAutonomousSelection();
        else
            {
            // time robot was enabled
            enabledTime = nPgmTime;

            if (bIfiAutonomousMode)
                {
                StartTask(autonomous);

                // Waiting for autonomous phase to end
                while (bIfiAutonomousMode && !bIfiRobotDisabled) {
                    if (!bVEXNETActive) {
                        if (nVexRCReceiveState == vrNoXmiters) // the transmitters are powered off!!
                            allMotorsOff();
                        }

                    // Status display during autonomous
                    LcdDisplayStatus(enabledTime);

                    // Waiting for autonomous phase to end
                    wait1Msec(25);
                    }

                allMotorsOff();

                // Stop other tasks here such as sensors
                StopTask(autonomous);
                }
            else
                {
                StartTask(usercontrol);
                while (!bIfiAutonomousMode && !bIfiRobotDisabled) {
                    if (nVexRCReceiveState == vrNoXmiters)
                        allMotorsOff();

                    // Status display during usercontrol
                    LcdDisplayStatus(enabledTime);

                    wait1Msec(25);
                    }

                allMotorsOff();

                // Stop other tasks here such as sensors
                StopTask(usercontrol);
                }
            }
        }
}


#14

Thank you very much, I will test it tomorrow during class:). Also yes the competition switch is purchased directly from vex.


#15

Btw thank you so much for responding! It means a lot to me and my team:)


#16

You are welcome, if that doesn’t work out I will look again.


#17

Dear @jpearman
Hi! I tried using some of your earlier codes(Demo 1, Demo 3, Demo 4) and got about 5 obscure errors(the red kind) that I can’t seem to discover the problem with. Do you have any idea what it might be? Our version of RobotC should be up to date… I have attached a picture of the error if that helps.

P.S. The image is for Demo 4.

Thanks,
Aragon17
Capture.PNG


#18

That is happening because it is not finding the include file “getlcdbuttons.c”. Place your code and the getlcdbuttons.c files in the same folder and try try to compile.
(getlcdbuttons.c was included with The original three demo programs but not demo4)

You will still get some warnings, this code was written over 4 years ago and ROBOTC has changed a little. To remove the warnings, change “StartTask” into “startTask” (non capitalized).

Replace 0 with kMenuStart on line 103

void
LcdAutonomousSelection()
{
    TControllerButtons  button;
    vexLcdMenus  menu = kMenuStart;

Update the three enumerated types as follows.

/*-----------------------------------------------------------------------------*/
/*  Definition of the menus and global variables for the autonomous selection  */
/*-----------------------------------------------------------------------------*/

typedef enum _vexAlliance {
    kAllianceBlue = 0,
    kAllianceRed
} vexAlliance;

typedef enum _vexStartposition {
    kStartHanging = 0,
    kStartMiddle
} vexStartposition;

typedef enum _vexLcdMenus {
    kMenuStart    = 0,

    kMenuAlliance = 0,
    kMenuStartpos,
    kMenuAutonSelect,

    kMenuMax
} vexLcdMenus;


#19

Thanks, your advice fixed all the warnings but even after placing getlcdbuttons.c in the same folder as the demo four code, “*Severe:Couldn’t open ‘#include’ file ‘getlcdbuttons.c’” still persists. Any other advice (or something I am doing wrong)?

P.S. Props for fastest Vex Forum reply time. :slight_smile:


#20

Not really sure what that could be.
I would try making a new folder in documents and placing both files there, also make sure that getlcdbuttons.c didn’t get accidentally renamed.