Thursday, July 17, 2008

USB Communication part II

The Arduino can receive string signals from the computer, but the computer has to send them. I have searched high and low for a multi-platform API to connect to a USB device and send strings to it in C++. No luck. Under windows there's CSerial, and Linux has libUSB, but instructions on how to use them are sparse, particularly on Unix/Linux.
So I turned to Python. Python is an interpreted language, useful for rapid prototyping software and scripting. It also has a brilliant USB communications library called pyserial. It also can be embedded in a C++ program. What follows is at best a hack. At worst it's a terrible kludge. Either way it works quite well. Python is installed by default on the Mac OS, so I didn't have to do anything beyond finding the right include directory. You can download it from and pyserial from sourceforge. Using Python to send messages over the USB connection is impressively simple. The test code looks like this:

import serial
import time

ser = serial.Serial('/dev/tty.usbserial',9600)
ser.write('Any message string you want.')
ser.write('Another message string')

The sleep commands ensure that the serial connection has time to start up (in the first case), and that it has time to transmit before the script ends (in the last case). In between, the connection buffers all the messages you send so the middle sleep isn't technically necessary.

Now I need to insert these commands into a C++ program. Fortunately, this is simple too. If you #include Python.h you gain access the the Python interpreter. I tried several different tutorials for using the various functions in Python.h, but the one that worked the best was the simple "PyRun_SimpleString(char* str);". With that, you can simply create your Python command in a char[] string in C++ and send it off. With that in mind I created the following wrapper class called serialBridge, which encapsulates the python commands including the setup and shutdown.

Here's the code:

And here's how to use it:

#include "iostream"

#include "Python.h"
#include "serialBridge.h"

using namespace std;

int main()
rSerial::serialBridge ser;

for(int i = 0; i <>
return 0;

Friday, July 11, 2008

Ordered a computer

I just put in a preorder for an ASUS eee PC 901 at NCIX. They had the Windows-equipped versions sitting right there on the counter, but I decided to wait for the Linux version. Why? Two reasons. The first is that for the same price, the Linux version come with a 20Gb Solid-State hard disk, as compared the 12Gb SSD in the Windows version. This offsets the cost of the Windows license. The second reason is that if I did get the Windows version, I'm stuck with an OEM copy of Windows XP Home on the computer, with no install disks. So that means that putting Xubuntu or some other flavour of Linux on the machine means wiping out that windows install and possibly never getting it back. I'll wait a week or two for the better machine with the free OS, thanks. I don't know if the stock Xandros-based Linux flavour will be okay or whether I should wipe it and install another distro. Time will tell.

The specs look like this:
  • ASUS Eee PC 901.
  • Intel Atom 1.6 GHz Diamondville Processor.
  • 1 Gb of DDR2-533/667 RAM (planning an upgrade to 2Gb).
  • 20 Gb Solid-State Hard Disk (4Gb on motherboard plus 16Gb in removable SSD).
  • 8.9in 1024x600 LCD Display.
  • 802.11n (draft) wireless.
  • 1.3 Megapixel webcam.
  • Bluetooth onboard.
  • Xandros Linux preinstalled (Replace with Xubuntu?).
  • 6 Cell battery - they claim 4-8 hours of life. I'm skeptical, but hopeful.
  • 3 USB ports, an SD card reader, VGA-out and ethernet.
  • Final price: $617.59 CAN.
The only thing missing is firewire, and I'm sure I can find a decent USB camera, so I'm not worried.

Thursday, July 10, 2008

Vision Software

In order to guide the robot I need to process video data from a camera. Initially, the goal is to get the robot to travel down a course defined by two rows of orange cones. This is the basis of the Waterloo Robot Racing competition. A simple algorithm to guide the robot tries to detect two rows of cones as lines forming two sides of a triangle. By heading towards the center of the triangle we will (roughly) head down the course. Obviously, we'll have to handle cases where the robot can't see two distinct lines. This can happen when the robot isn't pointing down the course, or when the rows of cones don't resolve themselves into easily distinguished rows.

For now, I'm using OpenCV to capture frames from a camera. This is surprisingly easy to do with many USB or firewire cameras when you have drivers. OpenCV also provides the functions for the colour space conversion to HSV and the Hough transform line detection. The algorithm looks like this:

  1. Capture a frame from the camera
  2. Convert the image to the HSV (hue, saturation, value) colour space. The hue channel tells us the colour of the pixel as an angle in a colour wheel. The saturation channel tells us how strong the colour is.
  3. Create a binary image where a pixel is zero unless the corresponding image pixel has a hue angle near to orange and a high saturation.
  4. Use a Hough Transform to detect lines in the binary image. The Hough Transform works by comparing many candidate lines to the image, and letting pixels "vote" for any line they lie upon. It returns the lines that have large numbers of votes.
  5. Group the lines into those with positive vs. negative slope. Compute an average for each group of lines.
  6. The triangle is formed by these two average lines. The bottom of the image provides the third line. Compare the center of the triangle to the vertical centerline of the image to get a value for the robot's steering.