Thursday, November 17, 2011

Control RC Tank from Nokia N82 or PC

http://hk.myblog.yahoo.com/robot-builder/article?mid=129

My idea is to make a universal controller for Radio Control Toys. From my previous post, I described how to make the receiver and transmitter from a hacked RC car. Now I am going to decode the Radio Signals for the following RC Tank and use Nokia N2 or PC to control the tank.
http://www.henglongtoys.net/eng/ShowProduct.asp?id=568



Lets watch how I control the tank from Nokia N82.



And the source codes:
http://universalrccontroller.googlecode.com/files/rc_controller_v0_1.zip

If you want to know the details on the controlling, please see the explanation blew.

By measuring the width of the pulses , I got the following results (for the details, please see the figure from oscilloscope):

Start High pulse width: 1000us (microseconds)
Start Low pulse width: 600us (microseconds)
Long pulse width: 260us (microseconds)
Short pulse width: 140us (microseconds)

And the Logical Bit 0 and Bit 1 can be made from the following combination:

Bit 1 = short high pulse (140us) + long low pulse (260us)
Bit 0 = short high pulse (140us) + short low pulse (140us)

And Start High pulse and Start Low pulse have to be sent at the start of each command.




Connecting the required components (Transmitter, Bluetooth serial module, Arduino and Nokia N82), uploading programe for Arduino and N82, I can now control the RC Tank from my N82.

Each command have three bytes, but the size of the actual command is less than three bytes. It has 17 bits only. e.g. (00000000111101000). I use a  variable called MASK_BITS to mask the active bits. In this way, I can use the Arduino to stimulate the signals as the factory transmitter do.


const int COMMAND_LENGTH = 3;   
const byte MASK_BITS[]       = {B11111111, B11111111, B10000000}; // mask control the active bits
// the  commands
const byte STOP[]            = {B00000000, B11110100, B00000000}; // 00000000111101000
const byte TURBO[]           = {B10110000, B01010100, B00000000}; // 10110000010101000
const byte FORWARD[]         = {B10110000, B01010100, B00000000}; // 10110000010101000
const byte BACKWARD[]        = {B10110000, B01010100, B00000000}; // 10110000010101000
const byte LEFT[]            = {B00010000, B01100100, B00000000}; // 00010000011001000
const byte RIGHT[]           = {B00010000, B10010100, B00000000}; // 00010000100101000
const byte RIGHT_FORWARD[]   = {B00010000, B00010100, B00000000}; // 00010000000101000
const byte RIGHT_BACKWARD[]  = {B00010000, B00100100, B00000000}; // 00010000001001000
const byte LEFT_FORWARD[]    = {B00010000, B01000100, B00000000}; // 00010000010001000
const byte LEFT_BACKWARD[]   = {B00010000, B10000100, B00000000}; // 00010000100001000
const byte CANNONRIGHT[]     = {B00011000, B00000100, B00000000}; // 00011000000001000
const byte CANNONLEFT[]      = {B00010100, B00000100, B00000000}; // 00010100000001000
const byte CANNONUP[]        = {B00010001, B00000100, B00000000}; // 00010001000001000
const byte CANNONFIRE[]      = {B00010010, B00000100, B00000000}; // 00010010000001000

For the PyS60, it senses the orientation (X,Yand Z axis) of the phone and use the following simple protocols to transfer commands.


The simple protocols sent from PyS60 
        msg = bytecmd(65) # "A" the sync byte
        msg +=bytecmd(mode) # mode [ 0: moving directing, 1: moving turret ]
        msg +=bytecmd(x_val) # x-axis [ -127 to  127 ]
        msg +=bytecmd(z_val) # z-axis  [
-127 to 127 ]

// decode the protocols in the Arduino
loop until the byte matches the sync byte

int findPacketHead() {
    while(1) {
        while(Serial.available() == 0) select_command() ;
        if(Serial.read()=='A') { // "A" is the sync byte
            break;
        }
    }
}

if the value is grater than 127, it means it is a negative number

    cmd[0] = receiveByte(); // mode
    cmd[1] = receiveByte(); // x-axis
    if (cmd[1] > 127) cmd[1] = cmd[1] -256;   // if is it larger than 127, it is negative  number
    cmd[2] = receiveByte(); // z-axis  
    if (cmd[2] > 127) cmd[2] = cmd[2] -256;    

According to the following table, the select_command() will select the command. ? means don't care the number.
Mode
cmd[0]
Z-axis
cmd[2]
X-axis
cmd[1]
Command
0
?
>30
Backward
0
?
<-30
Forward
0
30
?
Right
0
<-30
?
Left
0
>30
>30
Forward_right
0
<-30
>30
Forward_left
0
<-30
<-30
Backward_right
0
>30
<-30
Backward_left
1
>30
?
Turret_right
1
<-30
?
Turret_left
1
?
>30
Cannon_up
1
?
<-30
Fire
?
<30
<-30
Stop


If you don't have the bluetooth serial module and Nokia N82, you can directly control the tank by just a PC.

The easy way is to read the command (byte) sent from keyboard and directly map the key to it's related command. Please see the following select_command() for details.

int select_command(){
     delay_time=25;
    if(cmd[0] == '8') { // key 8
        send_command(FORWARD);       
    }else if(cmd[0] == '2') { // key 2
        send_command(BACKWARD);               
    }else if(cmd[0] == '4') { // key 4
        send_command(LEFT);       
    }else if(cmd[0] == '6') { // key 6
        send_command(RIGHT);      
    }else if(cmd[0] == '7') { // key 7
        send_command(LEFT_FORWARD);
    }else if(cmd[0] == '9') { // key 9
        send_command(RIGHT_FORWARD);
    }else if(cmd[0] == '1') { // key 1
        send_command(LEFT_BACKWARD);
    }else if(cmd[0] == '3') { // key 3
        send_command(RIGHT_BACKWARD);
    }else if(cmd[0] == '5') { // key 5
        send_command(STOP);
    }else if(cmd[0] == 'q') { // key q
        send_command(CANNONLEFT);
    }else if(cmd[0] == 'w') { // key w
        send_command(CANNONRIGHT);
    }else if(cmd[0] == 'a') { // key a
        send_command(CANNONUP);
    }else if(cmd[0] == 's') { // key s
        send_command(CANNONFIRE);
    }   
}

1 comment:

  1. Find the best rc tank at Nitrotek. From Heng Long & Taigen 1/16 scale bb firing radio controlled tanks, to 1/32 entry level RC tanks, Nitrotek has the biggest selection at the best prices. All our RC tanks come with with free mainland UK delivery. We have an RC tank to suit every budget and skill level.

    ReplyDelete