465

1

Posted

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 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>

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 };

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.

Recommendations

• Arduino Class

67,982 Enrolled

• Spotless Contest

We have a be nice policy.