Building a Universal Remote with an Arduino

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.

13 Responses to “Building a Universal Remote with an Arduino”

  1. Steve Dickie Says:

    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/

  2. Building a universal remote with an Arduino | SquareCows Says:

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

  3. Ribeiro Santos Says:

    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

  4. Mark Says:

    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.

  5. Josh Says:

    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

  6. Mark Says:

    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!

  7. Tom Says:

    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?

  8. Arduino Prototype for a Sunrise Alarm » Zovirl Industries Says:

    [...] 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 [...]

  9. Arduino + iRobot Infrared Communication « bits & bytes Says:

    [...] 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 [...]

  10. Chris Says:

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

  11. Santy's Wiki: Arduino Links Says:

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

  12. Arduino-0012 microsecond timing « Rcaron’s Blog Says:

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

  13. Home Easy -duino « Notes from a small field Says:

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

Leave a Reply

Comment moderation is on, so you won't see your comment right away.