• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Clone IR Remote for Arduino Projects (IRlib2)

Thread starter #1
Hello Gang!

I am trying to clone the IR signal of consumer electronics to give IR control to my Arduino.
(I wish to give the Arduino the ability to turn on and off a TV)
This seems simple enough, and there are several tutorials online, so, easy, right?

I've found several examples of how to copy the IR signal into the Serial Monitor my problem is re-transmitting them with my IR Led from my arduino.

Demo Hardware:


My breadboard example:
I'm using an detector to collect the IR signals, and a 940nm IR LED to transmit.



Most of the tutorials I find on the internet are based on outdated IR Libraries.
(I don't mind this, as long as I can get them to work)

After failing to transmit the captured codes from my IR Led I tired the examples from the new IRlib2 library.

I've tried the "rawRecv" example sketch and successfully captured the timing data.


Code:
/* rawR&cv.ino Example sketch for IRLib2
 *  Illustrate how to capture raw timing values for an unknow protocol.
 *  You will capture a signal using this sketch. It will output data the
 *  serial monitor that you can cut and paste into the "rawSend.ino"
 *  sketch.
 */
// Recommend only use IRLibRecvPCI or IRLibRecvLoop for best results
#include <IRLibRecvPCI.h>

IRrecvPCI myReceiver(2);//pin number for the receiver

void setup() {
  Serial.begin(9600);
  delay(2000); while (!Serial); //delay for Leonardo
  myReceiver.enableIRIn(); // Start the receiver
  Serial.println(F("Ready to receive IR signals"));
}

void loop() {
  //Continue looping until you get a complete signal received
  if (myReceiver.getResults()) {
    Serial.println(F("Do a cut-and-paste of the following lines into the "));
    Serial.println(F("designated location in rawSend.ino"));
    Serial.print(F("\n#define RAW_DATA_LEN "));
    Serial.println(recvGlobal.recvLength,DEC);
    Serial.print(F("uint16_t rawData[RAW_DATA_LEN]={\n\t"));
    for(bufIndex_t i=1;i<recvGlobal.recvLength;i++) {
      Serial.print(recvGlobal.recvBuffer[i],DEC);
      Serial.print(F(", "));
      if( (i % 8)==0) Serial.print(F("\n\t"));
    }
    Serial.println(F("1000};"));//Add arbitrary trailing space
    myReceiver.enableIRIn();      //Restart receiver


I get this code from my samsung remote:

Code:
Do a cut-and-paste of the following lines into the
designated location in rawSend.ino

#define RAW_DATA_LEN 68
uint16_t rawData[RAW_DATA_LEN]={
4530, 4514, 562, 1686, 562, 1682, 566, 1682,
562, 590, 534, 590, 534, 590, 534, 590,
534, 590, 534, 1686, 558, 1686, 562, 1686,
562, 590, 534, 590, 534, 590, 530, 594,
530, 594, 530, 590, 534, 1686, 562, 590,
534, 590, 534, 590, 534, 590, 534, 594,
526, 594, 530, 1686, 562, 590, 534, 1690,
558, 1682, 562, 1686, 562, 1686, 562, 1686,
562, 1682, 562, 1000};
Here is the 'rawSend' example sketch:

Code:
/* rawSend.ino Example sketch for IRLib2
 *  Illustrates how to send a code Using raw timings which were captured
 *  from the "rawRecv.ino" sample sketch.  Load that sketch and
 *  capture the values. They will print in the serial monitor. Then you
 *  cut and paste that output into the appropriate section below.
 */
#include <IRLibSendBase.h>    //We need the base code
#include <IRLib_HashRaw.h>    //Only use raw sender

IRsendRaw mySender;

void setup() {
  Serial.begin(9600);
  delay(2000); while (!Serial); //delay for Leonardo
  Serial.println(F("Every time you press a key is a serial monitor we will send."));
}
/* Cut and paste the output from "rawRecv.ino" below here. It will
 * consist of a #define RAW_DATA_LEN statement and an array definition
 * beginning with "uint16_t rawData[RAW_DATA_LEN]= {…" and concludes
 * with "…,1000};"
 */





/*
 * Cut-and-paste into the area above.
 */
  
void loop() {
  if (Serial.read() != -1) {
    //send a code every time a character is received from the
    // serial port. You could modify this sketch to send when you
    // push a button connected to an digital input pin.
    mySender.send(rawData,RAW_DATA_LEN,36);//Pass the buffer,length, optionally frequency
    Serial.println(F("Sent signal."));
  }
}


Hardware


I'm using a 940nm IR LED driven by a 2222a BJT.
I used the diagram from a tutorial that used a 4.6K resistor on the base.
(should I have a current limiter for the IR LED?)

Here is my question:


After I paste the timing code into "rawSend" How do I code the LED to turn on and off with the appropriate timing?

I've tried many tutorials I found online, but perhaps because they use a different library, I'm not having success.

I've tried examples like these:



Code: http://howtomechatronics.com/tutorials/arduino/control-any-electronics-with-a-tv-remote-arduino-ir-tutorial/]

http://howtomechatronics.com/tutori...tronics-with-a-tv-remote-arduino-ir-tutorial/

http://www.instructables.com/id/Arduino-Infrared-Remote-tutorial/

Using IR commands to control consumer electronics is something I'd like to use a lot once I figure it out.
Any tips would be greatly appreciated!

Thanks!
 
Last edited:
#2
Forgive me if this is niaive, but shouldn't that 4.6k resistor be connected to the base of the 2222a, not the emitter ?


S
 
Thread starter #3
Forgive me if this is niaive, but shouldn't that 4.6k resistor be connected to the base of the 2222a, not the emitter ?


S
Hello Mmanager,

It is on the base ;)
(optical illusion)
And I now have a 460 ohm resistor limiting the current to the IR Led (although I could probably leave it out based on my experiments with it)

I realize after I posted this question that there are SEVERAL ways to accomplish the task of sending IR signals to a device.
(I found this out after I started researching it!)

So I am going to be more clear about what my objectives are, that should distil the options down to what my needs are specifically.

Objectives:
1) Arduino hardware:

As stated in the topic description, I wish to use this in my Arduino projects.
(I have one started that I'm stuck on, but also I will need this ability for future Arduino projects)

2) Protocol agnostic:
Since I wish to use this method with all sorts of IR devices, I like the idea of collecting "raw" data from the remote pointed at the IR receiver and simply recording the pulse data.
This should work with any remote!

I'm aware that reverse engineering manufacturer protocols has it's benefits, especially if I wish to send multiple signals.
However, to just turn on a power button here or there this seems overkill, and will complicate my sketch.

3) Simple is best!
(for now)
If I can get away with a string of 'High' and 'Low' timings instead of evoking serial communication, or extra libraries, I'm all for it!

Is there a simple way to just record the "ON" and "OFF" times and blink the LED with direct code?
(this would require a different capture technique or some translation it seems?)

Once I am confident, and get this up and running, I am willing to try more complex methods to learn.

Any tips would be most appreciated!
 
Thread starter #5
This link downloads a pdf of the Samsung IR controller.
https://www.google.fi/url?sa=t&sour...ggfMAE&usg=AFQjCNFeEa_QlSTTwnN9rs2O7fP2h4cVrw

The transmitter sends pulses of different length of a 38kHz carrier.
Your raw data contains the approximate length of these pulses in usecs.
The nominal lengths are:
start 4.5ms on 4.5ms off
bit 0: 0.56ms on 0.56ms off
bit 1: 0.56ms on 1.69ms off
Thanks jjw!
I will need to get access to my oscilloscope to utilize this data, hopefully tomorrow.

I thought I would share the research I have been doing on this problem:

These libraries are made to do all of this with minimal code, but this is just one way to "skin the cat"
Another way is to decode the bits manually, then re-transmit
(I can have access to an oscilloscope tomorrow, hopefully I can line up all of my O-Scope work while I'm there.)

Backwards Engineering video:

This is the process Dave from the EEVBlog did for his remote, using his scope (and later a logic analyzer for finer measurement of the carrier)
his code is here:
(Note: Dave takes in consideration the delay time for the "digital write" command and also the "stop Bit" at the end.



Code (Text):
  1. //*****************************************
  2. // NEC (Japanese) Infrared code sending library for the Arduino
  3. // Send a standard NEC 4 byte protocol direct to an IR LED on the define pin
  4. // Assumes an IR LED connected on I/O pin to ground, or equivalent driver.
  5. // Tested on a Freetronics Eleven Uno compatible
  6. // Written by David L. Jones www.eevblog.com
  7. // Youtube video explaining this code:
  8. // License: Creative Commons CC BY
  9. //*****************************************

  10. #define IRLEDpin 2 //the arduino pin connected to IR LED to ground. HIGH=LED ON
  11. #define BITtime 562 //length of the carrier bit in microseconds
  12. //put your own code here - 4 bytes (ADDR1 | ADDR2 | COMMAND1 | COMMAND2)
  13. unsigned long IRcode=0b11000001110001111100000000111111;

  14. // SOME CODES:
  15. // Canon WL-D89 video remote START/STOP button = 0b11000001110001111100000000111111

  16. void setup()
  17. {
  18. }

  19. void IRsetup(void)
  20. {
  21. pinMode(IRLEDpin, OUTPUT);
  22. digitalWrite(IRLEDpin, LOW); //turn off IR LED to start
  23. }

  24. // Ouput the 38KHz carrier frequency for the required time in microseconds
  25. // This is timing critial and just do-able on an Arduino using the standard I/O functions.
  26. // If you are using interrupts, ensure they disabled for the duration.
  27. void IRcarrier(unsigned int IRtimemicroseconds)
  28. {
  29. for(int i=0; i < (IRtimemicroseconds / 26); i++)
  30. {
  31. digitalWrite(IRLEDpin, HIGH); //turn on the IR LED
  32. //NOTE: digitalWrite takes about 3.5us to execute, so we need to factor that into the timing.
  33. delayMicroseconds(9); //delay for 13us (9us + digitalWrite), half the carrier frequnecy
  34. digitalWrite(IRLEDpin, LOW); //turn off the IR LED
  35. delayMicroseconds(9); //delay for 13us (9us + digitalWrite), half the carrier frequnecy
  36. }
  37. }

  38. //Sends the IR code in 4 byte NEC format
  39. void IRsendCode(unsigned long code)
  40. {
  41. //send the leading pulse
  42. IRcarrier(9000); //9ms of carrier
  43. delayMicroseconds(4500); //4.5ms of silence

  44. //send the user defined 4 byte/32bit code
  45. for (int i=0; i<32; i++) //send all 4 bytes or 32 bits
  46. {
  47. IRcarrier(BITtime); //turn on the carrier for one bit time
  48. if (code & 0x80000000) //get the current bit by masking all but the MSB
  49. delayMicroseconds(3 * BITtime); //a HIGH is 3 bit time periods
  50. else
  51. delayMicroseconds(BITtime); //a LOW is only 1 bit time period
  52. code<<=1; //shift to the next bit for this byte
  53. }
  54. IRcarrier(BITtime); //send a single STOP bit.
  55. }

  56. void loop() //some demo main code
  57. {
  58. IRsetup(); //Only need to call this once to setup
  59. IRsendCode(IRcode);
  60. delay(5000);
  61. IRsendCode(IRcode);
  62. while(1);
  63. }
Here is an explanation of 2 data formats RC5 and NEC. (just the sort of thing I was trying to avoid getting involved in lol)
http://www.vishay.com/docs/80071/dataform.pdf

This post is from the "IRremote library" author (not the IRlib2 library mentioned in my original post)
"Using arbitrary remotes with the Arduino IRremote library" (protocol agnostic)
http://www.righto.com/2010/01/using-arbitrary-remotes-with-arduino.html

This is the general overview of the entire library:
http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html

This guy was able to use a backwards photodiode to reverse engineer with his O-scope!
http://www.zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/

Here is his code:

Code (Text):
  1. /* Control a Lutron Maestro light dimmer */
  2. #define BIT_IS_SET(i, bits) (1 << i & bits)

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

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

  14. void setup()
  15. {
  16. pinMode(LED_PIN, OUTPUT);
  17. }

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

  23. for (time = time/period; time > 0; time--) {
  24. digitalWrite(pin, HIGH);
  25. delayMicroseconds(wait_time);
  26. digitalWrite(pin, LOW);
  27. delayMicroseconds(wait_time);
  28. }
  29. }

  30. /* Leave pin off for time (given in microseconds) */
  31. void off(int pin, int time) {
  32. digitalWrite(pin, LOW);
  33. delayMicroseconds(time);
  34. }

  35. /* Send a byte over the IR LED */
  36. void send_byte(int bits) {
  37. for (int i = 7; i >= 0; i--)
  38. {
  39. if (BIT_IS_SET(i, bits)) {
  40. on(LED_PIN, PULSE_WIDTH);
  41. } else {
  42. off(LED_PIN, PULSE_WIDTH);
  43. }
  44. }
  45. }

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

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

I am trying to build off of the techniques already available.
But I'm not quite successful in adapting these projects for my purposes.
Small (& large) traps keep getting me! lol
 

Nigel Goodwin

Super Moderator
Most Helpful Member
#6
3) Simple is best!
(for now)
If I can get away with a string of 'High' and 'Low' timings instead of evoking serial communication, or extra libraries, I'm all for it!

Is there a simple way to just record the "ON" and "OFF" times and blink the LED with direct code?
(this would require a different capture technique or some translation it seems?)
Simple is easy :D

As long as you're just using one IR coding system, you just need to design a method of storing the data efficiently, and then read it out of the array and transmit it. My PIC tutorials show how to do this with the Sony SIRC's system, but transmitting is trivial for any system - and I've used the tutorial code (with very minor changes) for transmitting various different IR systems.

Receiving is far more complicated, and receiving multiple IR systems greatly more so - because you have to implement a scheme for storing a wide range of completely different data types.

As you're using Arduino, you already know there are numerous libraries available for doing exactly what you want, you just need to persevere in order to get them to work - it's amazing how few Arduino projects seem to work without having to tweak them.
 
Thread starter #7
Simple is easy :D
As long as you're just using one IR coding system, you just need to design a method of storing the data efficiently, and then read it out of the array and transmit it.
Hello Nigel.
I only foresee me needing 1 or 2 commands, not decoding the entire system (which many have done and posted)
So only "one IR coding system" at a time per se.

Somehow these cheap universal remotes have a "learn" function in which they can immediately spit out any code once they have seen and stored it once.
They must have simplified their approach to "cloning" the raw signal, wouldn't you think?

My PIC tutorials show how to do this with the Sony SIRC's system, but transmitting is trivial for any system - and I've used the tutorial code (with very minor changes) for transmitting various different IR systems.
Do I have to understand the underlying protocols and data, to simply mirror a transmission?
(I'll admit, it would surely make storage and execution simpler, and more accurate, but I don't need a true clone, a xerox will do ;)

Receiving is far more complicated, and receiving multiple IR systems greatly more so - because you have to implement a scheme for storing a wide range of completely different data types.
I'm fine with recording the received data and writing the code in each case.
I am not creating a universal remote, I just need to learn a signal and then find a way to deliver it in an output.
(no data transmission is required, or else I would outline a single protocol and stick with it, I'm simply replacing a remote control with and arduino)
In my case, all I need is a power button to turn on a TV.

As you're using Arduino, you already know there are numerous libraries available for doing exactly what you want, you just need to persevere in order to get them to work - it's amazing how few Arduino projects seem to work without having to tweak them.
Yeah, I'm finding that out!
I won't have access to my "tweaking tools" like oscilloscope until tomorrow.

Like in this example:
http://labdegaragem.com/profiles/blogs/controlando-ar-condicionado-utilizando-arduino-e-led
(Translated)

Software and Library Used:



Changes to the IRremote library



After several failed attempts, I succeeded by making some changes to the IRremote library

The first change in the library was to modify the IRremoteInt.h file, look for the line #define RAWBUF 100, and change the value to 200.

#define RAWBUF 200



The second change in the IRremoteInt.h file on line #define _GAP 5000 changes the value of the _GAP to 50000.

#define _GAP 50000



In most cases only these two modifications are sufficient for the operation of the system, however in some cases it is necessary to change the PWM pin of the sender. For this you must change the IRremoteInt.h file.

Change rows:

// Arduino Duemilanove, Diecimila, LilyPad, Mini, Wire, Nano, etc.
#else
// # define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3



For:

// Arduino Duemilanove, Diecimila, LilyPad, Mini, Wire, Nano, etc.

#else
#define IR_USE_TIMER1 // tx = pin 9
// # define IR_USE_TIMER2 // tx = pin 3
Thanks for the encouragement!
I would be in a better mind set to learn from this experience if it wasn't holding up my primary project!
But it has been educational!
 

Nigel Goodwin

Super Moderator
Most Helpful Member
#8
Somehow these cheap universal remotes have a "learn" function in which they can immediately spit out any code once they have seen and stored it once.
They must have simplified their approach to "cloning" the raw signal, wouldn't you think?
As I said, you've got to come up with some sensible and efficient way to decode and store the signal - that works with numerous different coding systems.

Studying the Arduino libraries will give you some insight as to at least one way of doing it.
 
Thread starter #9
As I said, you've got to come up with some sensible and efficient way to decode and store the signal - that works with numerous different coding systems.

Studying the Arduino libraries will give you some insight as to at least one way of doing it.
I found an awesome video that explains every step!
The only catch is that he is using a computer to send the IR pulse codes through the Com of the Arduino.
I'm going to copy his project, if it works, I'll modify it to send from the Arduino.

His code: (for both capture and send:

Code:
#include <IRremote.h>

IRrecv receiver(2); // receiver is connected to pin2
IRsend sender;
decode_results results;

long repetitions;
long count;
unsigned int durations[100];
void (*reset)(void) = 0;

void setup() {
  Serial.begin(9600);
  receiver.enableIRIn(); // start receiving signals
}

void loop() {

  // check for text from the PC
  // the PC sends a string containing "r,n,a,b,c,d,e,..." where r is how many times to repeat the command,
  // n is the number of durations, and a/b/c/d/e/... are the durations.
  // the durations are how long each mark and space period of an infrared command should last, in microseconds.
  if(Serial.available()) {

    // parse the text
    repetitions = Serial.parseInt();
    count = Serial.parseInt();
    for(int i = 0; i < count; i++)
      durations[i] = Serial.parseInt();

    // send the command using 40kHz PWM
    for(int i = 0; i < repetitions; i++) {
      sender.sendRaw(durations, count, 40);
      delay(50);
    }

    // for a bit of fault tolerance, reset the arduino after receiving any command
    reset();
   
  }

  // check if a decoded infrared signal is available
  if(receiver.decode(&results)) {
    Serial.println(results.value, HEX);
    Serial.print(results.rawlen - 1);
    for(int i = 1; i < results.rawlen; i++) {
      unsigned int number = results.rawbuf[i] * USECPERTICK;
      Serial.print(",");
      Serial.print(number);
    }
    Serial.println("");
    receiver.resume();
  }
 
}
 
Last edited:

Latest threads

EE World Online Articles

Loading

 
Top