Solved: Help with Motor Control w/ LCD Keypad

Hi Everyone,

I am looking for some help on a project I am working on for my lab. I am trying to build an orbital shaker. Something like this:{url]http://www.thingiverse.com/thing:303187[/url]. I have put together all of the components that I will be using and have written some code (with lots of reading of reading from the forum). I have the code and it compiles and uploads to the Arduino. The LCD turns on but when I press any button it seems to hang. I have no clue what is causing it. Any help would be appreciated. This is what I see when I give power.

Here are the components I am using: ( All of them work with other code)
Arduino R3 SMD
A motor control shield (ebay)
Adafruit 16x2 LCD Shield.
Nema 17 stepper motor

And here is my code:

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <AFMotor.h>



 //This code will run a orbital shaker and allows the user to set the speed 
 //and direction.
// Initialize the libraries for LCD and Motor
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
AF_Stepper motor(48, 2);

//States for the menu.
int currentMenuItem = 0;
int lastState = 0;
int motorSpeed;
byte numbr[4];
byte indx;
int a = 0;
 
void setup() {
   //Set the characters and column numbers.
  Serial.begin(9600);
  lcd.begin(16, 2);
   //Print default title.
   clearPrintTitle();
}
 
void loop() {
  //Call the main menu.
  setMotorSpeed();
  motor.setSpeed(motorSpeed);
  mainMenu();
}
 
void mainMenu() {
  //State = 0 every loop cycle.
  int state = 0;
  //Refresh the button pressed.
  int x = analogRead (0);
  //Set the Row 0, Col 0 position.
  lcd.setCursor(0,0);
 
  //Check analog values from LCD Keypad Shield
  if (x < 100) {
    //Right
  } else if (x < 200) {
   //Up
    state = 1;
  } else if (x < 400){
   //Down
    state = 2;
  } else if (x < 600){
    //Left
  } else if (x < 800){
    //Select
    state = 3;
  }
 
  //If we are out of bounds on th menu then reset it.
  if (currentMenuItem < 0 || currentMenuItem > 4) {
   currentMenuItem = 0;
  }
 
   //If we have changed Index, saves re-draws.
   if (state != lastState) {
      if (state == 1) {
         //If Up
          currentMenuItem = currentMenuItem - 1;
          displayMenu(currentMenuItem);
      } else if (state == 2) {
         //If Down
          currentMenuItem = currentMenuItem + 1;  
          displayMenu(currentMenuItem);
      } else if (state == 3) {
         //If Selected
         selectMenu(currentMenuItem);
      }
      //Save the last State to compare.
      lastState = state;
   }
   //Small delay
  delay(5);
}
 
//Display Menu Option based on Index.
void displayMenu(int x) {
     switch (x) {
      case 1:
        clearPrintTitle();
        lcd.print ("Forward");
        break;
      case 2:
        clearPrintTitle();
        lcd.print ("Backwards");
        break;
       case 3:
        clearPrintTitle();
        lcd.print ("Back and Forth");
        break;
    }
}
 
//Print a basic header on Row 1.
void clearPrintTitle() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Select Direction");
  lcd.setCursor(0,1);
}
 
//Show the selection on Screen.
void selectMenu(int x) {
   switch (x) {
      case 1:
        clearPrintTitle();
        lcd.print ("Forward");
        motor.step(-1, FORWARD, SINGLE); 
        break;
      case 2:
        clearPrintTitle();
        lcd.print ("Backward");
        motor.step(-1, BACKWARD, SINGLE); 
        break;
       case 3:
        clearPrintTitle();
        lcd.print ("Back & Forth");
        //Call the function that belongs to Option 3
        motor.step(48,FORWARD, SINGLE);
        motor.step(48,BACKWARD,SINGLE);
        break;
    }
}

//Function to set motor speed
void setMotorSpeed(){
 int x;  
  x = analogRead (0);
  lcd.setCursor(0,1);

  
  if (x < 60) {
   //right button
   if (indx < 3 ) { 
     indx++;
     a++;
   }
  
  
  }
  else if (x < 200) {
  //up button
   if (numbr[indx] < 250 ) {
     numbr[indx]++;
    lcd.print(numbr[indx]);
   }

    
  }
  else if (x < 400){
  //down button
    if (numbr[indx] > 0 ) {
    numbr[indx]--;
    lcd.print(numbr[indx]);
    }

  }
   else if (x < 600){
   //left button
     if (indx > 0) {
     indx--;
     a--;
     }

     
  }
  else if (x < 800){
 //want to use this to save the value and move onto another function. 
   int enteredValue = 0;
   for (int i = 0; i < 4; i++){
     enteredValue = (enteredValue * 10) + numbr[i];
    
    lcd.setCursor(a,1);
    lcd.print("Speed Set");
    delay(2000);
    motorSpeed = enteredValue;
     
    }
  }
}
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

should be simply:

Adafruit_RGBLCDShield lcd;

You have a Serial.begin() call in setup(), but no Serial.print() statements anywhere. Add some, to see what your code is actually doing.

The only motor control function you are calling is setSpeed(). At some point, you'll probably want to make them actually move.

Links to the hardware are necessary, so we can check for pin conflicts.

Thanks for the input. I made some of the changes that you suggested. Still nothing. Below are the links for the shields. LCD Keypad: https://learn.adafruit.com/rgb-lcd-shield Motor Controller: http://www.elecfreaks.com/store/arduino-motorstepperservo-shield-shdmstepper-p-475.html?zenid=6b63df72a2224b33d48e3cf72f59eef0

For the motors doesn't motor.step make the motors go. I have made them move using this before is that not the best way.

The LCD turns on but when I press any button it seems to hang.

According to the LCD shield web site:

we devised a shield that lets you control a 16x2 Character LCD, up to 3 backlight pins AND 5 keypad pins using only the two I2C pins on the Arduino!

So, the switches on the shield should be read using lcd.readButtons(), not analogRead() on pin 0.

Hi Thanks for all the help. I have made some progress but still I cant get this to work. I have gone through and made a lot of changes to the code. I think I have the setSpeed function working now but the lcd is always flashing and then when I select a speed it completely ignores the setDirection part of the code. To give a basic overview of what I would like the code to accomplish is that it should ask the user to set a speed (in rpm) and then set a direction. It will then do that forever(atleast until the unit is tuned off or reset.). I have gone through the code and reorganized and put in comment it hopes to make it easier to trouble shoot.

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <AFMotor.h>



 //This code will run a orbital shaker and allows the user to set the speed 
 //and direction.
// Initialize the libraries for LCD and Motor
Adafruit_RGBLCDShield lcd;
AF_Stepper motor(48, 2);

//States for the menu.
int currentMenuItem = 0;
int lastState = 0;
int motorSpeed;
byte numbr[4];
byte indx;
int a = 0;
 
void setup() {
   //Set the characters and column numbers.
  Serial.begin(9600);
  lcd.begin(16, 2);
}
//main loop this calls the function that sets speed and direction. 
void loop() {
 motorSpeed = setSpeed();
  if ( 1 > motorSpeed > 200){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Not Valid");
    lcd.setCursor(0,1);
    exit(0);
  }
  motor.setSpeed(motorSpeed);
  lcd.clear();
  setDirection();
}

//Speed menu 
int setSpeed(){
  uint8_t buttons = lcd.readButtons();
  lcd.clear();
  int setMotorSpeed;
  lcd.setCursor(0,0);
  lcd.print("Select Speed");
  lcd.setCursor(0,1);
  int indx = 0;
  lcd.print(numbr[indx]);    
     if (buttons) {
      lcd.setCursor(0,1);
      if (buttons & BUTTON_UP) {
           if (numbr[indx] < 250 ) {
             numbr[indx]++;
             lcd.print(numbr[indx]);
           }
      }
      if (buttons & BUTTON_DOWN) {
       if (numbr[indx] > 0 ) {
          numbr[indx]--;
          lcd.print(numbr[indx]);
          }
      }
      if (buttons & BUTTON_LEFT) {
       if (indx > 0) {
         indx--;
         a--;
         }
      }
      if (buttons & BUTTON_RIGHT) {
           if (indx < 3 ) { 
           indx++;
           a++;
          }
      }
      if (buttons & BUTTON_SELECT) {
       //want to use this to save the value and move onto another function. 
       int enteredValue = 0;
       for (int i = 0; i < 4; i++){
         enteredValue = (enteredValue * 10) + numbr[i];
      
          lcd.setCursor(a,1);
          lcd.print("Speed Set");
          delay(200);
          motorSpeed = enteredValue;
          return motorSpeed;
         }
       }
    }
  
}

//Function to select direction
void setDirection() {
  //State = 0 every loop cycle.
  int state = 0;
  //Refresh the button pressed.
  int x = lcd.readButtons();
  //Set the Row 0, Col 0 position.
  lcd.setCursor(0,0);
   uint8_t buttons = lcd.readButtons();
if (buttons) {
     if (buttons & BUTTON_UP) {
       state=1;
     }
     if (buttons & BUTTON_DOWN) {
        state=2;
     }
     if (buttons & BUTTON_SELECT) {
         state=3;
     }  
}
 
  //If we are out of bounds on th menu then reset it.
  if (currentMenuItem < 0 || currentMenuItem > 4) {
   currentMenuItem = 0;
  }
 
   //If we have changed Index, saves re-draws.
   if (state != lastState) {
      if (state == 1) {
         //If Up
          currentMenuItem = currentMenuItem - 1;
          displayMenu(currentMenuItem);
      } else if (state == 2) {
         //If Down
          currentMenuItem = currentMenuItem + 1;  
          displayMenu(currentMenuItem);
      } else if (state == 3) {
         //If Selected
         runMotor(currentMenuItem);
         
      }
      //Save the last State to compare.
      lastState = state;
   }
   //Small delay
  delay(5);
}
 
//Display Menu Option based on Index.
//Helper function for setDirection
void displayMenu(int x) {
     switch (x) {
      case 1:
        clearPrintTitle();
        lcd.print ("Forward");
        setDirection();
      case 2:
        clearPrintTitle();
        lcd.print ("Backwards");
        setDirection();
       case 3:
        clearPrintTitle();
        lcd.print ("Back & Forth");
        setDirection();
        break;
    }
} 
//Run the motor forever.
//Display direction and speed
void runMotor(int x) {
   switch (x) {
      case 1:
        lcd.setCursor(0,0);
        lcd.print ("Forward");
        lcd.setCursor(0,1);
        lcd.print("Speed:");
        motor.step(-1, FORWARD, SINGLE); 
      case 2:
        lcd.setCursor(0,0);
        lcd.print ("Backward");
        motor.step(-1, BACKWARD, SINGLE);
         lcd.setCursor(0,1);
        lcd.print("Speed:"+motorSpeed); 
       case 3:
        lcd.setCursor(0,0);
        lcd.print ("Back & Forth");
        lcd.setCursor(0,1);
        lcd.print("Speed:"+motorSpeed);
        //run forever
        while(true){
          motor.step(48,FORWARD, SINGLE);
          motor.step(48,BACKWARD,SINGLE);
          delay(5);
        }
    }
}

//Resets the lcd
void clearPrintTitle(){
  lcd.clear();
  lcd.setCursor(0,0);
}

edit to update code

  if ( 1 > motorSpeed > 200){

If motorSpeed is greater than one, compare true to 200. Otherwise, compare false to 200. Does that make sense?

Your setSpeed() function appears to allow the user to move the cursor back and forth, and increment or decrement the individual digits in a value. Is that correct? If so, why is the upper limit on any one digit 250? Why is there no lower limit?

Why is there a global variable called a? Is it REALLY that difficult to come up with a meaningful name?

Why is there a global variable called indx, of type byte, and a local variable of the same name, of type int?

Why is the return statement in the middle of the for loop, in setSpeed()?

Why are there STILL no Serial.print() statements?

If motorSpeed is greater than one, compare true to 200. Otherwise, compare false to 200. Does that make sense?

I noticed this too and have changed it.

Your setSpeed() function appears to allow the user to move the cursor back and forth, and increment or decrement the individual digits in a value. Is that correct? If so, why is the upper limit on any one digit 250? Why is there no lower limit?

I thought this was setting the max value. If i set this to nine it stops. There is no lower limit because it should never go less than 0. Is there a better way to do this?

Why is there a global variable called a? Is it REALLY that difficult to come up with a meaningful name?

Added a more descriptive name.

Why is there a global variable called indx, of type byte, and a local variable of the same name, of type int?

That was a mistake. the int should have been deleted.

Why is the return statement in the middle of the for loop, in setSpeed()?
What I am trying to do is have it stop their and return the value motorSpeed.

Why are there STILL no Serial.print() statements?

The print statements were less than help full. I used them to try and debug and they made me more confused so I removed them. If they would be helpful to you I can put some in and then post the results.

I have made some rather extensive updates to the code some related to the comments others not. I am closer but it still doesnt seem to work the way I would like. I have attached a video of what happens and the updated code.
http://videobam.com/hjafM#

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <AFMotor.h>



 //This code will run a orbital shaker and allows the user to set the speed 
 //and direction.
// Initialize the libraries for LCD and Motor
Adafruit_RGBLCDShield lcd;
AF_Stepper motor(48, 2);

//States for the menu.
int currentMenuItem = 0;
int lastState = 0;
int motorSpeed;
byte numbr[4];
byte indx;
int  numberPosition= 0;
 
void setup() {
   //Set the characters and column numbers.
  Serial.begin(9600);
  lcd.begin(16, 2);
}
//main loop this calls the function that sets speed and direction. 
void loop() {
  motorSpeed = setSpeed();
  if (motorSpeed > 200){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Not Valid");
    lcd.setCursor(0,1);
    exit(0);
  }
  motor.setSpeed(motorSpeed);
  lcd.clear();
  delay(100);
  setDirection();
}

//Speed menu 
int setSpeed(){
  uint8_t buttons = lcd.readButtons();
  lcd.clear();
  int setMotorSpeed;
  lcd.setCursor(0,0);
  lcd.print("Select Speed");
  lcd.setCursor(0,1);
  lcd.print(numbr[indx]); 
  int isSet=1; 
  while(isSet){ 
     uint8_t buttons = lcd.readButtons(); 
     if (buttons) {
      lcd.setCursor(0,1);
      if (buttons & BUTTON_UP) {
           if (numbr[indx] < 250 ) {
             numbr[indx]++;
             lcd.print(numbr[indx]);
             delay(100);
           }
      }
      if (buttons & BUTTON_DOWN) {
       if (numbr[indx] > 0 ) {
          numbr[indx]--;
          lcd.print(numbr[indx]);
          delay(100);
          }
      }
      if (buttons & BUTTON_LEFT) {
       if (indx > 0) {
         indx--;
         numberPosition--;
         delay(100);
         }
      }
      if (buttons & BUTTON_RIGHT) {
           if (indx < 3 ) { 
           indx++;
           numberPosition++;
           delay(100);
          }
      }
      if (buttons & BUTTON_SELECT) {
       //want to use this to save the value and move onto another function. 
       int enteredValue = 0;
       for (int i = 0; i < 4; i++){
         enteredValue = (enteredValue * 10) + numbr[i];
       }
      clearPrintTitle();  
      lcd.print("Speed Set" + enteredValue);
      delay(200);
      motorSpeed = enteredValue;
      isSet=0;
      delay(100);
         }
       }
    }
}


//Function to select direction
void setDirection() {
  //State = 0 every loop cycle.
  int state = 0;
  //Refresh the button pressed.
  int x = lcd.readButtons();
  //Set the Row 0, Col 0 position.
  lcd.setCursor(0,0);
   uint8_t buttons = lcd.readButtons();
   int isSet = 1;
   while(isSet){
if (buttons) {
     if (buttons & BUTTON_UP) {
       state=1;
     }
     if (buttons & BUTTON_DOWN) {
        state=2;
     }
     if (buttons & BUTTON_SELECT) {
         state=3;
     }  
}
 
  //If we are out of bounds on th menu then reset it.
  if (currentMenuItem < 0 || currentMenuItem > 4) {
   currentMenuItem = 0;
  }
 
   //If we have changed Index, saves re-draws.
   if (state != lastState) {
      if (state == 1) {
         //If Up
          currentMenuItem = currentMenuItem - 1;
          displayMenu(currentMenuItem);
      } else if (state == 2) {
         //If Down
          currentMenuItem = currentMenuItem + 1;  
          displayMenu(currentMenuItem);
      } else if (state == 3) {
         //If Selected
         runMotor(currentMenuItem);
         
      }
      //Save the last State to compare.
      lastState = state;
   }
   //Small delay
  delay(5);
}
}
 
//Display Menu Option based on Index.
//Helper function for setDirection
void displayMenu(int x) {
     switch (x) {
      case 1:
        clearPrintTitle();
        lcd.print ("Forward");
        setDirection();
      case 2:
        clearPrintTitle();
        lcd.print ("Backwards");
        setDirection();
       case 3:
        clearPrintTitle();
        lcd.print ("Back & Forth");
        setDirection();
        break;
    }
} 
//Run the motor forever.
//Display direction and speed
void runMotor(int x) {
   switch (x) {
      case 1:
        lcd.setCursor(0,0);
        lcd.print ("Forward");
        lcd.setCursor(1,1);
        lcd.print("Speed:");
        while(true){
        motor.step(-1, FORWARD, SINGLE);
        } 
      case 2:
        lcd.setCursor(0,0);
        lcd.print ("Backward");
        lcd.setCursor(1,1);
        lcd.print("Speed:"+motorSpeed); 
        while(true){
        motor.step(-1, BACKWARD, SINGLE);
        }
       case 3:
        lcd.setCursor(0,0);
        lcd.print ("Back & Forth");
        lcd.setCursor(1,1);
        lcd.print("Speed:"+motorSpeed);
        //run forever
        while(true){
          motor.step(48,FORWARD, SINGLE);
          motor.step(48,BACKWARD,SINGLE);
          delay(5);
        }
    }
}

//Resets the lcd
void clearPrintTitle(){
  lcd.clear();
  lcd.setCursor(0,0);
}

If motorSpeed is greater than one, compare true to 200. Otherwise, compare false to 200. Does that make sense?

It does but that's not how it is written.

It is written like this.

if ( 1 > motorSpeed && motorSpeed > 200)
{
  //code
}

You have a few while loops that don't allow your code to break from, like setDirection() and runMotor()

Why make setSpeed() an int if your not returning anything?

I thought this was setting the max value. If i set this to nine it stops. There is no lower limit because it should never go less than 0. Is there a better way to do this?

You didn’t answer the question. You have numbr as an array of 4. You increment and decrement indx, and use that as in index into the numbr array.

When the select key is pressed, you multiply the values in the numbr array by 10 and add to the running total.

So, the array can hold 250, 250, 250, and 250. (((((250 * 10) + 250) * 10) + 250) * 10) + 250 is going to be a pretty large number.

You don’t have a lower limit, so what happens as the value is decremented from 3 to 2 to 1 to 0 to ?

Never mind. I see that you fixed that <

Either there is something fundamentally wrong with the code, or with my understanding.

So, lets make the question real simple. Exactly what IS the numbr array supposed to hold? speed and three other values? or 4 digits of the speed value?

If it’s speed and three other values, why is the setSpeed() function multiplying and adding all the values in the array? If it is the 4 digits of the speed value, why can any one digit range from -infinity to 250?

What I am trying to do is have it stop their and return the value motorSpeed.

You need to explain this. Only the one element of the numbr array is actually being used with the return statement in the for loop, so the for loop is stupid. Or the unconditional return statement in the for loop is.

The print statements were less than help full. I used them to try and debug and they made me more confused so I removed them. If they would be helpful to you I can put some in and then post the results.

Then you were:
a) not printing the right stuff
b) not identifying what you were printing

Let’s look at setSpeed() again.

int setSpeed(){
  uint8_t buttons = lcd.readButtons();
  lcd.clear();
  int setMotorSpeed;
  lcd.setCursor(0,0);
  lcd.print("Select Speed");
  lcd.setCursor(0,1);
  lcd.print(numbr[indx]); 
  int isSet=1; 
  while(isSet){ 
     uint8_t buttons = lcd.readButtons(); 
     if (buttons) {
      lcd.setCursor(0,1);
      if (buttons & BUTTON_UP) {
           if (numbr[indx] < 250 ) {
             numbr[indx]++;
             lcd.print(numbr[indx]);
             delay(100);
           }
      }
      if (buttons & BUTTON_DOWN) {
       if (numbr[indx] > 0 ) {
          numbr[indx]--;
          lcd.print(numbr[indx]);
          delay(100);
          }
      }
      if (buttons & BUTTON_LEFT) {
       if (indx > 0) {
         indx--;
         numberPosition--;
         delay(100);
         }
      }
      if (buttons & BUTTON_RIGHT) {
           if (indx < 3 ) { 
           indx++;
           numberPosition++;
           delay(100);
          }
      }
      if (buttons & BUTTON_SELECT) {
       //want to use this to save the value and move onto another function. 
       int enteredValue = 0;
       for (int i = 0; i < 4; i++){
         enteredValue = (enteredValue * 10) + numbr[i];
       }
      clearPrintTitle();  
      lcd.print("Speed Set" + enteredValue);
      delay(200);
      motorSpeed = enteredValue;
      isSet=0;
      delay(100);
         }
       }
    }
}

Once again, you have two variables named buttons with different scopes. Why?

What is the purpose of the lcd.print(numbr[indx]) line? What, exactly, is it showing on the LCD? What is the value of indx when setSpeed() is called?

How do indx and numberPosition differ? Why are there two variables that appear to serve the same purpose?

The setSpeed() function is defined to return an int. Yet it doesn’t contain a return statement, so the return value will be whatever garbage is on the stack. NOT a good idea.

I’m not picking on you. I’m trying to make you think about what you are doing, and to EXPLAIN what you are doing. If what you are doing doesn’t match what you say you are doing, we can help get you on track. Without the explanations, though, all we have to go on is your code. Which you admit doesn’t do what you want.

Don’t worry I don’t think your picking on me and I sincerely appreciate all of the help. I know this all should be more organized than this I have been working on this basically nonstop for a month trying everything I could think of.

You didn’t answer the question. You have numbr as an array of 4. You increment and decrement indx, and use that as in index into the numbr array.

When the select key is pressed, you multiply the values in the numbr array by 10 and add to the running total.

So, the array can hold 250, 250, 250, and 250. (((((250 * 10) + 250) * 10) + 250) * 10) + 250 is going to be a pretty large number.

Either there is something fundamentally wrong with the code, or with my understanding.

So, lets make the question real simple. Exactly what IS the numbr array supposed to hold? speed and three other values? or 4 digits of the speed value?

numbr is supposed to hold the speed that the user would like to set the motor to run at. It will be a max 250 and ideally needs to be more than 0(if it gets set to zero I don’t really care the motor just wont go). So basically I used an array so I could display a 3 digit number but then I need to convert it to an int to pass to my setSpeed function (now called getSpeed).

If it’s speed and three other values, why is the setSpeed() function multiplying and adding all the values in the array? If it is the 4 digits of the speed value, why can any one digit range from -infinity to 250?

Hopefully my explanation about helps answer this question.

You need to explain this. Only the one element of the numbr array is actually being used with the return statement in the for loop, so the for loop is stupid. Or the unconditional return statement in the for loop is.

What I need to do is have a user set the speed using the keypad then this will then be used later to set the speed of the motor. Then I need setSpeed(getSpeed) to nothing after that. I should probably just have it set a global variable instead of trying to have it return the desired speed? or is that a bad idea.

  • I realized when looking at this that the motor function is also called set speed(I am an idiot). I will change mine to getSpeed because I feel that is more descriptive of what it needs to do.

Then you were:
a) not printing the right stuff
b) not identifying what you were printing

You are completely right. I have no idea how to use serial print so I read about it a little then just tried a few things. For example put setSpeed() in the statement and then look at the output and all I got was a bunch of 1’s. i honestly have no clue how to use this effectively.

Once again, you have two variables named buttons with different scopes. Why?

I was being sloppy again. I have just been trying anything to get this to work and its gotten a bit messy. I didn’t even notice it.

What is the purpose of the lcd.print(numbr[indx]) line? What, exactly, is it showing on the LCD? What is the value of indx when setSpeed() is called?

This line is meant to display the update value on screen and I never set indx.
Here is what I see: Motor control - YouTube

How do indx and numberPosition differ? Why are there two variables that appear to serve the same purpose?

They don’t they are interchangeable I am going to get rid of one.

The setSpeed() function is defined to return an int. Yet it doesn’t contain a return statement, so the return value will be whatever garbage is on the stack. NOT a good idea.

Yea I realized this. It could just be void. Right?

So basically what I want to do is:

  1. Have a number be set by the keypad with a max value of 250. Store this number for later use.
    2)Set the speed of the motor to that value. Using motor.setSpeed (not my poorly named function)
    3)Have a menu with three options so the user can decide which way the motor runs. Forward, backwards, back and forth.
    4)Make the motors move based on the user input
  2. Do that until loss of power or reset.

Here is my update code

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <AFMotor.h>



 //This code will run a orbital shaker and allows the user to set the speed 
 //and direction.
// Initialize the libraries for LCD and Motor
Adafruit_RGBLCDShield lcd;
AF_Stepper motor(48, 2);

//States for the menu.
int currentMenuItem = 0;
int lastState = 0;
int motorSpeed;
byte numbr[4];
byte indx;
 
void setup() {
   //Set the characters and column numbers.
  Serial.begin(9600);
  lcd.begin(16, 2);
}
//main loop this calls the function that sets speed and direction. 
void loop() {
  getSpeed();
  if (motorSpeed > 200){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Not Valid");
    lcd.setCursor(0,1);
    exit(0);
  }
  motor.setSpeed(motorSpeed);
  lcd.clear();
  delay(100);
  setDirection();
}

//Speed menu 
void getSpeed(){
  lcd.clear();
  int setMotorSpeed;
  lcd.setCursor(0,0);
  lcd.print("Select Speed");
  lcd.setCursor(0,1);
  lcd.print(numbr[indx]); 
  int isSet=1; 
  while(isSet){ 
     uint8_t buttons = lcd.readButtons(); 
     if (buttons) {
      lcd.setCursor(0,1);
      if (buttons & BUTTON_UP) {
           if (numbr[indx] < 250 ) {
             numbr[indx]++;
             lcd.print(numbr[indx]);
             delay(100);
           }
      }
      if (buttons & BUTTON_DOWN) {
       if (numbr[indx] > 0 ) {
          numbr[indx]--;
          lcd.print(numbr[indx]);
          delay(100);
          }
      }
      if (buttons & BUTTON_LEFT) {
       if (indx > 0) {
         indx--;
         delay(100);
         }
      }
      if (buttons & BUTTON_RIGHT) {
           if (indx < 3 ) { 
           indx++;
           delay(100);
          }
      }
      if (buttons & BUTTON_SELECT) {
       //want to use this to save the value and move onto another function. 
       int enteredValue = 0;
       for (int i = 0; i < 4; i++){
         enteredValue = (enteredValue * 10) + numbr[i];
       }
      clearPrintTitle();  
      lcd.print("Speed Set" + enteredValue);
      delay(200);
      motorSpeed = enteredValue;
      isSet=0;
      delay(100);
         }
       }
    }
}


//Function to select direction
void setDirection() {
  //State = 0 every loop cycle.
  int state = 0;
  //Set the Row 0, Col 0 position.
  lcd.setCursor(0,0);
   uint8_t buttons = lcd.readButtons();
   int isSet = 1;
   while(isSet){
if (buttons) {
     if (buttons & BUTTON_UP) {
       state=1;
     }
     if (buttons & BUTTON_DOWN) {
        state=2;
     }
     if (buttons & BUTTON_SELECT) {
         state=3;
     }  
}
 
  //If we are out of bounds on th menu then reset it.
  if (currentMenuItem < 0 || currentMenuItem > 4) {
   currentMenuItem = 0;
  }
 
   //If we have changed Index, saves re-draws.
   if (state != lastState) {
      if (state == 1) {
         //If Up
          currentMenuItem = currentMenuItem - 1;
          displayMenu(currentMenuItem);
      } else if (state == 2) {
         //If Down
          currentMenuItem = currentMenuItem + 1;  
          displayMenu(currentMenuItem);
      } else if (state == 3) {
         //If Selected
         runMotor(currentMenuItem);
         
      }
      //Save the last State to compare.
      lastState = state;
   }
   //Small delay
  delay(5);
}
}
 
//Display Menu Option based on Index.
//Helper function for setDirection
void displayMenu(int x) {
     switch (x) {
      case 1:
        clearPrintTitle();
        lcd.print ("Forward");
        setDirection();
      case 2:
        clearPrintTitle();
        lcd.print ("Backwards");
        setDirection();
       case 3:
        clearPrintTitle();
        lcd.print ("Back & Forth");
        setDirection();
        break;
    }
} 
//Run the motor forever.
//Display direction and speed
void runMotor(int x) {
   switch (x) {
      case 1:
        lcd.setCursor(0,0);
        lcd.print ("Forward");
        lcd.setCursor(1,1);
        lcd.print("Speed:");
        while(true){
        motor.step(-1, FORWARD, SINGLE);
        } 
      case 2:
        lcd.setCursor(0,0);
        lcd.print ("Backward");
        lcd.setCursor(1,1);
        lcd.print("Speed:"+motorSpeed); 
        while(true){
        motor.step(-1, BACKWARD, SINGLE);
        }
       case 3:
        lcd.setCursor(0,0);
        lcd.print ("Back & Forth");
        lcd.setCursor(1,1);
        lcd.print("Speed:"+motorSpeed);
        //run forever
        while(true){
          motor.step(48,FORWARD, SINGLE);
          motor.step(48,BACKWARD,SINGLE);
          delay(5);
        }
    }
}

//Resets the lcd
void clearPrintTitle(){
  lcd.clear();
  lcd.setCursor(0,0);
}

HazardsMind:

If motorSpeed is greater than one, compare true to 200. Otherwise, compare false to 200. Does that make sense?

It does but that's not how it is written.

It is written like this.

if ( 1 > motorSpeed && motorSpeed > 200)
{
  //code
}

You have a few while loops that don't allow your code to break from, like setDirection() and runMotor()

Why make setSpeed() an int if your not returning anything?

I realized the mistake in the if statement. That was supposed to be a place marker to let me know what to do when I was doing the original sudo code. Somehow it made it all the way to this point without me noticing.

As for the while loop I wanted them to be endless. Once setDirection is used it calls runMotor and then the motors should run until loss of power or reset. Is there a better way?

setSpeed being an int was a mistake I had it returning a value at one time and then changed how I wanted to deal with the value and forgot to change that.

Well if you really don't want it to do [u]anything else until it dies[/u], then sure, you can do it the way you have it.

You still need to iron out the points PaulS spoke about.

I went through and did a major overhaul on the code. I want to say thank you to everyone who helped. I think the code is working properly. I will update after I do some testing with the motor control shield. I have posted the code below for reference if there are small changes I may update the code to reflect the final working version.

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <AFMotor.h>



 //This code will run a orbital shaker and allows the user to set the speed and direction

// Initialize the libraries for LCD and Motor
Adafruit_RGBLCDShield lcd;
AF_Stepper motor(48, 2);

//Global for motor speed initialized to 1
int motorSpeed = 1;
 
void setup() {
    Serial.begin(9600);
   //Set the characters and column numbers.
  lcd.begin(16, 2);
}
//main loop this calls the function that sets speed and direction. 
void loop() {
  getSpeed();
  motor.setSpeed(motorSpeed);
  lcd.clear();
  delay(50);
  setDirection();
}

//Gets user input for desired speed
void getSpeed(){
  clearPrintTitle();
  lcd.print("Select Speed");
  lcd.setCursor(0,1);
  lcd.print(motorSpeed);
  int isSet=1; 
  //loop until speed is set by user pressing select. Max motor speed of 250 min of 1. 
  while(isSet){ 
     uint8_t buttons = lcd.readButtons(); 
     if (buttons) {
        lcd.setCursor(0,1);
        if (buttons & BUTTON_UP) {
             if (motorSpeed < 250) {
               motorSpeed++;
               lcd.print(motorSpeed);
               delay(100);
             }
        }
        if (buttons & BUTTON_DOWN) {
         if (motorSpeed > 1  ) {
            motorSpeed--;
            lcd.print(motorSpeed);
            delay(100);
            }
        }
  
        if (buttons & BUTTON_SELECT) {
             //want to use this to save the value and move onto another function. 
            clearPrintTitle();  
            lcd.print("Speed Set As:");
            lcd.setCursor(0,1);
            lcd.print(motorSpeed);
            isSet=0;
            delay(3000);
         }
        
     }
   }
}


//Function to select direction
void setDirection() {
  //State = 0 every loop cycle.
  int motorDirection = 1;
  int lastMotorDirection = 1;
  //Set the Row 0, Col 0 position.
  lcd.setCursor(0,0);
  lcd.print("Set Direction");
  lcd.setCursor(0,1);
  displayMenu(motorDirection);
  int isSet = 1;
  while(isSet){
      uint8_t buttons = lcd.readButtons();
      if (buttons) {
        Serial.print("buttons loop");
           if (buttons & BUTTON_UP) {
             Serial.print("up");
              if (motorDirection == 3){
                lastMotorDirection = motorDirection;
                motorDirection = 1;
              }
              else{
                lastMotorDirection = motorDirection;
                motorDirection++;
              }
            displayMenu(motorDirection);
           }
           if (buttons & BUTTON_DOWN) {
             Serial.print("down");
              if (motorDirection == 1){
                lastMotorDirection = motorDirection;
                motorDirection = 3;
              }
              else{
                lastMotorDirection = motorDirection;
                motorDirection--;
              }
              displayMenu(motorDirection);
           }
           if (buttons & BUTTON_SELECT) {
             Serial.print("select");
             //want to use this to save the value and move onto another function. 
            clearPrintTitle();  
            lcd.print("Direction Is:");
            lcd.setCursor(0,1);
            lcd.print(motorDirection);
            isSet=0;
            delay(3000);
           } 
      }
     delay(30);
  }
  runMotor(motorDirection);
}
 
//Display Menu Option based on Index.
//Helper function for setDirection
void displayMenu(int x) {
     switch (x) {
      case 1:
        lcd.clear();
        lcd.print("Set Direction");
        lcd.setCursor(0,1);
        lcd.print ("Forward");
        break;
      case 2:
        lcd.clear();
        lcd.print("Set Direction");
        lcd.setCursor(0,1);
        lcd.print ("Backwards");
        break;
       case 3:
        lcd.clear();
        lcd.print("Set Direction");
        lcd.setCursor(0,1);
        lcd.print ("Back & Forth");
    }
} 
//Run the motor forever.
//Display direction and speed
void runMotor(int x) {
   switch (x) {
      case 1:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print ("Forward");
        lcd.setCursor(0,1);
        lcd.print("Speed:");
        lcd.print(motorSpeed);
        while(true){
        motor.step(-1, FORWARD, SINGLE);
        } 
      case 2:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print ("Backward");
        lcd.setCursor(0,1);
        lcd.print("Speed:");
        lcd.print(motorSpeed); 
        while(true){
        motor.step(-1, BACKWARD, SINGLE);
        }
       case 3:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print ("Back & Forth");
        lcd.setCursor(0,1);
        lcd.print("Speed:");
        lcd.print(motorSpeed);
        //run forever
        while(true){
          motor.step(48,FORWARD, SINGLE);
          motor.step(48,BACKWARD,SINGLE);
          delay(5);
        }
    }
}

//Resets the lcd
void clearPrintTitle(){
  lcd.clear();
  lcd.setCursor(0,0);
}