Drive a Lamborghini With Your Keyboard

A few months ago I was talking to a friend of mine about robotics and hardware. He mentioned something called an Arduino Uno board and I was intrigued. After doing some DIY search online I found out this little prototype platform has a whole family of boards. I also found out that the web is filed with neat things you can do with it. An Arduino cost about $15 on Amazon. I had to have one. So I typed in my password to Amazon and about a week later I promptly got my new toy. I immediately took it out of the little box, examined it and went through the Arduino tutorials. Since then my Arduino has been collecting dust. I bought it thinking if I had it I will find a use for it. Following “if you build it, they will come”. Nothing came to mind. That is until I was walking down an aisle at the store yesterday and I saw a neat orange looking remote controlled Lamborghini. It was on sale for $15. I bought it on the spot.

wpid-orangelookingremotecontrolledlamborgini-2013-01-3-07-38.jpg

When I got home and opened up this new toy I was deeply disappointed. The remote for this car has to be an example of the worst human interface known to man. I know this remote comes with a lot of RC cars, but from some reason I just could not take it. I could barley control the thing. And then The idea came to me. How cool would it be if I were to control the car via my Bluetooth keyboard? After all, I have lot of experience driving with my keyboard from GTA. Hours later it turned out to be very cool indeed...

wpid-Arduino_CarControl_00-2013-01-3-07-38.jpg

So what went in to this cool little thing? A night worth of work, and about 270 lines of code. You can download the code for Arduino CarControl, but unless you follow what I did on the hardware part you might find it useless. Here is the “big picture” overview of what I did. I took apart the remote control and wired the connection to the Arduino pins. Then I use python’s serial module (download pyserial) to communicate with the Arduino. I used PyGame (download pygame) to get key pressed information. And finally, I had to write the code that is on the Arduino to accept serial input and output the correct command to the remote control. It seems like a lot, but it is really fairly simple.

Here is a video of the whole thing in action:

Step 0: Get comfortable with the Arduino.

The Arduino is programmed using an its own language. It is a set of c/c++ and was really easy to pickup. You will need to download from Arduino’s site an IDE that was designed to communicate with the board. The software contains a few examples. At the bare minimum, you should try out the blink example.


// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

If you were to wire up an LED to pin 13 of the Arduino and run the code, the LED diode will blink at fixed intervals. The main part I found useful was to understand the structure of the program.

* Before the first functions there are setup variables.
* After the variables there are functions.

There are two (2 things) functions that make the whole thing run. First there is a setup function. This will be executed as son as the Arduino powers up. The second is the main loop. Opposite from programming, electronic run on a while(1) loop. Any code you have in the loop function will run again, and agin, and again ...

Step 1: Taking apart the remote

For some people the thought of taking apart something brand new might be hard, not for me. I have been taking things apart since I was 3. This is what I found in the RC remote ‘under the hood’:

wpid-Arduino_CarControl_01-2013-01-3-07-38.jpg

Here is a closer look:

wpid-Arduino_CarControl_02-2013-01-3-07-38.jpg

Neat. The small board is wired to 4 things. Positive and negative are near the middle. On the right there is the antenna connection. Near the top-middle there is a red LED diode to indicate power-on. Note the positive wire run through a power switch, which is your remote control on-off switch. Here are some more photos of it disassembled from the remote housing:

wpid-Arduino_CarControl_04-2013-01-3-07-38.jpg

One of the most imperative things I have learned from taking things apart is always stop and check your work. There is nothing more then going a few steps forward and then when a problem arises to trace back. There is no ‘control-z’ in hardware, so be careful. At this point I wired up to remote board to check that it still turns on. It did.

wpid-Arduino_CarControl_06-2013-01-3-07-38.jpg

Being who I am, I also looked around for some housing so It will look nice. I found a pice of foam laying around that fit the task. I mounted the board and this is what I got.

wpid-Arduino_CarControl_09-2013-01-3-07-38.jpg

wpid-Arduino_CarControl_10-2013-01-3-07-38.jpg

Step 2: Reverse engineer the remote board.

This was the part I thought will be the most difficult. It turned out not as bad as I thought. I am not an electrical engineer by any means, but I will try to explain it. The basic idea is that an electronic circuit is either closed or open. When the circuit is open, electricity cannot power what ever is connected to the circuit. When the circuit is closed (and somewhere along the circuit there is a power source), electricity can move around the circuit and power everything along the way. What you will need to do is figure out how the board work. I managed to send a single to the car by emulating the original remote control switch using a small wire. In connecting the to spots in the picture I closed the circuit and indeed the car was moving.

wpid-Arduino_CarControl_05-2013-01-3-07-38.jpg

Step 3: Send out a test single

In order for the Arduino to communicate with the board, you will need to find a better way to move the car. If you can try to follow the logic on the board to figure out which pins are associated with which command. There are a total of 4 command you can give to the car:

  • Forward
  • Reverse
  • Left
  • Right

The forward - reverse command and left-right can only be executed one option at a time. However you could say turn left and move forward at the same time. This came back to bite me later on in the first version. Since I am not an electrical engineer, I had to take the long route to figure things out. I checked each one of the top connectors until I found all four (4) movement controls.

wpid-Arduino_CarControl_13-2013-01-3-07-38.jpg

Step 4: The Python code

The python part is really simple. Get keyboard input using PyGame Library, and output a command using the serial library. The complete carControl.py file is available. Let us look at the main() function:


def main():

    clear_screen()

    print '\nStarting Car Control v.0.3\n';

    ser = serial.Serial('/dev/tty.usbmodem411', 115200, timeout=1);

    pygame.init();
    run = [True,0];
    previous = -1

    while run[0]:
        run = getOrder(run);

        #debug
        #print 'current orders: ' + str(run[1]);

        if (run[1] != previous):
            previous = run[1];
            ser.write(chr(run[1] + 65));
            print run[1];

    ser.close();

We start by opening a serial port to the Arduino. We do that using serial.Serial() passing in the path, bandwidth (and timeout is optional). The path to your usb device is found by running ‘ls /dev/tty.usb*’ in the terminal or you may find it on the Arduino IDE in the bottom right corner.

wpid-pathtoArduino-2013-01-3-07-38.png

We continue to initiate PyGame and some variables and run a main loop. Notice the run variable contains 2 elements. The first indicates whether or not we should keep the loop running, the second is the command. For each iteration of the loop we write the appropriate command to the serial port using the write function. When we exist the loop we close the serial port and end the program.

The second function we need is getOrder. This is where we handle all the keyboard input cases. You can check out the complete code. Here is a snippet of what it looks like:


def getOrder(run):
        for event in pygame.event.get():
            if (event.type == KEYDOWN):
                keyinput = pygame.key.get_pressed();

                #complex orders
                if keyinput[pygame.K_UP] and keyinput[pygame.K_RIGHT]:
                    run[1] = 21;
                elif keyinput[pygame.K_UP] and keyinput[pygame.K_LEFT]:
                    run[1] = 22;
                elif keyinput[pygame.K_DOWN] and keyinput[pygame.K_RIGHT]:
                    run[1] = 23;
                elif keyinput[pygame.K_DOWN] and keyinput[pygame.K_LEFT]:
                    run[1] = 24;

#a few lines later...

return run

For each keyboard input we modify our run variable and at the end return it.

Step 5: The Arduino code

The Arduino part of the code is very similar to the python code. Let us take a look at it part by part. Here is a link to the complete car.ino file.


int reversePin = 9;
int forwardPin = 8;
int leftPin = 7;
int rightPin = 6;

int order = 55;
int time = 75;

//control flag
int flag = 0;

We have our output pins, similar to the blinking LED example. We have 4 output pins, one for each car movement. An initial order that is not a real order. A time variable for delay purposes and a flag to indicate the start of the python program. Now let us look at the setup function:


void setup() {
  // initialize the digital pins as an output.
  pinMode(rightPin, OUTPUT);
  pinMode(leftPin, OUTPUT);
  pinMode(forwardPin, OUTPUT);
  pinMode(reversePin, OUTPUT);

  Serial.begin(115200);
  Serial.print("\n\nStart...\n");
}

We initialize the pins to be in output mode and initialize a serial connection. Now let us look at the main loop:


void loop() {

  //Turn everything off...
  off();

  //get input
  if (Serial.available() > 0){
    order = Serial.read() - 65;
    Serial.print("I received: ");
    Serial.println(order);
    flag = 1;
  }

  if(flag){
    //complete orders
    orderControl(order,time);
  }

At the stat of every loop we turn everything off. If we have serial command we try to read the command. At the end as long as the flag has been raised, meaning we started the python program, we execute what ever command we got using orderControl(). This function takes a order number and a time. Then, using a switch statement, it invokes smaller functions that can execute simple, complex and demo commands.

Here is an example of a simple command function forward:


void forward(int time){
  Serial.println("This is forward...");
  digitalWrite(forwardPin, LOW);
  delay(time);
  digitalWrite(forwardPin,HIGH);
}

A more complex command leftTurnReverse:


void leftTurnReverse(int time){
  digitalWrite(reversePin, LOW);
  digitalWrite(leftPin, LOW);
  delay(time);
  off();
}

And a demo function:


void demoOne(){

  int demoTime = 500;

  forward(demoTime);
  reverse(demoTime);
  left(demoTime);
  right(demoTime);
}

Notice that the functions uses reverse magnitude, LOW setting to activate a command. If you were to connect an LED to the command wire, you would need a not gate to invert the signal.

Step6: Wire everything togther

The final step is to put all the wires together, load the Arduino and run the python code. If everything goes well, it should work flawlessly.

wpid-Arduino_CarControl_11-2013-01-3-07-38.jpg

After a night of paying around with the Arduino and the car I have to say this is one of the coolest things I put together. I think the same principles could apply for nearly any out of the box RC vehicle. Maybe I will get an air vehicle (Quad Copter) next time and test my flying skills using a keyboard. Or maybe I will try to get a joystick. In the mean time I have a cool toy setting in the corner that I can use to scare off my dogs when they start bothering me too much.

wpid-Arduino_CarControl_12-2013-01-3-07-38.jpg

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
  • Craig Curtin

    Captain,
    nice blog posting about controlling your new 'car'. This may be the only way I'd ever drive a Lamborghini.

    btw, on the video who is playing that cover of the rover ... made me go dig out my copy of graffitti!

    Craig

    • CptDeadBones

      Craig,

      Thank you for your comment. I think this is just about as close I jot to a Lamborghini aside from having one fly by me on the highway. I am not sure who the specific music is by. It is a mixup of a few guitarsits. I think Led Zeppelin, Pink Floyd, Iron Maiden and Metallica are in it. Sorry I cannot help you more there.

      • Craig Curtin

        Captain,
        The audio to go with your video is from Dream Theater's 1995 release, A Change in Seasons, The Rover - Achilles Last Stand - The Song Remains The Same medley.
        I enjoy your blog, keep up the good work!

        Cheers,
        Craig

        • CptDeadBones

          Thank you Craig.

          Captain DeadBones
          thelivingpearl.com

  • Christian Padilla

    Is there any other way to find what is the path of the usbe device? I am using Arduino ERW, (because the original Arduino IDE Does not work)

    • CptDeadBones

      There is. It depends on what system you are running. On Mac systems you will find it by running the command ' ls /dev/tty.usb* '. This will list all usb devices currently plugged into your machine.

  • dancy

    I do everything what is on this web, but get this messages http://prntscr.com/5bj5h0, , any help please

    • CptDeadBones

      You will need the correct port open in order for this to work. Try to change the port to COM4. You can also look http://stackoverflow.com/questions/6105182/error-while-opening-port-in-python for more information or send me a private message via the contact link. Let me know if you need anymore help.

      • dancy94

        problem, listen, what I am doing wrong, 1. open arduino, upload the program 2. open python and click run, after this information on this link, there was no problem, but, when click run this is go outhttp://prntscr.com/5bpr06 and that is all, please help, what I am doing wrong, I am on win7 32 bit

        • dancy94
        • CptDeadBones

          There isn't much of an output. Once you get the program running, PyGame should lunch and then keyboard arrows would drive the car. Take a closer look at the video on top.

          • dancy94

            but they didn't work, just stand "0"

      • dancy94

        please help, I have instaled a linux 14.04 and it is not working, what to do

  • dancy94

    pleeassseee helllp