Help creating menu for golf robot

Read their document page 10 and change your values[] according to their adc_key_values. Can't copy values from pdf on stupid ipad. My library is not designed FOR their product, which they don't seem to support well, just read their date on the doc. My default values follow the Arduino analgoButton example but theirs don't. Any library you download requires some change and mine has sample code with extensive comment. Read them all.

BTW, since their keypad has no escape key, you will have to select something every time :slight_smile: and there is no way for you to run a multiple-select list on that pad. In multiple-select, you press enter on every item you mark as select so multiple items are selected. Then you have to press escape to exit.

Ah huh - that was the approach I had originally tried to follow using values I had had previous success with in earlier trial sketches using this LCD Shield. But inserting these threshold levels results in no switch responses at all in my Phi_prompt_example sketch. (e.g. see the following sketch which works AOK:)

//Sample using LiquidCrystal library
#include <LiquidCrystal.h>

/*******************************************************

This program will test the LCD panel and the buttons of
the DFRobot LCD Keypad Shield for Arduino
Product code : RB-Dfr-07
http://www.robotshop.com/dfrobot-lcd-keypad-shield-arduino-1.html

Note cct error identified by Arduino forum discussion at:
http://arduino.cc/forum/index.php/topic,96747.0.html
which advises insertion of a Germanium 1n34a or a Schotky 1N5819
diode between pin 10 and the base of Q1 (K to pin 10).

sample code originally by Mark Bramwell, July 2010
modifications by Dion Weston, March 2012



********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int backLight   = 10;    // LCD Panel Backlight LED connected to digital pin 10
int lightLevel  = 255;   // Initialise light full on
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor 
 // my [Mark Bramwell's] buttons when read are centered at these valies: 0, 144, 329, 504, 741
 // we add approx 50 to those values and check to see if we are close
 if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
 if (adc_key_in < 50)   return btnRIGHT;  
 if (adc_key_in < 195)  return btnUP; 
 if (adc_key_in < 380)  return btnDOWN; 
 if (adc_key_in < 555)  return btnLEFT; 
 if (adc_key_in < 790)  return btnSELECT;   
 return btnNONE;  // when all others fail, return this...
}

void setup()
{
 lcd.begin(16, 2);              // start the LCD library
 lcd.setCursor(0,0);            // move cursor to beginning of line "0"
 lcd.print("Backlight adjust"); // print a simple message
 
}
 
void loop()
{
 analogWrite(backLight, lightLevel);
 lcd.setCursor(13,1);            // move to position 13 on the second line
 lcd.print(lightLevel);

 lcd.setCursor(0,1);            // move to the beginning of the second line
 lcd_key = read_LCD_buttons();  // read the buttons

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     lcd.print("LED On          ");
     lightLevel = 255;
     break;
     }
   case btnLEFT:
     {
     lcd.print("LED Off         ");
     lightLevel = 1;
     break;
     }
   case btnUP:
     {
     lcd.print("LED Fade Up     ");
     if (lightLevel < 255) lightLevel += 1;
     break;
     }
   case btnDOWN:
     {
     lcd.print("LED Fade Down   ");
     if (lightLevel > 1) lightLevel -= 1;
     break;
     }
   case btnSELECT:
     {
     lcd.print("Select          ");
     break;
     }
     case btnNONE:
     {
     lcd.print("                ");
     break;
     }
 }
 
}

In other words transposing the following into my Phi_prompt_example code:

int values[]={50, 195, 380, 555, 790}; // Numbers from previous successful LCD_example sketches.

means no switch detection at all.

Changing the threshold settings to the p10 values you point to:

int values[]={30, 150, 360, 535, 760 }; // Switch threshold values taken from p10 of dfrobot product manual

means now the only switch detected is 'up' which still decrements the display. No other switches are detected.

And, of course, your original levels taken from the Arduino analgoButton example:

int values[]={0, 144, 342, 505, 742};  // Original analogue switch threshold numbers from Template_using_analog_keys.pde.

results in the 'Up", "Right", "Left" and "Select" switches being detected but not apparently for their intended purposes. The "Left" and "Select" switches are

Looks like I will simply have to use a trial and error approach to discover the threshold settings that works for Phi_interface.

"phi_analog_keypads_example_01.pde" looks like the ideal place to start.

There might be some error bars to the P10 numbers. I would do the following: simply load the analogInOutSerial example code included in arduino IDE and for each button held down read at least 10 values and average them. Then fill in the right numbers to values[]. If somehow up and down action are swapped, you can swap the definition of:

analog_mapping[]={'U','D','L','R','B'};

to look like:

analog_mapping[]={'D','U','L','R','B'};

Thanks liudr

The mapping that appears to work correctly on the DFR-007 16x2 LCD Keypad is:

char analog_mapping[]={'R','U','D','L','B'};

A successfully implemented example is as follows:

#include <LiquidCrystal.h>
#include <Wire.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <phi_interfaces.h>
#include <phi_prompt.h>

//DFRobot LCD shield pin setting
#define LCD_RS 8
#define LCD_EN 9
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7

//DFRobot LCD shield row & column assignments
#define lcd_rows 2
#define lcd_columns 16

#define analog_buttons_per_column 5 // Each analog pin has five buttons with resistors.
#define analog_buttons_per_row 1 // There are two analog pins in use.

#define name_length 8 // This is the max length of names.

char analog_mapping[]={'R','U','D','L','B'}; // This is an analog keypad.
byte analog_pins[]={0}; // The pin numbers are analog pin numbers.
int values[]={0, 143, 328, 503, 741};  // Measured switch threshold values
phi_analog_keypads analog_keypad(analog_mapping, analog_pins, values, analog_buttons_per_row, analog_buttons_per_column);


// This serial keypad is for debugging.
phi_serial_keypads debug_keypad(&Serial,9600);

// The following sets up function keys for phi_prompt library
char up_keys[]={"U"}; ///< All keys that act as the up key are listed here.
char down_keys[]={"D"}; ///< All keys that act as the down key are listed here.
char left_keys[]={"L"}; ///< All keys that act as the left key are listed here.
char right_keys[]={"R"}; ///< All keys that act as the right key are listed here.
char enter_keys[]={"B"}; ///< All keys that act as the enter key are listed here.
char escape_keys[]={"A"}; ///< All keys that act as the escape key are listed here.
char * function_keys[]={up_keys,down_keys,left_keys,right_keys,enter_keys,escape_keys}; ///< All function key names are gathered here for phi_prompt.

// The following adds all available keypads as inputs for phi_prompt library
multiple_button_input * keypads[]={&analog_keypad, &debug_keypad,0};

int backLight   = 10;    // LCD Panel Backlight LED connected to digital pin 10
int lightLevel  = 255;   // Initialise light full on

// The following sets up LCD and other objects
LiquidCrystal lcd(LCD_RS,LCD_EN,LCD_D4,LCD_D5,LCD_D6,LCD_D7); // Create the lcd object

void setup()
{
    lcd.begin(lcd_columns, lcd_rows);
    init_phi_prompt(&lcd,keypads,function_keys, lcd_columns, lcd_rows, '~'); // Supply the liquid crystal object, input keypads, and function key names. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
    Serial.begin(9600); // Serial is used as a debug keypad. This can be deleted after debug.
}

void loop()
{

phi_prompt_struct myTextInput; // This struct stores information for library functions. 
char file_name[]="TEST0000.TXT"; // This buffer stores the content of the text panel. 
myTextInput.ptr.msg=file_name; // Assign the text buffer address 
myTextInput.low.c='A'; // Text panel valid input starts with character 'A'. 
myTextInput.high.c='Z'; // Text panel valid input ends with character 'Z'.
myTextInput.width=12; // Length of the input panel is 12 characters. 
myTextInput.col=2; // Display input panel at column 2 
myTextInput.row=1; // Display input panel at row 1 
myTextInput.option=1; // Option 1 includes 0-9 as valid characters. Option 0, default 'A-Z' only. 
lcd.clear(); // Clear the lcd 
lcd.print("File name:"); // Prompt user for input 
input_panel(&myTextInput); // User input is stored in file_name. Notice the “&”.

/*

The user text input is stored in file_name after the function returns.

*/

Serial.println(file_name);

}

May be I'm too late... :slight_smile:
I made a simple library for menu management and used it to write a sketch for you.
All your application behaviour is coded as following (it works , I tested it):
Of course you need to write the true fireAction callback (it is simulated on a serial terminal by now);
You can find and download freely the library with some notes at

Only be aware of the following

  • it needs I2c lcd (i tested with 20x4 chars display, but it should work with 16x2 as well, with minor changes to the labels)
  • you need 6 buttons by now (but if you use I2C lcds you save lots of precious pins ...)

I hope this can be usefull for you.

Have a nice play!

//MENWIZ ESAMPLE
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <buttons.h>
#include <MENWIZ.h>

// DEFINE ARDUINO PINS FOR THE NAVIGATION BUTTONS
#define UP_BOTTON_PIN       9
#define DOWN_BOTTON_PIN     10
#define LEFT_BOTTON_PIN     7 
#define RIGHT_BOTTON_PIN    8
#define CONFIRM_BOTTON_PIN  12
#define ESCAPE_BOTTON_PIN   11

//Create global object LCD and MENU
menwiz menu;
LiquidCrystal_I2C lcd(0x27,20,4);

//instantiate global variables to bind to menu
byte m=0;
int  fd=0,yd=0;

void setup(){
  _menu *r,*s1;

  Serial.begin(19200);  
 
  // inizialize the menu object (20 colums x 4 rows LCD)
  menu.begin(&lcd,20,4);

  //create the menu tree
  r=menu.addMenu(MW_ROOT,NULL,"GOLF ROBOT");           //create a root menu at first (required)
      s1=menu.addMenu(MW_VAR,r,"Modes");                        //add a terminal node in the menu tree (that is "variable"); 
          s1->addVar(MW_LIST,&m);                                          //create the terminal node variable of type OPTION LIST and bind it to the app variable "m"
          s1->addItem(MW_LIST,"Drive");                                  //add an option to the OPTION LIST
          s1->addItem(MW_LIST,"Punch");                                 //add an other option to the OPTION LIST
          s1->addItem(MW_LIST,"Chip");                                    //add the third option to the OPTION LIST
          s1->addItem(MW_LIST,"Putt");                                    //add the last option to the OPTION LIST
      s1=menu.addMenu(MW_VAR,r,"Putt Dist.(feets)");        //create an other "variable" menu terminal mode
          s1->addVar(MW_AUTO_INT,&fd,0,100,1);                   //int type, fd binded variable, rage 0-100, step 1
      s1=menu.addMenu(MW_VAR,r,"Other Dist. (yrds)");
          s1->addVar(MW_AUTO_INT,&yd,0,300,5);                  //int type, yd binded variable, rage 0-300, step 5
      s1=menu.addMenu(MW_VAR,r,"Fire action");                 //latest menu entry
          s1->addVar(MW_ACTION,fireAction);                          // associate an action (variable of type function) to the menu entry

  //declare navigation buttons (required)
  // equivalent shorter call: menu.navButtons(9,10,7,8,11,12);
  menu.navButtons(UP_BOTTON_PIN,DOWN_BOTTON_PIN,LEFT_BOTTON_PIN,RIGHT_BOTTON_PIN,ESCAPE_BOTTON_PIN,CONFIRM_BOTTON_PIN);
  }

void loop(){
  // NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING
  menu.draw(); 

  //PUT APPLICATION CODE HERE
  // if any .... :-)
  }

// user defined action for fire action 
void fireAction(){
  Serial.print("FIRED ");
  switch (m){
    case 0:
      Serial.print("Drive to ");Serial.print(yd); Serial.println(" yrds");
      break;
    case 1:
      Serial.print("Punch to ");Serial.print(yd); Serial.println(" yrds");
      break;
    case 2:
      Serial.print("Chip to ");Serial.print(yd); Serial.println(" yrds");
      break;
    case 3:
      Serial.print("Put  to "); Serial.print(fd); Serial.println(" feets");
      break;
    default:
      break;
    }
  Serial.println("ACE!");
  }

dweston:
Thanks liudr

The mapping that appears to work correctly on the DFR-007 16x2 LCD Keypad is:

char analog_mapping[]={'R','U','D','L','B'};

A successfully implemented example is as follows:

#include <LiquidCrystal.h>

#include <Wire.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <phi_interfaces.h>
#include <phi_prompt.h>

//DFRobot LCD shield pin setting
#define LCD_RS 8
#define LCD_EN 9
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7

//DFRobot LCD shield row & column assignments
#define lcd_rows 2
#define lcd_columns 16

#define analog_buttons_per_column 5 // Each analog pin has five buttons with resistors.
#define analog_buttons_per_row 1 // There are two analog pins in use.

#define name_length 8 // This is the max length of names.

char analog_mapping[]={'R','U','D','L','B'}; // This is an analog keypad.
byte analog_pins[]={0}; // The pin numbers are analog pin numbers.
int values[]={0, 143, 328, 503, 741};  // Measured switch threshold values
phi_analog_keypads analog_keypad(analog_mapping, analog_pins, values, analog_buttons_per_row, analog_buttons_per_column);

// This serial keypad is for debugging.
phi_serial_keypads debug_keypad(&Serial,9600);

// The following sets up function keys for phi_prompt library
char up_keys[]={"U"}; ///< All keys that act as the up key are listed here.
char down_keys[]={"D"}; ///< All keys that act as the down key are listed here.
char left_keys[]={"L"}; ///< All keys that act as the left key are listed here.
char right_keys[]={"R"}; ///< All keys that act as the right key are listed here.
char enter_keys[]={"B"}; ///< All keys that act as the enter key are listed here.
char escape_keys[]={"A"}; ///< All keys that act as the escape key are listed here.
char * function_keys[]={up_keys,down_keys,left_keys,right_keys,enter_keys,escape_keys}; ///< All function key names are gathered here for phi_prompt.

// The following adds all available keypads as inputs for phi_prompt library
multiple_button_input * keypads[]={&analog_keypad, &debug_keypad,0};

int backLight   = 10;    // LCD Panel Backlight LED connected to digital pin 10
int lightLevel  = 255;   // Initialise light full on

// The following sets up LCD and other objects
LiquidCrystal lcd(LCD_RS,LCD_EN,LCD_D4,LCD_D5,LCD_D6,LCD_D7); // Create the lcd object

void setup()
{
    lcd.begin(lcd_columns, lcd_rows);
    init_phi_prompt(&lcd,keypads,function_keys, lcd_columns, lcd_rows, '~'); // Supply the liquid crystal object, input keypads, and function key names. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
    Serial.begin(9600); // Serial is used as a debug keypad. This can be deleted after debug.
}

void loop()
{

phi_prompt_struct myTextInput; // This struct stores information for library functions.
char file_name[]="TEST0000.TXT"; // This buffer stores the content of the text panel.
myTextInput.ptr.msg=file_name; // Assign the text buffer address
myTextInput.low.c='A'; // Text panel valid input starts with character 'A'.
myTextInput.high.c='Z'; // Text panel valid input ends with character 'Z'.
myTextInput.width=12; // Length of the input panel is 12 characters.
myTextInput.col=2; // Display input panel at column 2
myTextInput.row=1; // Display input panel at row 1
myTextInput.option=1; // Option 1 includes 0-9 as valid characters. Option 0, default 'A-Z' only.
lcd.clear(); // Clear the lcd
lcd.print("File name:"); // Prompt user for input
input_panel(&myTextInput); // User input is stored in file_name. Notice the “&”.

/*

The user text input is stored in file_name after the function returns.

*/

Serial.println(file_name);

}

I'm glad it worked. I'm releasing a new version of the library so there will be some simple_menu functions besides what it already has. You may simply send the function a string spelling out the entire menu and the return is which choice the user made. Gong to mighty easy to do menus.

Super - can't wait.

I was just about to embark in my current project on trying to work this all up from scratch and frankly it appeared well beyond me at my current level of Arduino proficiency.

Your efforts are much appreciated.