Introduction: RC Toy Arduino PC Controlled by 2 Wires (signal and Ground)

About: I'm a ordinary guy that like to know how to make things, how things works... And I'm a little sad because I have no much time to learn and make all things I want ;)

This instructables is my way to say thanks to all authors of the instructables that inspire me. Thank You!

I previously controlled RC Toys by soldering wires in the pads of the RX2 IC and sending commands (HIGH/LOW) to the H-Bridge like many of these instructables.

Using the previous method to control my RC Tank (HQ516) 6 digital ports is needed (left motor forward, left motor backward, right motor forward, right motor backward, turret left and turret right) and I lose the sound and infrared functions, I do not like it. I want all factory functionalities and the possibility to control my Tank using an Arduino compatible board!

Warning: I’m not an engineer, I’m hobbyist trying to make things, sometimes I have no idea about what I’m doing, SO I’m not responsible for any direct, indirect, incidental or consequential loss or damage to devices or yourself. If you explode the world, don't blame me ;)

*This instructable is based on deductions, so please, if you have any useful technical information, use comments to help us =)

Step 1: Required Parts

Arduino or Arduino compatible board (I’m using a pro mini and usb/serial adapter)
Solder Iron
Breadboard
Wires
Optocoupler (I used 817B) or NPN transistor
Resistors
2x 100K
1x 10K
1x 240K

Step 2: Investigation

In the beginning I thought: why not use only one wire connected to the

antenna? (I know nothing about radio frequency =/).

But!! (we always have a BUT)

Internet is magic and I found much information about RF, modulation, demodulation, waveform, carrier signal and other related information. I understood no much, but I figured out that antenna is not the way.

Looking at TX-RX datasheet I figured out that the TX (controller) generate a “code” (like infrared applications, PPM-pulse position modulation) modulate it and send to RX (toy), so we only have to read and reproduce this code!

So, let's disassemble things to see what have inside.

Step 3: Inside TX

Inside of TX I found an embedded chip on a little pcb, but I found no information about it, so I follow the traces.

I found the connections of the buttons, VCC, GND and the last trace was the signal, so I soldered one wire in this trace, another wire in the ground trace and I mounted the circuit using the optocoupler to read the signal.

I used the optocoupler because it was already in the breadboard, you can use a transistor.

The transistor or optocoupler is needed because the TX works at 2.4 volts (TX uses 2 AA batteries and I read the voltage using an multimeter on the signal trace) and Arduino need a voltage greater than 3 volts on digital pin to recognize the state as high.

Step 4: Reading TX Signal

Upload to Arduino the code provided by benripley in this post (image above), connect the Arduino to your PC and open the serial monitor.

volatile int pwm_value = 0;
volatile int prev_time = 0; void setup() { Serial.begin(115200); // when pin D2 goes high, call the rising function attachInterrupt(0, rising, RISING); } void loop() { } void rising() { attachInterrupt(0, falling, FALLING); prev_time = micros(); } void falling() { attachInterrupt(0, rising, RISING); pwm_value = micros()-prev_time; Serial.println(pwm_value); }

Pressing each button and push sticks up and down you will see a sequence of numbers that represent the length of the pulses in microseconds (time that the signal stay high).

When I pushed up the left stick, the controller send (repeatedly):

84 564 564 564 560 1356 860 560 564 560 560 564 560 564 860 560 560 560 560 564 1356 860 564 560 564 564 560 564 560 864 564 564 564 564 564 (...)

So, we can see: a long pulse of 1356 micros (is “sync” a good name?) two pulses of 860 micros (command) and 12 pulses of 564 micros

When I released:

1356 564 564 564 564 564 564 564 564 564 564 560 564 564 564 1360 564 564 564 564 564 564 564 564 564 564 560 560 564 564

Again a long pulse of 1356 micros and 14 pulses of 564 micros (no code)

In the end I got the table above.

Step 5: Inside RX

Same

as TX, RX have an embedded chip on a little pcb and I found no information about it, following the traces I found connections to 3 H-bridge (left motor, right motor and turret), IR sender, IR receiver, TRA1309B (Speaker Driver) and ABERX69.

Checking ABERX69 datasheet I got pins definition and tried to read pin VO2 (output connected to the “microcontroller”)

I'm deducting the pins and functions, I can't read chinese language and translating (on google) I found no detailed information. If you know how it works, please let us know!

Step 6: Reading RX (received Codes)

Using same circuit used to read TX and connecting Arduino pin 2 to ABERX69 pin 7 (VO2) I could read the codes sent from TX, a little different because of 5660 micros pulse and micros intervals.

208 280 340 384 748 5660 272 320 360 400 1296 776 464 480 488 496 504 508 512 832 5704 260 316 348 384 1276752 444 452 468 468 476 484 488 816 5684

But, we can see same long pulse around 1300 micros, 2 pulses around 800 and intermediary pulses.

Reading some posts I understood that long delay is related to the toy microcontroller, but I'm not sure.

Reading all commands, I made the table above.

Step 7: Send Codes to RX

Now it’s time to try to send the codes from Arduino to RX, RX69A datasheet says that the pin 6 (VI2) is input (as V02 is the output that we read), absolute maximum ratings on datasheet tell us that max voltage is GND -0.2V to VDD + 0.2V (I measured 1.57 volts using my multimeter, so if anyone can tell what datasheet is trying to say, please help ;)

I started the voltage divider using values from 1 milliohms, but seems that current was insufficient, at the end I used two 100 kilohms resistors, dropping the voltage to 2.5v (voltage under 2 volts seems not take effect).

I tried to send the code one time only and sometimes worked sometimes not (related to 5684 micos delay?), sending two times and it seems ok.

<p>#define SYNC_US 1300<br>#define SPACING_US 500
#define SIGNAL_US 800
#define PinPPM 8
#define CYCLES 2</p><p>void setup() {
  Serial.begin(57600);
  Serial.println(F("#Serial Ready"));
  pinMode(PinPPM, OUTPUT);
}</p><p>void
loop() {
  if(Serial.available() > 0){
    char inChar = Serial.read();
    if(inChar == 'p'){
      Serial.println(inChar);
      //Power
      pulseOut(PinPPM,SYNC_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SIGNAL_US);
      pulseOut(PinPPM,SIGNAL_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      //Power
      pulseOut(PinPPM,SYNC_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SIGNAL_US);
      pulseOut(PinPPM,SIGNAL_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
      pulseOut(PinPPM,SPACING_US);
    }
    else if (inChar == 'o'){
      Serial.println(inChar);
      uint16_t CodeToSend = 0b0000000110000000;
      SendCode(CodeToSend);
    }
  }
}</p><p>// set thr port high/low, used in SendCode
void pulseOut(uint8_t pin, uint16_t TimeMicro){
  digitalWrite(pin,HIGH);
  delayMicroseconds(TimeMicro);
  digitalWrite(pin, LOW);
  delayMicroseconds(TimeMicro);
}</p><p>void SendCode(uint16_t CodeToSend){
  Serial.print(F("#SendCode: S"));
  for (int index = 0; index < 13; index++) {
    uint8_t bit = (CodeToSend & (1 << index)) != 0;
    Serial.print(bit);
  }
  Serial.println();
  
  for(int x = 0; x < CYCLES; x++){
    pulseOut(PinPPM, SYNC_US);
    for (int index = 0; index < 13; index++) {
      uint8_t bit = (CodeToSend & (1 << index)) != 0;
      if(bit == 1)
        pulseOut(PinPPM, SIGNAL_US);
      else
        pulseOut(PinPPM, SPACING_US);
    }
  }
}</p>

Worked! Sending 'p' or 'o' from serial monitor I could turn the Tank on and off.

Testing "left motor forward" code, the motor worked for a little time and stopped, seems that we will need to keep sending the command while we want the tank in movement.

Now it’s time to the complete application.Using ascii in serial transmissions is the simplest way, but I want economy of bytes (looking to my future projects, if we use one char for each button we will need 8 bytes, using bits we only need one byte).

My communication structure have 10 bytes because of another (simultaneous) projects, the first byte is prefix, the second is type, bytes 3 to 8 is data (commands, sensors, etc) and bytes 9 and 10 is for CRC. Take a look in the codes.

To compatibility with ascii communication I use “#” as prefix and “\r” as postfix, for my use it is ok.

I attached two source codes, one "the controller" for visual studio 2010 c#.net and one for Arduino. Keep in your mind that the code is not complete and is not bug free. ;)

If you don’t have visual studio and you want to try this instructable, you can execute Controller\bin\Debug\Controller.exe (require.net framework 4), connect to Arduino serial port (you can use Arduino USB cable or Bluetooth device connected to TX/RX), check the checkbox "capture keyboard keys to control" and use the keys below (the controller will listen only these keys):

UP = Tank forward

DOWN = Tank backward

LEFT = Tank left

RIGHT = Tank right

Q = Turret left

W = Fire

E = Turret right

P = Power (on/off)

Controller will receive the key down (action) and key up (stop) events and set the bits in a byte and send to Arduino.

Arduino will receive that byte through serial and set bits to a 16 bits variable to send the code to the RX.

If you read carefully the codes, everything will be clear and easy (I hope) ;)

Sorry for my bad English (I tried my best. if you want to make a revision, you are welcome to send me a private message)

I hope you enjoy this article.

First Time Author Contest

Participated in the
First Time Author Contest