Introduction: Arduino - Keypad-Controlled Servo
For this project, we will take input from a keypad, process that input as an angle position, and move a servo motor based on the 3-digit angle acquired. The parts required are:
1 x Arduino Uno or similar
1 x Keypad (4x4)
1 x Servo Motor
I used a 4 x 4 keypad, but if you have a 3x4 keypad, it has a very similar hookup, so it could be easily adapted. Similarly, some Arduino kits come with a 4x4 push-button matrix which work in exactly the same way.
Step 1: Set Up the Hardware
The setup is straightforward. We will be using:
Pins 4 - 11: Keypad input
Pin 3: Servo motor output
VCC (5V)
GND (Ground)
The keypad input hooks up straight down the line. Hook up each wire on the keypad to pins 4 - 11 from right to left. The servo motor hooks directly up to 5V, ground, and pin 3. On my servo (Tower Pro SG90), the red wire was for 5V, brown was ground, and yellow was the output pin. Check the documentation for your servo motor.
Step 2: The Code
Let's look at the code:
#include <Keypad.h> #include <Servo.h> // Set up keypad variables: int numKeyPresses = 0; // Track number of key presses int maxKeyPresses = 3; // Only allow 3 digits to be entered int keyPresses[3] = { 0, 0, 0 }; // Initialize an empty array to hold input const byte numRows= 4; // # of rows on the keypad const byte numCols= 4; // # of columns on the keypad // Set up servo variables: int angle = 0; // Angle in degrees to position servo [0-180] int angleMultiplier = 1; // Multiply by each digit, divide by 10 on each input Servo servo; // Create the servo object int servoPin = 3; // Set the servo pin char keymap[numRows][numCols]= // Setup the keypad layout { {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'}, };
Here, we import Keypad and Servo libraries to help with some of the input and output processing. The numkeyPresses variable tracks how many entries have been input. When maxKeyPresses is reached, this will be reset to 0. The keymap is set up in a 4x4 matrix, mimicking the physical keypad.
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. byte rowPins[numRows] = { 11, 10, 9, 8 }; // Connect keypad COL0, COL1 and COL2 to these Arduino pins. byte colPins[numCols] = { 7, 6, 5, 4 }; // Create the Keypad Keypad kpd = Keypad( makeKeymap( keymap ), rowPins, colPins, numRows, numCols ); void setup() { Serial.begin(9600); // Start up serial comms resetAngleMultiplier(); // Start accepting numeric input servo.attach( servoPin ); // Attaches the servo to the servo object } // setup
Here we use a method called resetAngleMultiplier, which I will discuss in a moment. The idea is that we want to mathematically convert the input to a usable number, rather than characters. This sets us up to do that.
void loop() { char key = kpd.getKey(); if( key ) // Check for a valid key { if( key >= 0x41 && key <= 0x44 || key == 0x23 || key == 0x2A ) { resetInput(); Serial.println( "ERROR: Numeric input only!" ); } // ^ if invalid entry else // Else, entry is valid: { angle += angleMultiplier * ( key - 0x30 ); angleMultiplier /= 10; if( numKeyPresses == maxKeyPresses - 1 ) { setServo( angle ); // Use the input to turn servo resetInput(); } else { numKeyPresses++; } Serial.println( (String) angle ); } } // if( key ) } // loop
Here we take the input and process it. We will talk about how it is processed in a moment.
void setServo( int angle ) { if( angle > 180 ) angle = 180; Serial.println( "Setting servo to " + (String) angle + " degrees." ); servo.write( angle ); // Set the servo position } // setServo void resetAngleMultiplier() { angleMultiplier = 1; /* We started out with a multiplier of 10^0 (or 1). For each number we want to accept, we want to have a multiplier one order of magnitude greater. So, for example, for 5 digits, the multiplier starts out as 10 000. */ for( int i = 0; i < maxKeyPresses - 1; i++ ) angleMultiplier *= 10; } // resetAngleMultiplier void resetInput() { resetAngleMultiplier(); // Reset the numeric input angle = 0; // Reset the angle numKeyPresses = 0; // Reset number of key presses }
The Math
In the loop, we check for non-numeric input and reset the numKeyPresses variable if detected. The part that does the conversion is: angle += angleMultiplier * ( key - 0x30 ). When we got the keypress, it is returned as a character from the keymap 2-diminsional array. key - 0x30 subtracts 30 in hexadecimal in order to get its numeric equivalent.
Then, we have to multiply it by angleMultiplier. The angle multiplier starts out at 100. So, for instance, if the first digit input is 3, the number added to the angle will be 300. Then divide the angle multiplier by 10 so that the next iteration, the angle multiplier will be 10. If 2 is input, it is multiplied by 10 and added, giving us 320. This continues until the end of the input.
I wrote this to be scaleable, allowing maxKeyPresses to be expanded. C++'s maximum integer value is 2147483647, so using this program, you could theoretically take up to 10 digits of input, as long as the actual key code did not add up to more than this. You could always use a long to store the input, but for our purposes, there is no need.
Applying the Math
So, now that we have our (probably overly-complicated) calculation, it is simply passed to the servo to position it to that particular angle. Here it is limited to 180 degrees of movement. If the numeric input is over 180, it is reset to 180 degrees and passed to the servo. This could have multiple applications, whether you wanted to implement a locking system in your home, a security camera positioner, or whatever you need it for.
Although this is not the only way to convert keypad input, this is one way that works well, and it turned out to be a fun experiment with computing and mathematical relationships as well.
5 Comments
Question 1 year ago
i dont know how to set the password??
Question 3 years ago
Hey! Here's my code,somehow its not working... My servo motor moves for the 1st two times then stops,please help!
#include <Keypad.h>
#include <Servo.h>
// Set up keypad variables:
int numKeyPresses = 0; // Track number of key presses
int maxKeyPresses = 3; // Only allow 3 digits to be entered
int keyPresses[3] = { 0, 0, 0 }; // Initialize an empty array to hold input
const byte numRows = 4; // # of rows on the keypad
const byte numCols = 4; // # of columns on the keypad
// Set up servo variables:
int angle = 180; // Angle in degrees to position servo [0-180]
int angleMultiplier = 1; // Multiply by each digit, divide by 10 on each input
Servo servo; // Create the servo object
int servoPin = 3; // Set the servo pin
char keymap[numRows][numCols] = // Setup the keypad layout
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'},
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[numRows] = { 11, 10, 9, 8 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[numCols] = { 7, 6, 5, 4 };
// Create the Keypad
Keypad kpd = Keypad( makeKeymap( keymap ), rowPins, colPins, numRows, numCols );
void setup()
{
Serial.begin(9600); // Start up serial comms
resetAngleMultiplier(); // Start accepting numeric input
servo.attach( servoPin ); // Attaches the servo to the servo object
} // setup
void loop()
{
char key = kpd.getKey();
if ( key ) // Check for a valid key
{
if ( key >= 0x41 && key <= 0x44 || key == 0x23 || key == 0x2A )
{
resetInput();
Serial.println( "ERROR: Numeric input only!" );
} // ^ if invalid entry
else // Else, entry is valid:
{
angle += angleMultiplier * ( key - 0x30 );
angleMultiplier /= 10;
if ( numKeyPresses == maxKeyPresses - 1 )
{
setServo( angle ); // Use the input to turn servo
resetInput();
}
else
{
numKeyPresses++;
}
Serial.println( (String) angle );
}
} // if( key )
} // loop
void setServo( int angle )
{
if ( angle > 180 )
angle = 180;
Serial.println( "Setting servo to " + (String) angle + " degrees." );
servo.write( angle ); // Set the servo position
} // setServo
void resetAngleMultiplier()
{
angleMultiplier = 1;
/* We started out with a multiplier of 10^0 (or 1). For each
number we want to accept, we want to have a multiplier one
order of magnitude greater. So, for example, for 5 digits, the
multiplier starts out as 10 000. */
for ( int i = 0; i < maxKeyPresses - 1; i++ )
angleMultiplier *= 10;
} // resetAngleMultiplier
void resetInput()
{
resetAngleMultiplier(); // Reset the numeric input
angle = 0; // Reset the angle
numKeyPresses = 0; // Reset number of key presses
}
3 years ago
Hi,I really need help. My servo motor is moving only the first two times,then it stops
#include <Keypad.h>
#include <Servo.h>
// Set up keypad variables:
int numKeyPresses = 0; // Track number of key presses
int maxKeyPresses = 3; // Only allow 3 digits to be entered
int keyPresses[3] = { 0, 0, 0 }; // Initialize an empty array to hold input
const byte numRows = 4; // # of rows on the keypad
const byte numCols = 4; // # of columns on the keypad
// Set up servo variables:
int angle = 180; // Angle in degrees to position servo [0-180]
int angleMultiplier = 1; // Multiply by each digit, divide by 10 on each input
Servo servo; // Create the servo object
int servoPin = 3; // Set the servo pin
char keymap[numRows][numCols] = // Setup the keypad layout
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'},
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[numRows] = { 11, 10, 9, 8 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[numCols] = { 7, 6, 5, 4 };
// Create the Keypad
Keypad kpd = Keypad( makeKeymap( keymap ), rowPins, colPins, numRows, numCols );
void setup()
{
Serial.begin(9600); // Start up serial comms
resetAngleMultiplier(); // Start accepting numeric input
servo.attach( servoPin ); // Attaches the servo to the servo object
} // setup
void loop()
{
char key = kpd.getKey();
if ( key ) // Check for a valid key
{
if ( key >= 0x41 && key <= 0x44 || key == 0x23 || key == 0x2A )
{
resetInput();
Serial.println( "ERROR: Numeric input only!" );
} // ^ if invalid entry
else // Else, entry is valid:
{
angle += angleMultiplier * ( key - 0x30 );
angleMultiplier /= 10;
if ( numKeyPresses == maxKeyPresses - 1 )
{
setServo( angle ); // Use the input to turn servo
resetInput();
}
else
{
numKeyPresses++;
}
Serial.println( (String) angle );
}
} // if( key )
} // loop
void setServo( int angle )
{
if ( angle > 180 )
angle = 180;
Serial.println( "Setting servo to " + (String) angle + " degrees." );
servo.write( angle ); // Set the servo position
} // setServo
void resetAngleMultiplier()
{
angleMultiplier = 1;
/* We started out with a multiplier of 10^0 (or 1). For each
number we want to accept, we want to have a multiplier one
order of magnitude greater. So, for example, for 5 digits, the
multiplier starts out as 10 000. */
for ( int i = 0; i < maxKeyPresses - 1; i++ )
angleMultiplier *= 10;
} // resetAngleMultiplier
void resetInput()
{
resetAngleMultiplier(); // Reset the numeric input
angle = 0; // Reset the angle
numKeyPresses = 0; // Reset number of key presses
}
Here's the code. Please help asap
Question 4 years ago
Can you give me the link of the keypad library used in this code?
Answer 4 years ago
https://github.com/Chris--A/Keypad
its here..