1. 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.
    Dismiss Notice

Clone IR Remote for Arduino Projects (IRlib2)

Discussion in 'Arduino' started by joshsstuff, Jul 1, 2017.

  1. joshsstuff

    joshsstuff New Member

    Joined:
    Sep 7, 2010
    Messages:
    20
    Likes:
    0
    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.

    [​IMG]

    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 (text):

    /* 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 (text):

    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 (text):

    /* 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: Jul 1, 2017
  2. Musicmanager

    Musicmanager Active Member

    Joined:
    Dec 4, 2014
    Messages:
    586
    Likes:
    48
    Location:
    Birmingham, UK
    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
     
  3. joshsstuff

    joshsstuff New Member

    Joined:
    Sep 7, 2010
    Messages:
    20
    Likes:
    0
    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!
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. jjw

    jjw Member

    Joined:
    Apr 16, 2012
    Messages:
    266
    Likes:
    15
    Location:
    Helsinki, Finland

    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
     
  6. joshsstuff

    joshsstuff New Member

    Joined:
    Sep 7, 2010
    Messages:
    20
    Likes:
    0
    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
     
  7. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,294
    Likes:
    647
    Location:
    Derbyshire, UK
    ONLINE
    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.
     
  8. joshsstuff

    joshsstuff New Member

    Joined:
    Sep 7, 2010
    Messages:
    20
    Likes:
    0
    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?

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

    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.

    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)

    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!
     
  9. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,294
    Likes:
    647
    Location:
    Derbyshire, UK
    ONLINE
    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.
     
  10. joshsstuff

    joshsstuff New Member

    Joined:
    Sep 7, 2010
    Messages:
    20
    Likes:
    0
    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 (text):


    #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: Jul 11, 2017

Share This Page