This project extends a simple remote-controlled car, allowing it to be controlled by an iPad or by hand gestures. This project builds on the Arduino project, the Kinect and certain HTML5 features (WebSockets, DeviceMotionEvent, Canvas). The final product is this:
Overview
There are two different versions of this project – one for the HTML5 web app, and the other for the Kinect. In the HTML5-based version, the web application uses DeviceMotionEvent to get accelerometer readings and determine what the car has to do. This action is encoded in the format expected by the Arduino sketch, and is then sent over a WebSocket to a simple server written in Python. The Python script simply forwards the received data to the Arduino via the serial port. The Arduino toggles its output to close and open switches on the remote controller (using optical isolators). The car moves correspondingly.
The Kinect-based version functions in a nearly identical manner – the only difference is that the Kinect data is received and processed in the same C# application that dispatches instructions over the serial port. You can download the full source code here.
Now, to take a closer look at each section of this project, from the bottom-up:
The Arduino
The Arduino receives commands from its Serial interface and toggles its output to control the car’s remote controller. For a controller that supports only one speed, the circuit looks like this:
Each output pin controls current passing through an opto-isolator, which isolates the circuit of the Arduino from that of the car’s controller. This allows the Arduino to control the car, despite both circuits having different electrical potentials. The switches at the top of the above diagrams are placeholders for the actual control mechanism of the car. A current-limiting resistor is chosen so as to provide a current within the operating parameters of the opto-isolator. The breadboarded circuit looks like this:
The sketch that the Arduino runs is very simple:
int pinRight = 11;
int pinLeft = 10;
int pinForward = 9;
int pinReverse = 8;
void setup() {
Serial.begin(9600);
pinMode(pinRight, OUTPUT);
pinMode(pinLeft, OUTPUT);
pinMode(pinForward, OUTPUT);
pinMode(pinReverse, OUTPUT);
}
void loop() {
if(Serial.available() > 0){
int tmpByte = Serial.read();
switch(tmpByte){
case 'w': // Move car FORWARDS
digitalWrite(pinReverse, LOW);
digitalWrite(pinForward, HIGH);
break;
case 's': // Move car in REVERSE
digitalWrite(pinForward, LOW);
digitalWrite(pinReverse, HIGH);
break;
case 'a': // Turn steering wheels LEFT
digitalWrite(pinRight, LOW);
digitalWrite(pinLeft, HIGH);
break;
case 'd': // Turn steering wheels RIGHT
digitalWrite(pinLeft, LOW);
digitalWrite(pinRight, HIGH);
break;
case '_': // STOP ALL motion
digitalWrite(pinReverse, LOW);
digitalWrite(pinForward, LOW);
// The missing break; here is entirely intentional.
case 'x': // Move steering wheels STRAIGHT
digitalWrite(pinRight, LOW);
digitalWrite(pinLeft, LOW);
break;
default:
break;
}
}
}
Notice that the digitalWrite(pin, LOW); always precedes the digitalWrite(pin, HIGH); command? This is to prevent conflicting commands from being sent to the car(e.g. Forwards and Backwards simultaneously).
And now, on to the Web App-based controller:
Web Application Controller
This controller comes in two parts. One is the actual client, which is served as a single html file (with optional additions – discussed later), and one is the server, which is a Python script that simply copies all data sent over a WebSocket to the Arduino over a serial port. This is how the client interface looks like:
The server is based on this Python script (if you want to use a test server, grab this code – the response headers adhere to the Same-Origin Policy). pyserial 2.5 is used to send output to the Arduino.
The web-based client, on the other hand, is much more complex and interesting. A single file (index.html) draws the GUI (using Canvas), reads the tilt angle of the device (using DeviceMotionEvent), calculates the action that the car has to perform and sends the action to the Python script over a WebSocket connection. HTML5 is certainly useful, isn’t it?
The JavaScript has been extensively commented, and is included (along with the optional files) in the download above.
The purpose of the optional files (cache_manifest.php and date.php) is explained here. They are not essential to the functioning of the code.
Kinect Controller
The Kinect controller is written using Code Laboratories’ CL NUI SDK instead of the more commonly used (and official) OpenNI or OpenKinect/libfreenect. The primary motivation in choosing CL NUI over the other SDKs is that CL NUI makes writing code in C# very easy and serial communication is a trivially easy in C#. The tradeoff of writing in managed C# is that (1) Threading is inevitable, which adds to the complexity of the code and (2) The image processing code runs painfully slowly. The software looks like this:
The bar on the left is not relevant to this project – it is just a quick way to move the Kinect up and down (using the built-in motor) and to read and graph the angle over time. The algorithm used to detect the position of the hand has been deliberately kept simple – working with System.Drawing.Bitmap objects is very slow. Here is the algorithm:
// System.Drawing.Bitmap bmpVideoData contains the current frame.
// double xbar, ybar contain the running average of the points that lie
// in the desired depth range. Tweak the incremented values until satisfied
// with the accuracy and speed trade-off. The choice of 10 is arbitrary.
for(int i=0; i<bmpVideoData.Width; i+=10)
for(int j=0; j<bmpVideoData.Height; j+=10){
c = bmpVideoData.GetPixel(i, j);
// Check to see if color of pixel in depth map corresponds to the desired
// depth range. This was manually calculated beforehand, but can be
// automated if the range needs to be varied.
if (c.R == 0 && c.B == 255 && c.G < 192) {
// Live, numerically stable, mean calculation:
++count;
xbar += (i - xbar) / count; // Update the mean x value
ybar += (j - ybar) / count; // Update the mean y value
}
}
// xbar and ybar will be used to calculate the position of the hand onscreen,
// and the action to be performed by the robot.
As algorithms go, this is among the simplest. It gives surprisingly robust tracking, though. Do note that you need to install Code Laboratories’ CL NUI SDK before you can run the code included in the download above. Once you have done that, copy CLNUIDevice.cs, CLNUIDevice.dll and NUIImage.cs into the project folder, replacing the existing files. (As per their SDK license requirements, I cannot distribute these files directly).
Future Expansion
- Use the Ethernet shield and write a sketch that allows the Arduino to act as a WebSocket server. This will remove the need for having a computer as an intermediary (to forward WebSocket data to the Arduino over the serial port).
- Modify the web app code to automatically use the internal gyroscope when available (by using DeviceOrientationEvent instead of DeviceMotionEvent). When I eventually get a device with a gyroscope, I’ll look into it.
- Implement the same thing in a toy helicopter. Same concept, new dimension! Use the Kinect to gather positional data, and the iPad to steer it around.
- Modify the vision algorithm to detect each hand separately (using a conditional floodfill), and allow each hand to control a different car. Alternatively, use it to steer a helicopter in three dimensions.





Pingback: R/C car controlled by an iPad or Kinect - Hack a Day
wow, that’s great. I suppose you could make a simplistic 3D-style app using the tilt sensor/accelerometer and the same setup, but reversing the x-y coordinates?
If you do make a DS controller, let me know
.
Pingback: R/C car controlled by an iPad or Kinect « Black Hat Security
Very nice! How about a pov camera on the vehicle?
Why not?
The main challenge (getting the video onto the remote device in realtime) might take some time to accomplish, but its a perfectly plausible idea.
awesome,I want to do a similar thing, but instead kinect wants to use the wiimote.I use Ubuntu and I have no idea how to implement communication between wiimote and Arduino(wiimote->netbook->arduino->rc_car or robot).
Can someone HELP ME???< please:D send info on how to do it or helpful links
Pretty cool stuff!
I just completed the same thing! But, I use TouchOSC to send raw accelerometer data to the Arduino via the PC(Processing) and hence do the controlling part.
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) -- Engadget
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | Weblinxx.ca
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | Graphic Tablets Store
Pingback: RicciAngel News » Man steers R/C car with his hands, not to mention an HTML5-based web app (video)
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) - Finding Out About
Pingback: Unlimited MobileUnlimited Mobile
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) |
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | et
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | Niffybranco.com
Pingback: Is Verizon Getting the Iphone » Blog Archive » Man steers R/C car with his hands, not to mention an HTML5-based web app (video)
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | High Tech News
Cool! It can be used like a car racing game on an iPad, but this one can use a real toy car.
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | Techieboy
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) » Gadgets, gizmos, gaming, mobiles, tech news, updates, reviews and more
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | Technology and gadget wars
Pingback: HTML5 Web App Created To Steer R/C Race Car From Various Devices
Pingback: Man controls RC car with his hand | 2dayBlog
Pingback: VIDEO: iPad and Kinect controlled RC car
Hi Gaurav, great one dude. well done.
Pingback: DataBytez.com | Latest News on Technology, Science, Entertainment » Man steers R/C car with his hands, not to mention an HTML5-based web app (Video)
Pingback: Điều khiển ôtô từ xa sử dụng iPad hoặc Kinect – TechNotes.vn- Tin tức & Đánh Giá | Khoa Học & Công Nghệ
Sorry! There is one thing I don’t understand: how do you get the information from the ipad to the Arduino? Do you use the Ethernet-shield running with an HTTP-Server – and do you use the Wifi to connect via an access point?
Web app -> PC -> Arduino
Web app-> PC: Uses web sockets
PC -> Arduino: Uses serial
I would want to try using an Ethernet shield, but I can’t seem to find one anywhere.
Pingback: Man steers R/C car with his hands, not to mention an HTML5-based web app (video) | koreyweldon
Pingback: Macchina radiocomandata controllata con iPad o Kinect | Lega Nerd
Pingback: » Man steers R/C car with his hands, not to mention an HTML5-based web app (video) Consolidate Your Loan
cool. not really html 5, but cool.
Er… The web application makes use of HTML5 extensively. Read the technical details.
Pingback: 程序员玩家的胜利 iPad+Kinect控制遥控汽车 | PrimeSense中文网
Pingback: RC Car Hack for iPad » TechMASH
Pingback: Arduino and Kinect Controlled Car | Paul Hartigan's Blog
Pingback: Man controls RC car with his hand | Feed blog!
Pingback: Kinect and iPad R/C Cars – Really Cool! | Tech Pinger
Thank you very much. This looks like good fun and i’d like to play with it. I installed python and pyserial on vista. I believe the server is starting because, for example, it complains if i disconnect com1.
on my iphone i’m trying to access 192.168.1.109:6799/index.html but i get a message saying the server cannot be found.
I believe the windows firewall is turned off – any thoughts or debugging suggestions?
oops, found it – I’ll move along now.
maybe i’m wrong to expect python to serve the index file? I see the connection coming in now from the iphone (which is neat) but the web server must be expecting some kind of structured input – maybe i’m supposed to copy the file to the phone manually?
The current error message is
C:\Users\Bill\Documents\RC_Car\RC_Car\Web App>ws_server.py
We will now listen for a connection on port 6799
Connection from: (’192.168.1.111′, 55741)
Exception in thread Thread-1:
Traceback (most recent call last):
File “C:\Python26\lib\threading.py”, line 532, in __bootstrap_inner
self.run()
File “C:\Python26\lib\threading.py”, line 484, in run
self.__target(*self.__args, **self.__kwargs)
File “C:\Users\Bill\Documents\RC_Car\RC_Car\Web App\ws_server.py”, li
nums1 = key1.count(” “)
UnboundLocalError: local variable ‘key1′ referenced before assignment
Yep. Python doesn’t serve the index file. You need to host that separately, using either a web host (many web hosts will give you your money’s worth for a free account) or use a separate server program. If you run OSX, apache comes preinstalled. If you use windows, try XAMPP (http://www.apachefriends.org/). I use that as a local development server.
The Python code only acts as a WebSocket (http://en.wikipedia.org/wiki/WebSockets) server. The error happens because your regular HTTP request (for the page) does not include the information needed to create the response key, leaving key1 and key2 uninitialized.
Do tell me how it goes!
Regards,
Gaurav
Thanks. I got the simplest server I could find to load the file from windows (HFS, it’s great!). I’ve made progress to where I now see the app on the phone. Back to arduino now.
btw I had to comment out the line below – i assume it won’t hurt anything:
debug = “Please lock your screen rotation!\nCurrent Version: ” + php_date + “\n”;
Yep, it won’t hurt anything.
The use of the php_date variable is explained here (http://www.gauravmanek.com/blog/?p=31).
For completeness’ sake, you could also remove the script tag that includes date.php, and add the line debug = “” (to give the variable a starting value), but the code will work even without that.
Pingback: Control an RC Car using iPad or iPad 2! | 9to5iPad | the iPad Blog
OMG, thats really, really cool.
I’m trying it myself. I loaded the HTML5 onto a web server, but when i acces it from ipad, all i get is a blank screen with the title “Car Driver”. Abyss web server on PC, ipad ios 4.3.3. Any ideas?
Thanks
I haven’t tried it with Mobile Safari on iOS 4.3.3. Perhaps you could take a look at it with the Developer Toolbar enabled?
Pingback: The Next Steps In Robotics And Computer Vision: Behavior Analysis, Situational Awareness | TechCrunch
Hi Gauravmm. I am Randson. I currently doing a project exactly the same as your project. I am actually using the kinect to control. Can i seek your advise that
1: How do you know whether the car is travelling in 1 speed or?
2: How to you connect the opto isolator to the car remote. I can’t really see
3: How to you connect Arduino to the opto isolator
Kindly Advise. Thanks
1) The car I’m using is a one-speed-only car. Most cheap RC Cars are.
2) and 3) Google for tutorials. There are many good ones (like http://coldsolder.wordpress.com/2010/04/20/sound-activated-flash-trigger-for-high-speed-photography/ and http://www.glacialwanderer.com/hobbyrobotics/?p=11).
Hope you found this helpful.
Bro Thanks for that wonderful link. I have a major problem now is that i am programming my codes in C# where finally my kinect is able to capture and recognized my action. My action is being save into a text file. Next thing is that how can i program the codes that the car actually understand what my action are? I don’t how to transmit.