using keypad to key in servo value in order to control bldc motor

guys, servo value is 1-180. I’m using servo library to control a bldc motor. i need to use a keypad to key in the servo value, then the value is relayed to the ESC then to the bldc motor. How do i program so that the keypad input is use to control the bldc. i read something about atoi, somehow i still don’t quite understand. the program below shows how i control the bldc with servo library using the computer keyboard to enter the servo value, how do i enter the servo value using a 4x4 matric keypad?? Please help… i’m new to programming…

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
// read the hall effect sensor on pin 2
const int hallPin=2;
const unsigned long sampleTime=1000;
const int maxRPM = 9000; 

#include <Servo.h> 
Servo esc;
int escPin = 11;
int minPulseRate = 700;
int maxPulseRate = 2000;
int throttleChangeDelay = 100;

void setup() {
  
  Serial.begin(9600);
  Serial.setTimeout(500);
  // Attach the the servo to the correct pin and set the pulse range
  esc.attach(escPin, minPulseRate, maxPulseRate); 
  // Write a minimum value (most ESCs require this correct startup)
  esc.write(0);

  pinMode(hallPin,INPUT);
  lcd.begin(16, 2);
  lcd.print("initializing");
  delay(1000);
  lcd.clear();
  
}

void loop() {

  // Wait for some input
  if (Serial.available() > 0) {
    
    // Read the new throttle value
    int throttle = normalizeThrottle( Serial.parseInt() );
    
    // Print it out
    Serial.print("Setting throttle to: ");
    Serial.println(throttle);
    
    // Change throttle to the new value
    changeThrottle(throttle);

    delay(100);
  int rpm=getRPM();
  lcd.clear();
  displayRPM(rpm);
  
  }

}

void changeThrottle(int throttle) {
  
  // Read the current throttle value
  int currentThrottle = readThrottle();
  
  // Are we going up or down?
  int step = 1;
  if( throttle < currentThrottle )
    step = -1;
  
  // Slowly move to the new throttle value 
  while( currentThrottle != throttle ) {
    esc.write(currentThrottle + step);
    currentThrottle = readThrottle();
    delay(throttleChangeDelay);
  }
  
}

int readThrottle() {
  int throttle = esc.read();
  
  Serial.print("Current throttle is: ");
  Serial.println(throttle);
  
  return throttle;
}

// Ensure the throttle value is between 0 - 180
int normalizeThrottle(int value) {
  if( value < 0 )
    return 0;
  if( value > 180 )
    return 180;
  return value;
}


 int getRPM()
{
  // sample for sampleTime in millisecs
  int kount=0;
  boolean kflag=LOW;
  unsigned long currentTime=0;
  unsigned long startTime=millis();
  while (currentTime<=sampleTime)
  {
    if (digitalRead(hallPin)==HIGH)
    {
      kflag=HIGH;
    }
    if (digitalRead(hallPin)==LOW && kflag==HIGH)
    {
      kount++;
      kflag=LOW;
    }
    currentTime=millis()-startTime;
  }
  int kount2rpm = int(60000./float(sampleTime))*kount;
  return kount2rpm;
}
    
void displayRPM(int rpm) 
{
  lcd.clear();
  // set the cursor to column 0, line 1
  lcd.setCursor(0, 0); 
  // print the number of seconds since reset:
  lcd.print(rpm,DEC);
  lcd.setCursor(7,0);
  lcd.print("RPM");
}

void displayBar(int rpm)
{
  int numOfBars=map(rpm,0,maxRPM,0,15);
  lcd.setCursor(0,1);
  if (rpm!=0)
  {
  for (int i=0; i<=numOfBars; i++)
   {
        lcd.setCursor(i,1);
        lcd.write(1023);
      }
  }
}

how do i enter the servo value using a 4x4 matric keypad??

Step 1. Read the keypad and display on the Serial monitor what you get when a key is pressed. When that works you know that the keypad is working.

Now the clever part. Make the value of an index variable 0 ready to be used. Each time you get a character between '0' and '9' on the keypad put it into an array of chars at least 4 characters long, increment the array index variable and put a zero, not a '0' in the resulting array position.

What you are building is a zero terminated array of chars, aka a C style string (lowercase s). When you have received 3 characters or when you receive an "end of input" character, such as '#' then convert the string to an integer using the atoi() function. Use the int to position the servo using servo.write().

thanks UKHeliBob for your response… very much appreciated…

i tried your steps… i manage to get the keypad to function well… however, my problem is to incorporate the key in value mapped to the bldc motor… i use atoi…i some how still get errors and the bldc motor is not spinning when value is key in. Please help… the code is shown below with addition of keypad keyin value… hope you can help me…

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
// read the hall effect sensor on pin 2
const int hallPin=2;
const unsigned long sampleTime=1000;
const int maxRPM = 9000;

#include <Servo.h>
Servo esc;
int escPin = 11;
int minPulseRate = 700;
int maxPulseRate = 2000;
int throttleChangeDelay = 100;

void setup() {

Serial.begin(9600);
Serial.setTimeout(500);
// Attach the the servo to the correct pin and set the pulse range
esc.attach(escPin, minPulseRate, maxPulseRate);
// Write a minimum value (most ESCs require this correct startup)
esc.write(0);

pinMode(hallPin,INPUT);
lcd.begin(16, 2);
lcd.print(“initializing”);
delay(1000);
lcd.clear();

}

void loop()
{

char key = keypad.getKey();
if (key != NO_KEY)
{
int i;
char buffer[4];
lcd.print("number: ");
lcd.print(key);
fgets (buffer, 4, stdin);
i = atoi (buffer);
lcd.print(i);
}

// Wait for some input
if (Servo.write() > 0) {

// Read the new throttle value
int throttle = normalizeThrottle( Servo.read() );

// Print it out
Serial.print("Setting throttle to: ");
Serial.println(throttle);

// Change throttle to the new value
changeThrottle(throttle);

delay(100);
int rpm=getRPM();
lcd.clear();
displayRPM(rpm);

}

}

void changeThrottle(int throttle) {

// Read the current throttle value
int currentThrottle = readThrottle();

// Are we going up or down?
int step = 1;
if( throttle < currentThrottle )
step = -1;

// Slowly move to the new throttle value
while( currentThrottle != throttle ) {
esc.write(currentThrottle + step);
currentThrottle = readThrottle();
delay(throttleChangeDelay);
}

}

int readThrottle() {
int throttle = esc.read();

Serial.print("Current throttle is: ");
Serial.println(throttle);

return throttle;
}

// Ensure the throttle value is between 0 - 180
int normalizeThrottle(int value) {
if( value < 0 )
return 0;
if( value > 180 )
return 180;
return value;
}

int getRPM()
{
// sample for sampleTime in millisecs
int kount=0;
boolean kflag=LOW;
unsigned long currentTime=0;
unsigned long startTime=millis();
while (currentTime<=sampleTime)
{
if (digitalRead(hallPin)==HIGH)
{
kflag=HIGH;
}
if (digitalRead(hallPin)==LOW && kflag==HIGH)
{
kount++;
kflag=LOW;
}
currentTime=millis()-startTime;
}
int kount2rpm = int(60000./float(sampleTime))*kount;
return kount2rpm;
}

void displayRPM(int rpm)
{
lcd.clear();
// set the cursor to column 0, line 1
lcd.setCursor(0, 0);
// print the number of seconds since reset:
lcd.print(rpm,DEC);
lcd.setCursor(7,0);
lcd.print(“RPM”);
}

void displayBar(int rpm)
{
int numOfBars=map(rpm,0,maxRPM,0,15);
lcd.setCursor(0,1);
if (rpm!=0)
{
for (int i=0; i<=numOfBars; i++)
{
lcd.setCursor(i,1);
lcd.write(1023);
}
}
}

  if (key != NO_KEY)
  {
    int i;
  char buffer[4];
  lcd.print("number: ");
  lcd.print(key);
  fgets (buffer, 4, stdin);
  i = atoi (buffer);
  lcd.print(i);
  }

What do you think fgets() is doing? If NOTHING doesn't ring a bell, it should.

i tried your steps... i manage to get the keypad to function well...

I can't really see where you incorporated it.

Also, I just noticed this

  if (Servo.write() > 0) {

What is it supposed to do ?

hye guys… i still can’t control the bldc motor. i have use char and atoi… still cannot mapped the value into the bldc. i was hoping you guys can help me out here… i’m still new to this programming stuff and doing my best to understand… the code below is what i have tried so far trying to key in the kepad value and then received by the bldc motor. still can’t spin the bldc motor to the desired value. this is my code… tell me what modification i should make. i appreciate all the response in get from you…please guide guy…

#include <LiquidCrystal.h>
#include  <Keypad.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
// read the hall effect sensor on pin 2
const int hallPin=2;
const unsigned long sampleTime=1000;
const int maxRPM = 9000; 

#include <Servo.h> 
Servo esc;
int escPin = 11;
int minPulseRate = 700;
int maxPulseRate = 2000;
int throttleChangeDelay = 100;

const byte ROWS = 4; //four rows
const byte COLS = 3; //four columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {9,8,7,6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5,4,3}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad keypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup() {
  
  Serial.begin(9600);
  Serial.setTimeout(500);
  // Attach the the servo to the correct pin and set the pulse range
  esc.attach(escPin, minPulseRate, maxPulseRate); 
  // Write a minimum value (most ESCs require this correct startup)
  esc.write(0);
  

  pinMode(hallPin,INPUT);
  lcd.begin(16, 2);
  lcd.print("initializing");
  delay(1000);
  lcd.clear();
  
}

void loop() {

   char key = keypad.getKey();

  if (key != NO_KEY)
  {
   int i;
   char command[3];
   command[3]=key;
   i=atoi(key);
   lcd.setCursor (0,2); 
   lcd.print(key);
  }
    
    // Read the new throttle value
    int throttle = normalizeThrottle(atoi(key));
    
    // Print it out
    Serial.print("Setting throttle to: ");
    Serial.println(throttle);
    
    // Change throttle to the new value
    changeThrottle(throttle);

    delay(100);
  int rpm=getRPM();
  lcd.clear();
  displayRPM(rpm);
  
 

}


void changeThrottle(int throttle) {
  
  // Read the current throttle value
  int currentThrottle = readThrottle();
  
  // Are we going up or down?
  int step = 1;
  if( throttle < currentThrottle )
    step = -1;
  
  // Slowly move to the new throttle value 
  while( currentThrottle != throttle ) {
    esc.write(currentThrottle + step);
    currentThrottle = readThrottle();
    delay(throttleChangeDelay);
  }
  
}

int readThrottle() {
  int throttle = esc.read();
  
  Serial.print("Current throttle is: ");
  Serial.println(throttle);
  
  return throttle;
}

// Ensure the throttle value is between 0 - 180
int normalizeThrottle(int value) {
  if( value < 0 )
    return 0;
  if( value > 180 )
    return 180;
  return value;
}


 int getRPM()
{
  // sample for sampleTime in millisecs
  int kount=0;
  boolean kflag=LOW;
  unsigned long currentTime=0;
  unsigned long startTime=millis();
  while (currentTime<=sampleTime)
  {
    if (digitalRead(hallPin)==HIGH)
    {
      kflag=HIGH;
    }
    if (digitalRead(hallPin)==LOW && kflag==HIGH)
    {
      kount++;
      kflag=LOW;
    }
    currentTime=millis()-startTime;
  }
  int kount2rpm = int(60000./float(sampleTime))*kount;
  return kount2rpm;
}
    
void displayRPM(int rpm) 
{
  lcd.clear();
  // set the cursor to column 0, line 1
  lcd.setCursor(0, 0); 
  // print the number of seconds since reset:
  lcd.print(rpm,DEC);
  lcd.setCursor(7,0);
  lcd.print("RPM");
}
  char key = keypad.getKey();

  if (key != NO_KEY)
  {
    int i;
    char command[3];
    command[3] = key;
    i = atoi(key);
    lcd.setCursor (0, 2);
    lcd.print(key);
  }

This section of code will get you a single digit from the keypad and put it into the [u]fourth[/u] position of the command array which does not actually exist. Then you try to convert the command array to an integer but that would not work anyway because you have not terminated the array with a zero to turn it into a C style string. In any case, because you declare the array and i for that matter each time through loop() the values will be initialised to unknown values.

The idea is that you should read the keypad until either 3 characters have been received or the "end of input" character, perhaps '#' is received. As each character is received it is put into the char array at the current position, the index is incremented and a zero is put into the next position. If 3 characters or a '#' has been received then, and only then do you use atoi() on the char array to convert it to an integer.

Thanks UKHeliBOB.... I'll work on using the string and use your idea... One more question...Is the atoi(key) in the code correct in order to run the bldc motor after I change string to integer?

// Read the new throttle value
    int throttle = normalizeThrottle(atoi(key));
    
    // Print it out
    Serial.print("Setting throttle to: ");
    Serial.println(throttle);

atoi(key) will return the integer represented by the string key as long as key is a zero terminated array of chars containing digits.

using the code below, i manage to get the numbers on the lcd screen… but how to i keep it into a char array and use atoi to change the number to integer to get the motor spinning to the desire value…

#include   <Keypad.h>
#include <LiquidCrystal.h>

 LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
// Variables to hold entered number on Keypad
 int firstnumber=0;  
 int secondnumber=0;
 int thirdnumber=0;




// Keypad Setup
const byte ROWS = 4; // Four Rows
const byte COLS = 3; // Four Columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {9,8,7,6}; // Arduino pins connected to the row pins of the keypad
byte colPins[COLS] = {5,4,3}; // Arduino pins connected to the column pins of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );  // Keypad Library definition


void setup(void) {

  lcd.begin (16,2); 
}


void loop(){
  
  char keypressed = keypad.getKey();  // Get value of keypad button if pressed
  if (keypressed != NO_KEY){  // If keypad button pressed check which key it was
    switch (keypressed) {
      
      case '1':
        checknumber(1);
      break;
        
      case '2':
        checknumber(2);
      break;

      case '3':
        checknumber(3);
      break;

      case '4':
        checknumber(4);
      break;

      case '5':
        checknumber(5);
      break;

      case '6':
        checknumber(6);
      break;

      case '7':
        checknumber(7);
      break;

      case '8':
        checknumber(8);
      break;

      case '9':
        checknumber(9);
      break;

      case '0':
        checknumber(0);
      break;

      
    }
  }

}

void checknumber(int x)
{
  if (firstnumber == 0) { // Check if this is the first number entered
    firstnumber=x;
    String value = String(firstnumber);  //  Transform int to a string for display
    lcd.print(value); // Redraw Nokia lcd
    
  } else {
    if (secondnumber == 0) {  // Check if it's the second number entered
      secondnumber=x;
      String value = (String(firstnumber),String(secondnumber));
      lcd.print(value);

    } else {  // It must be the 3rd number entered
      thirdnumber=x;
      String value = (String(firstnumber),String(secondnumber),String(thirdnumber));
      lcd.print(value);

    }
  }
}

but how to i keep it into a char array

Well, first you have to have a char array. Get rid of the firstcnumber, secondnumber, and thirdnumber crap.

Create an array and an index into that array.

is this correct?

please point out my fault in the code…

#include <Keypad.h>
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);


const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns


// Define the Keymap
char keys[ROWS][COLS] = 
{
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};


// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = {9,8,7,6};
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = {5,4,3}; 

int i=0;
char name[3];			//this stores the entered IC number

// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  
  Serial.begin(9600);
}
//lcd.clear();
void loop()
{
   char key= kpd.getKey();
   
   if(key!=NO_KEY)  // Check for a valid key.
   {
    switch (key)
    
    {
        case '#':
         Serial.println();
         name[i]='\0';
         for(i=0;i<3;i++)
         {
           lcd.print(name[i]);
         }
         return i;
         break;
         
       case '*':
        i = 0;
        lcd.clear();
        default:
         name[i]=key;
         i++;
     }
   }
 }
char name[3];			//this stores the entered IC number

But allows no room for the require NULL terminator.

}
//lcd.clear();
void loop()
{

Get your delete key fixed.

         name[i]='\0';
         for(i=0;i<3;i++)
         {
           lcd.print(name[i]);
         }

You do NOT need to print the characters individually. Print the string.

       case '*':
        i = 0;
        lcd.clear();
        default:
         name[i]=key;
         i++;

ALL cases should have a break; statement.

You should ALWAYS check that there is room in the array before writing to the array.

what am i doing wrong here?? the error said keypad is not declare…

#include <Keypad.h>
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);


const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns


// Define the Keymap
char keys[ROWS][COLS] = 
{
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};


// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = {9,8,7,6};
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = {5,4,3}; 



// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  
  Serial.begin(9600);
  lcd.begin(16,2);
}

void loop()
{
   char key= kpd.getKey();
   
   if(key!=NO_KEY)  // Check for a valid key.
   if (key == '*')
  {
     lcd.clear();
     lcd.setCursor(0, 0);
     lcd.print("Currnt Spd = ");
     lcd.print(spd);
     lcd.setCursor(0, 1);
     lcd.print("Input Speed: ");
     digitalWrite(ledpin, HIGH);
     char digits[3];
     do {
       key = keypad.getKey();
     } while(key != '0' && key != '1' && key != '2');
     digits[0] = key;
     lcd.setCursor(12,1);
     lcd.print(key)
     do {
       key = keypad.getKey();
     } while(key != '0' && key != '1' && key != '2' && key != '3' && key != '4' && key != '5' && key != '6' && key != '7' && key != '8' && key != '9');
     digits[1] = key;
     lcd.setCursor(13,1);
     lcd.print(key)
          do {
       key = keypad.getKey();
     } while(key != '0' && key != '1' && key != '2' && key != '3' && key != '4' && key != '5' && key != '6' && key != '7' && key != '8' && key != '9');
     digits[2] = key;
     lcd.setCursor(14,1);
     lcd.print(key)
     int newSpeed = atoi(digits);
     //do something with the speed
  }
 } 
}
   char key= kpd.getKey();
       key = keypad.getKey();

Do you actually have two instances of the Keypad class, to go with two instances of the hardware?

I only need use 1 keypad hardware... So I have to choose between the two instances?

It works... Thanks so much!!!!!

where did i go wrong?? the program compiled… how ever no spinnning of bldc motor…

#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Servo.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
Servo esc;

int newSpeed;
const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns


// Define the Keymap
char keys[ROWS][COLS] = 
{
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};


// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = {9,8,7,6};
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = {5,4,3}; 
// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  esc.attach(11);
  Serial.begin(9600);
  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Servo: ");
}

void loop()
{
   char key= kpd.getKey();
   
   if (key !=NO_KEY )
  {
     char digits[3];
     do {
       key = kpd.getKey();
     } while(key != '0' && key != '1' && key != '2');
     digits[0] = key;
     lcd.setCursor(6,0);
     lcd.print(key);
     do {
       key = kpd.getKey();
     } while(key != '0' && key != '1' && key != '2' && key != '3' && key != '4' && key != '5' && key != '6' && key != '7' && key != '8' && key != '9');
     digits[1] = key;
     lcd.setCursor(7,0);
     lcd.print(key);
          do {
       key = kpd.getKey();
     } while(key != '0' && key != '1' && key != '2' && key != '3' && key != '4' && key != '5' && key != '6' && key != '7' && key != '8' && key != '9');
     digits[2] = key;
     lcd.setCursor(8,0);
     lcd.print(key);
     int newSpeed = atoi(digits);
     //do something with the speed
  }

    if (key == '#')
     {
      for( newSpeed= 0 ; newSpeed <= 180 ; newSpeed+=1); 
      esc.write ( newSpeed );
      delay(500);
     }

  
 }

Leaving aside how clumsy the code is, the digits array is not zero terminated and doesn’t have space for it anyway. There are also other problems, not least the fact that this for loop

   for ( newSpeed = 0 ; newSpeed <= 180 ; newSpeed += 1);

resets newspeed to zero so even if the input ar atoi() had worked you have just wiped out the value received.

You're saying that my code is entirely wrong?? How do I add the null terminate?