Implement Yourself

This page is only for those who do not want to use the prebuilt module. The prebuilt module is recommended since it takes care of all the communication and the decoding of the IR signals. If you make your own implementation it is important to keep in mind that your system needs to be stable and should always be able to decode the IR signals even if you main CPU hangs or go into deadlock. This is crucial since the kill switch should always be operative.

Implement the remote start and kill switch by yourself
If you prefer to implement everything by yourself you can follow the documentation on this page.

Hardware

Hardware remote start
The hardware of the remote start system fairly simple: it is mainly a 38khz IR receiver connected to one of the I/O pins on the microcontroller. Any standard 38Khz IR receiver should do, you can find two examples here: VishayVishay at sparkfun. In the datasheets of the components you can also find examples of how to use the receiver and what additional components that is necessary (usually the receiver requires a resistor and a capacitor).

Status LED
The contestant have to provide a LED, display or something similar that can give feedback of what state the robot is in.

Hardware Kill switch
The implementation of the kill switch is the same as for the prebuilt module, the contestant is responsible for implementing this kill switch which will ensure that the referee can cut the power to the motors. This functionality is only mandatory for the 3kg robots.
Click here for an example of how to implement the kill switch using a relay.
Click here for an example of how to implement the kill switch using an optocoupler.

Input and output pins
The microcontroller will have to provide at least total of 2 I/O pins (3 for the 3kg class): 1 input pin for the IR receiver and 1 output pin for the LED. For the 3kg class, at least one additional output for the kill switch circuit is needed.

Software

The microcontroller to which the IR receiver is connected have to take care of the reading the commands from the receiver. The commands are sent using the standard RC-5 protocol.

The 5 bit address will be fixed which means the system will listen for a RC-5 signal only with this pre-decided address. The next 5 bits in the command will tell which dohyo the signal belongs to and the last bit will tell if the robot is suppose to start or stop. A one means start and a zero means stop. To change what dohyo identifier to listen for a programming command is sent. This package will consist of a fixed system address (the programming address) and the new stop command.

  • The fixed address used for starting and stopping the robots: 0x07 (hexadecimal)
  • The fixed address used for programming: 0x0B (hexadecimal)’

A detailed state chart for the module operation can be found here.

Caution: The implentation of the RC-5 communication is usally done with very cheap components therefore the timing is never perfect. This have to be considered when designing the code, such as adding a tolerance for the the lengths of bits. Consult the source code examples listed in the end for further details.

Non-volatile memory
The microcontroller should save the current state in a non-volatile memory. This is to ensure robustness of the system. If the microcontroller should reset it will then return to the last saved state (in the same way the prebuilt module works).

Source code
Source code can be found on Github under Source, look at the “Generic” examples.

Example of operation

Here follows a short example of operation, which is an example of how an implementation should work. It goes through start, stop and program.

Your robot receives an RC-5 package when in Power-ON or Started state with the following data:

  • rc5Address = 0x0B (11 in decimal) (Programming address)
  • rc5Command = 0x12 (18 in decimal, 0b00010010 in binary) (Dohyo with start/stop-bit cleared)

This means that your robot competes on dohyo with base command 18. Your robot should save this number as the stop command and should also calculate the start command as 19.

stopCommand = rc5Command & 0xFE; //or 0b11111110 if your compiler supports this
startCommand = (rc5Command & 0xFE) + 1;

At this point, the robot should go into Power-ON state and wait for a start command (even if the current state was Started). The robot should also stop its motors. Remember to save this state and the stopCommand into a non-volatile memory. The robot should also signal that it has been programmed by blinking an LED 2 times quickly (about 500ms between each blink).

Next, your robot receives an RC-5 package when in Power-ON state with the following data:

  • rc5Address = 0x07 (Competition system address, also defined in the standard as Experimental)
  • rc5Command = 0x13 (19 in decimal, 0b00010011 in binary) (Dohyo with start/stop-bit set)

This means that your robot is allowed to start, since it received the start command. It should go into STARTED state and show this using an LED (LED on as long as it’s in started state).

Next, your robot receives an RC-5 package in any state with the following data:

  • rc5Address = 0x07 (Competition system address, also defined in the standard as Experimental)
  • rc5Command = 0x12 (18 in decimal, 0b00010010 in binary) (Dohyo with start/stop-bit cleared)

This means that your robot must stop, since the stop command is received. Shut off your motors, set your state to STOPPED and save it to the non-volatile memory. Your robot should also indicate that it’s in stopped by blinking an LED slowly. It should not listen to any further commands until it has gone through a power cycle.

When your robot boots, it should read the current state and stopCommand from the non-volatile memory and calculate the startCommand as:
startCommand = stopCommand +1; //for instance
It should also restore its behaviour according to the current state. If the current state is Stopped, simple set the current state to Power-ON and proceed as normal.

To make the code more secure, you should add an exception case for when the data read is not any of the allowed states (which could happen after programming or if the memory has become corrupt for some reason for instance).

Quick reference

This is intended as a quick-check to see if your implementation complies with the remote-start system. To comply, your implementation should…

  • Decode RC-5 signals using 38kHz carrier frequency.
  • Listen to commands only sent on the predefined addresses (see “software” above).
  • Signal the current state, preferably using at least an LED as described for the prebuilt module.
  • Be able to be listen to different start commands used at different dohyos (it should support “programming”).
  • Save the current state and dohyo address into a non-volatile memory.
  • Use a state machine as described here.
  • (only for the 3kg class) cut power to the motors when stop command is received.

And finally: If you have your own implementation and you come to a competition, make sure you tell the referee how your implementation behaves.

16 thoughts on “Implement Yourself

  1. I’ve implemented that with Vishay TSOP 31236 and Arduino Nano

    1. Great! Could you send us your code so that we may help others implement it using Arduino?

      1. Shure, just push the website link

      2. The website can be found by clicking on Oleg Lyan’s username, or by going here;

        http://destroyer3000.blogspot.no/2013/03/start-module-implement-yourself.html

        1. I have a build problem for Arduino Nano (atmega328p@16MHz).
          Can you send link for correct FSM library or compiled hex?

  2. How do you program the remote? Do you use avrdude with a Makefile? If so – what does the Makefile look like?

  3. For anyone making the remote – you should use the Atmega168PA. I first tried with the Atmega48 which is listed as an alternative chip in the componentlist, but couldn’t get the .hex file from GitHub to work until I switched over to Atmega168PA-AUR.

    For programming the remote (using an USB ASP from ebay) I used the command;

    avrdude -c usbasp -p m168 -F -U flash:w:remoteControl.hex

    When you include the crystal (I used 8MHz, mouser part: 559-FOXS080-20-LF), which is listed as optional in the component list, you should not have to change the fusebits.

  4. Hi,
    I write this code for simple “Remote_Control” on custom Arduino Uno shield.
    It’s working well !!!!!!

    /* IR_Remote_Shield_UNO.ino May 2017
    * ********* TRANSMITTER IR REMOTE START MODULE WITH ARDUINO UNO CUSTOM SHIELD*********
    * ********* https://p1r.se/startmodule/implement-yourself/ ***************
    * ********* IMPORTANT: insert Library “IRremote-multiSend” **************
    * 0° IR LED must be connected to Arduino PWM pin 3(Arduino Uno) doesn’t used
    * 1° IR LED must be connected to Arduino PWM pin 10(Arduino Uno) used for START & STOP
    * 2° IR LED must be connected to Arduino PWM pin 9(Arduino Uno) used for PROGRAM
    */

    #include // IMPORTANT: insert Library “IRremote-multiSend”
    //IRsend irsend; // doesn’t used
    IRsend1 irsend1; // used for START & STOP (Arduino Uno pin 10)
    IRsend2 irsend2; // used for PROGRAM (Arduino Uno pin 9)

    #define CMD_BIS 0b100000000000 // only for reply original IR TRANSMITTER
    #define CMD_START 0b000000000001 // last START/STOP bit SET = START
    #define CMD_STOP 0b000000000000 // last START/STOP bit CLEARED = STOP
    #define ADR_CMD 0b000111000000 // fixed address used for START & STOP: 0×07 (hexadecimal)
    #define ADR_PRG 0b001011000000 // fixed address used for PROGRAM: 0x0B (hexadecimal)
    #define NUM_BIT 12 // number bits for RC5 protocol
    #define INTERVAL_IR 114 // interval for correct RC5 protocol
    #define REPEAT_IR 200 // interval for repeat IR send
    #define PRG_BLINK 400 // time blink for PROGRAM
    #define SW_START A5 // switch START (analog input used as digital)
    #define SW_STOP A4 // switch STOP (analog input used as digital)
    #define SW_PRG 12 // switch PROGRAM
    //#define ADDR0 xx // DIP ADDRESS 0 -> doesn’t used on shield UNO
    //#define ADDR1 xx // DIP ADDRESS 1 -> doesn’t used on shield UNO
    //#define ADDR2 xx // DIP ADDRESS 2 -> doesn’t used on shield UNO
    #define ADDR3 11 // DIP ADDRESS 3
    #define ADDR4 8 // DIP ADDRESS 4
    #define LED_Y 13 // Led yellow on shield

    bool state_IR = 0; // sate IR -> 0(false) = PowerON/STOP, 1(true) = RUN
    unsigned int dip_prg; // variable for MASK ADDRESS

    void setup()
    {
    // initialize the digital/analog pin as an input
    pinMode(SW_START, INPUT_PULLUP);
    pinMode(SW_STOP, INPUT_PULLUP);
    pinMode(SW_PRG, INPUT_PULLUP);
    pinMode(ADDR3, INPUT_PULLUP);
    pinMode(ADDR4, INPUT_PULLUP);
    // initialize the digital pin as an output.
    pinMode(LED_Y, OUTPUT);
    }

    void loop() {
    loop_Address();
    loop_Switchs();
    }

    void loop_Switchs() {
    if (digitalRead(SW_START) == LOW) // Switch START pressed -> continue loop IR code
    {
    state_IR = true; // state RUN
    irsend1.sendRC5(ADR_CMD | dip_prg | CMD_START, NUM_BIT);
    digitalWrite(LED_Y, HIGH);
    delay(INTERVAL_IR);
    irsend1.sendRC5(CMD_BIS | ADR_CMD | dip_prg | CMD_START, NUM_BIT);
    digitalWrite(LED_Y, LOW);
    delay(REPEAT_IR);
    }
    else if (digitalRead(SW_STOP) == LOW) // Switch STOP pressed -> continue loop IR code
    {
    state_IR = false; // state PowerON/STOP
    irsend1.sendRC5(ADR_CMD | dip_prg | CMD_STOP, NUM_BIT);
    digitalWrite(LED_Y, HIGH);
    delay(INTERVAL_IR);
    irsend1.sendRC5(CMD_BIS | ADR_CMD | dip_prg | CMD_STOP, NUM_BIT);
    digitalWrite(LED_Y, LOW);
    delay(REPEAT_IR);
    }
    else if (digitalRead(SW_PRG) == LOW) // Switch PROGRAM pressed -> only send one IR code
    {
    if (state_IR == false) // PROGRAM only if state is PowerON/STOP
    {
    irsend2.sendRC5(ADR_PRG | dip_prg | CMD_STOP, NUM_BIT);
    digitalWrite(LED_Y, HIGH);
    delay(PRG_BLINK);
    digitalWrite(LED_Y, LOW);
    while(digitalRead(SW_PRG) == LOW){}
    delay(PRG_BLINK);
    }
    }
    }

    void loop_Address() {
    dip_prg = 0b000000001100; // MASK DIP: ADDR0=0 ADDR=1 ADDR2=1

    if (digitalRead(ADDR3) == LOW)
    {
    dip_prg = dip_prg | 0b000000010000;
    }
    if (digitalRead(ADDR4) == LOW)
    {
    dip_prg = dip_prg | 0b000000100000;
    }
    }

    1. Sorry, there was a problem with cut/paste !!!!!

      #include “IRremote.h” // IMPORTANT: insert Library “IRremote-multiSend”

      1. Good job! Have you got any schematics for this?

        And also, have you made Arduino source code for the receiving module as well?

        1. Hi,
          I don’t have schematics, but it’s very easy to connect the components on arduino UNO:
          Infrared Led START/STOP —– pin 10 (PWM)
          Infrared Led PROGRAM —- pin 9 (PWM)
          Push button START —- pin A5 (used as digital)
          Push button STOP —- pin A4 (used as digital)
          Push button PROGRAM —- pin D12
          Dip switch ADDRESS3 —- pin D11
          Dip switch ADDRESS4 —- pin D8
          Optional LED Yellow —- pin D13 (already on board)

          Receiving module source code is here (thanks to Oleg Lyan):
          http://destroyer3000.blogspot.no/2013/03/start-module-implement-yourself.html

  5. hello I have problems to record the hex to the control someone could record it

    1. Hi,
      The last time i used this instructions:

      ====================== Programming the device

      For those who want to build their own modules based on this code and microcontroller, it is important that the fuse are correct when uploading the hex-file. Incorrect settings may brick your chip.

      Using the following avrdude command is used when programming the prebuilt modules. It utilizes the AvrISP MKII programmer, so if you use any other programmer, change the programming command accordingly. Make sure to be in the correct folder, or replace “StartModule.hex” to the correct path to your hex-file.

      avrdude -pt13 -cavrispmkII -Pusb -u -Uflash:w:StartModule.hex:a -Ulfuse:w:0x79:m-Uhfuse:w:0xef:m

      These fuse bits sets the following. The ones marked (important) have the potential to brick your system if set incorrectly. Set them as below and you should be fine:

      No brownout detection
      No clock division by 8
      No Debug wire
      No Eeprom preserve through programming
      No reset disable (important)
      Self Programming enabled (important)
      SPI programming enabled (important)
      Clock source as 4.8MHz, 14CK 64ms startup time (important)
      No watchdog
      You can check http://www.engbedded.com/fusecalc for further information about fusebtis.

      When the flash has been written, the module will go into “Stopped” state, which means it will blink slowly. Cycle the power and it should be ready to use.

  6. Does someone help me to program the receiver?

  7. What program do I use if I have the mkii recorder?

  8. Can I use a universal remote to control it? And if i can which brand should i try.

Leave a Reply

Your email address will not be published.


eight + 1 =

This site uses Akismet to reduce spam. Learn how your comment data is processed.