Building a Universal Remote with an Arduino

November 13, 2008

It is really easy to build a universal remote using an Arduino. With just an infrared LED, it can impersonate remotes for your TV, fans, lights, etc. and can let you easily incorporate these into your electronics projects. You won’t even have to solder anything or void any warranties.

For a project I’m working on, I need to emulate the remote for a Lutron Maestro light dimmer. It uses a modulated IR signal, which is a common way for remotes to communicate and is easy to generate with an Arduino. The basic scheme is simple: each command is sent as a series of pulses representing bits, which can be either 1 or 0. To send a 1, you rapidly blink the LED on and off at 38 kHz, and for 0 you leave the LED off. (The 38 kHz modulation makes the signal more resistant to interference from other light sources).

Decoding the Signal

measuring signal with photodiode
To decode what the remote was sending, I used an oscilloscope and a small photodiode. The photodiode generates a small amount of voltage when light hits it, and responds to changes in light level quickly enough that the oscilloscope can draw a really nice plot of the signal. I have a Parallax USB oscilloscope, which is perfect for showing the command pulses and is just fast enough to find the modulation frequency. As an aside, I’m really happy with the Parallax oscilloscope for projects like this. It is simple to use and I love being able to save images to share with people.
Here’s what two of the commands from the dimmer remote look like. The top signal is the “fade lights up” command, and the bottom one is “fade lights down”:
oscilloscope image of 2 commands

I captured several different commands, then measured the length of all the pulses. Looking at all the commands, a couple patterns are obvious:

  • The entire command takes 82.8 ms (after which it immediately repeats, presumably because I held the button on the remote down a little too long).
  • The lengths of the on/off pulses are all multiples of 2.3 milliseconds (which means that the entire 82.8 ms command represents 36 bits of data).
  • The last four bits are always 0, so really each command is four bytes long, followed by four 0 bits

The particular remote I’m emulating has five commands, and once they are decoded they look like this:

fade up        = [255, 136, 130, 34]
fade down      = [255, 136, 130, 20]
full on        = [255, 136, 132, 184]
full off       = [255, 136, 189, 18]
memory recall  = [255, 136, 132, 183]

The one other missing piece of information is the modulation frequency which can be measured by zooming in on any of the pulses. This remote uses a frequency of 39.68 kHz. (In the plot below, it says the frequency is 3.96 kHz because I included 10 pulses in the measurement to increase accuracy)
oscilloscope image show modulation

Programming the Arduino

arduino

Using an Arduino makes the circuit really simple. I put an IR LED between pin 13 and ground. Since pin 13 has an internal resistor, that’s all that’s required. The code is also pretty straightforward:

/* Control a Lutron Maestro light dimmer */
#define BIT_IS_SET(i, bits)  (1 << i & bits)

// LED connected to digital pin 13
const int LED_PIN = 13;
// Width of a pulse, in microseconds
const int PULSE_WIDTH = 2300;
// # of bytes per command
const int COMMAND_LENGTH = 4;    

const int UP[]     = {255, 136, 130, 34};
const int DOWN[]   = {255, 136, 130, 20};
const int ON[]     = {255, 136, 132, 184};
const int OFF[]    = {255, 136, 189, 18};
const int RECALL[] = {255, 136, 132, 183};

void setup()
{
  pinMode(LED_PIN, OUTPUT);
}

/* Modulate pin at 39 kHz for give number of microseconds */
void on(int pin, int time) {
  static const int period = 25;
  // found wait_time by measuring with oscilloscope
  static const int wait_time = 9;  

  for (time = time/period; time > 0; time--) {
    digitalWrite(pin, HIGH);
    delayMicroseconds(wait_time);
    digitalWrite(pin, LOW);
    delayMicroseconds(wait_time);
  }
}

/* Leave pin off for time (given in microseconds) */
void off(int pin, int time) {
  digitalWrite(pin, LOW);
  delayMicroseconds(time);
}

/* Send a byte over the IR LED */
void send_byte(int bits) {
  for (int i = 7; i >= 0; i--)
  {
    if (BIT_IS_SET(i, bits)) {
      on(LED_PIN, PULSE_WIDTH);
    } else {
      off(LED_PIN, PULSE_WIDTH);
    }
  }
}

/* Send a full command */
void command(const int bytes[]) {
  for (int i = 0; i < COMMAND_LENGTH; i++) {
    send_byte(bytes[i]);
  }
  off(LED_PIN, 4 * PULSE_WIDTH);
}

void loop()
{
  command(UP);
  delay(1000);
  command(DOWN);
  delay(1000);
}

Checking the Arduino with the Oscilloscope

After programming the Arduino, I used the oscilloscope to check the output of the Arduino vs. the original remote. On my first attempt, the wait_time in on() was too long, so the command was stretched out. I hadn’t accounted for the fact that the digitalWrite() calls would consume some time, so I just decreased wait_time until the length of the overall command was correct. As you can see, the final synthesized command overlaps exactly with the authentic one. The green signal on top is from the remote, and the blue signal on the bottom is the arduino:
oscilloscope image of arduino and remote sending same command

Final Test

Once everything was ready to go, it was time for the last test: I tried using the Arduino in place of the remote and it worked! It was able to control the light dimmer flawlessly. This lets me finish my project, plus now that I have all the code written it should be easy to adapt to other remote control devices.


Comments

Great project. I am so doing this. What a great April Fools Joke. My son turns off all the lights when he plays video games. This year on April 1st, turning the light off will also turn off the TV.

On a side note, for people who don’t have an o-scope. You can use Audacity and a solar cell plugged into your microphone jack to do the same thing.

http://www.instructables.com/id/Cheap%2c-Easy-Light-Probe/

posted on November 18, 2008 by Steve Dickie

[...] More about Building a universal remote with an Arduino [...]

posted on November 18, 2008 by Building a universal remote with an Arduino | SquareCows

Hi,

Great Project!

And what about a universal remote RECEIVER? Hi, have several remotes (Samsung, Soundgraph,…) and want they command my robot. Anyone knows how to get arduino be a universal receiver?

Thanks a lot,
Ribeiro Santos

posted on December 3, 2008 by Ribeiro Santos

I know you can buy IR receiver modules fairly cheaply from places like Sparkfun (for example, http://www.sparkfun.com/commerce/product_info.php?products_id=8545). I suspect that’s the easiest/cheapest approach.

posted on December 6, 2008 by Mark

If you don’t have an Oscilloscope you could always make one out of your Arduino. http://accrochages.drone.ws/en/node/90. Pretty neat idea

posted on December 8, 2008 by Josh

Cool, so between Steve’s idea to use your computer’s line-in port and Josh’s idea to use an Arduino, everyone should be able to do the signal measurements even if they don’t have an oscilloscope. Thanks for the tips!

posted on December 9, 2008 by Mark

Thanks for this awesome post. You inspired me to do this project.
I was not comfy with using my sound port, and don’t have an O-scope. So I bought a $4 IR module at Radio Shack (they don’t have much, but hey, convenient in a pinch). Use it to read the decoded data on a digital pin on the Arduino, and voila. I can decode the on/off bits.
Can still be a bit of detective work (how many bits, does the signal get repeated, etc.), and I am sure when I get to generating my signal at the proper frequency I will have other challenges as well.
BTW – I am just doing this so I can take my remote for my fancy Cable box and switch channels and watch from my bedroom! Ultimate lazy no?

posted on December 9, 2008 by Tom

[...] it with a single IR LED. (You can read more about how to use the Arudino as a remote control in this post). The nice thing about controlling the dimmer wirelessly is that everything is 5 volts, and I [...]

posted on December 11, 2008 by Arduino Prototype for a Sunrise Alarm » Zovirl Industries

[...] code I found around the web.  Kudos to Mark Ivey, he’s done most of the work for us with his Universal Remote Arduino project. I’ve modified a bunch of the code to accommodate the IR spec for the iRobot. Here it [...]

posted on January 18, 2009 by Arduino + iRobot Infrared Communication « bits & bytes

Thanks alot for this tutorial. I used this info to make a homemade Slingbox and it works beautifully!!!

posted on January 20, 2009 by Chris

[...] Universal Remote with Arduino [...]

posted on January 29, 2009 by Santy's Wiki: Arduino Links

[...] Arduino Universal Remote <–great resource on the IR protocol Explore posts in the same categories: Uncategorized [...]

posted on January 29, 2009 by Arduino-0012 microsecond timing « Rcaron’s Blog

[...] Building a Universal Remote with an Arduino [...]

posted on February 5, 2009 by Home Easy -duino « Notes from a small field

[...] http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ via http://tinyurl.com/ir-remote-control <blockquote> To decode what the remote was sending, I used an oscilloscope and a small photodiode. The photodiode generates a small amount of voltage when light hits it, and responds to changes in light level quickly enough that the oscilloscope can draw a really nice plot of the signal. I have a <a href="http://www.parallax.com/tabid/136/List/1/ProductID/46/Default.aspx">Parallax USB oscilloscope</a>, which is perfect for showing the command pulses and is just fast enough to find the modulation frequency. As an aside, I’m really happy with the Parallax oscilloscope for projects like this. It is simple to use and I love being able to save images to share with people.<br> Here’s what two of the commands from the dimmer remote look like. The top signal is the “fade lights up” command, and the bottom one is “fade lights down”:<br> <img src="http://zovirl.com/2008/11/two_commands.jpg" alt="oscilloscope image of 2 commands"> </blockquote> (tags: saved ir howto oscilliscope modulation avr arduino project code infrared control wishlist remote usb protocol) [...]

posted on September 23, 2009 by links for 2009-09-22 « Talkabout

Today I will try to make such device.Thanks for the instruction

posted on September 29, 2009 by Evgeniy

how much will cost something like this. Thank you

posted on December 1, 2009 by pytho25

[...] Project Idea: “TV Remote Control for Giants” – A mashup of Ardumo and a Universal Remote with an Arduino [...]

posted on December 4, 2009 by | panoskolivanis.com

You can get an Arduino for about $20-$30. I don’t know how much the photodiode and infrared LED were. I expect you could get them for under $1. The oscilloscope I used is about $100 I think, but there were 2 comments at the top from Steve and Josh about cheap ways to build an oscilloscope.

posted on December 22, 2009 by Mark

$100 for an oscilloscope? Go to your local electronics store and pick up a three pin IR Receiver that takes up a single Arduino pin, for $4.50.

Not only is it cheaper, it’s way easier to read from and with a library like this:

http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm

You’ll be acting on specific buttons with a single line of code.

I’m new to this as well; check out my mini collection at http://www.vulcan.it.cx/arduino – There might be something useful there :)

posted on January 20, 2010 by Subby

Hello, thanks for the post. I got it to work with the remote I have. The problem is that the signal is really weak and it only works within a very close range (1ft). Is there a way to boost the signal? or is it because my signal is somehow off?

posted on February 15, 2010 by baombaom

Hey! There is one thing I did not understand?? How did tou get to those 4 ints arrays?? I just can’ t get it??

Can you help?? Thanks

posted on April 7, 2010 by Ricky

If I wanted to buy an Arduino to do this, do i have to find one that says Diecimila? I don’t know anything about arduinos and a little help would be appreciated.

posted on May 20, 2010 by Kapil

[...] code I found around the web.  Kudos to Mark Ivey, he’s done most of the work for us with his Universal Remote Arduino project. I’ve modified a bunch of the code to accommodate the IR spec for the iRobot. Here it [...]

posted on May 29, 2010 by Arduino + iRobot Infrared Communication | Adrian Lombard

you don’t by chance have a spec or mouser/digikey/etc. part # for that photodiode do you?

posted on July 1, 2010 by Rob Ray

Hello, we are trying to do the same thing with the Sony infrared protocol, but looking to your ‘on’ function we calculated that when you use 2300 on ‘time’ the real oscillation time results in 1656.
We got 1656 through (time/period) * (wait_time * 2) where the “2″ means the times we called delayMicroseconds(wait_time) inside the for loop.

Is that correct?

posted on August 24, 2010 by Carlos Eduardo

Rob Ray: No, it was just some photodiode I had laying around. I have no idea what the specs are on it.

Carlos Eduardo: In theory you are right. In practice, digitalWrite() takes a small amount of time so you need to account for that. I ended up determining the correct value for wait_time empirically: I set it to 12 initially, then measured the results with the oscilloscope. It wasn’t fast enough, so I changed it. Eventually I worked out that 9 was the best fit.

posted on October 3, 2010 by Mark