IR remote control of servo using Arduino
Got a little bit done of the control for the sound system… I wasn’t getting good results from the Sharp GP1U5 module I was using until I stumbled upon some work by Ken Shirriff. He has written an IRremote library that supports both sending and receiving and includes support for a few different protocols.
The supported protocols don’t seem to cover the remotes I’m playing with, but luckily, he also did a post on handling arbitrary remotes by generating a hash value. Using that as a starting point, I cobbled together a fairly simple proof of concept sketch.
/*
* IR Remote controlled servo
*
*
*
* IR Remote code from Ken Shirriff (www.arcfn.com), specifically this post:
* http://www.arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
*/
#include
#include
Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
#define LEDPIN 13
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
int volume = 0;
int max_volume = 180; // determined by max position of the servo
int mute = 0;
void setup()
{
irrecv.enableIRIn(); // Start the receiver
myservo.attach(9,600,2400); // attaches the servo on pin 9 to the servo object with pulse widths for Hitec
// servo
myservo.write(0); // tell servo to go to base position
delay(1000);
Serial.begin(9600);
}
// Compare two tick values, returning 0 if newval is shorter,
// 1 if newval is equal, and 2 if newval is longer
// Use a tolerance of 20%
int compare(unsigned int oldval, unsigned int newval) {
if (newval < oldval * .8) {
return 0;
}
else if (oldval < newval * .8) {
return 2;
}
else {
return 1;
}
}
// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
#define FNV_PRIME_32 16777619
#define FNV_BASIS_32 2166136261
/* Converts the raw code values into a 32-bit hash code.
* Hopefully this code is unique for each button.
*/
unsigned long decodeHash(decode_results *results) {
unsigned long hash = FNV_BASIS_32;
for (int i = 1; i+2 < results->rawlen; i++) {
int value = compare(results->rawbuf[i], results->rawbuf[i+2]);
// Add value into the hash
hash = (hash * FNV_PRIME_32) ^ value;
}
return hash;
}
void loop() {
if (irrecv.decode(&results)) {
unsigned long hash = decodeHash(&results);
switch (hash) {
case 0x4B12992B: // Vol Up
case 0x22D912B8:
Serial.println("Volume Up");
volume += 1;
if ( mute == 1 ) {
volume -= 1;
mute = 0;
}
break;
case 0x1BE8C80D: // Vol Down
case 0x776C6E79:
Serial.println("Volume Down");
volume -= 1;
if ( mute == 1 ) {
volume += 1;
mute = 0;
}
break;
case 0x92DFD41C:
Serial.println("Mute");
mute = 1;
break;
default:
Serial.print("'real' decode: ");
Serial.print(results.value, HEX);
Serial.print(", hash decode: ");
Serial.println(hash, HEX);
}
irrecv.resume(); // Resume decoding (necessary!)
if ( volume < 0 ) { volume = 0; };
if ( volume > max_volume ) { volume = max_volume; }
if ( mute == 1 ) {
myservo.write(0);
}
else {
myservo.write(volume);
}
}
}
I’m using a Hitec HS-325HB servo with this code, and I implemented volume controlling from two different remotes I had kicking around – only one had a mute button.
Mute is handled by moving the servo to the zero position, and the next volume up/down will unmute by returning the servo to the correct position.
With the Arduino side basically figured out, the next step is to figure out the best way to tie the volume control and Arduino together. One potential problem is that with the servo hooked up, turning the volume control manually will probably not be possible. I’ll probably add a mute button and up/down buttons to allow control without needing to find the remote control. Doing that should be simple enough, and make it a lot more user friendly.