Saturday, April 30, 2011

SparkFun AVC 2011

The 2011 SparkFun Autonomous Vehicle Competition was last weekend in Boulder, CO. I entered as "Team Zyzzyx" in the ground category with a modified 1:10 scale RC car. Here are the details of my entry. Most of this is duplicated from a post over at DIY Drones.


First off, a big thank you to the hardware and software developers of the APM autopilot. Without it I wouldn't have been able to pull off a working autonomous system in such a short time. Thanks as well to Jack Dunkle for helping me out with a late encoder addition.

A couple months ago I saw the SparkFun AVC announcements and decided to enter. I bought parts early, but didn't get it all working right until the end. Here are all the details on my entry, for anyone interested.

  • Traxxas Rustler VXL
    • Reasonably fast RC car straight out of the box. I probably could have saved some bucks and gone with the non-VXL (brushed motor) version and not known the difference. Came with a 2-channel RC receiver/transmitter pair.
    • I thought about switching out the included 8.4V NiMH battery, but it ended up being more than sufficient.
  • 5V switching regulator
    • The Traxxas ESC puts out 6V so an external regulator was necessary. This one died a unfortunate squealing death the week before the competition and I actually ended up replacing it with a simple LM7085T.
  • ArduPilot Mega / OilPan IMU
    • The APM was a no-brainer given that electrically it does everything I needed, and there are code libraries for almost all the sensors I was using. I'm naturally lazy and this was clearly the path of least effort.
    • I actually didn't end up using the IMU (except for magnetometer roll/pitch correction), but that's okay since I'm hoping to repurpose this hardware on a quad.
  • SkyLab SKM53 GPS
    • This was the first thing I purchased (bought a GPS, had to build a robot around it). It uses the standard MediaTek MT3329 module. In retrospect I should have gone with the module + adapter from DIY Drones.
  • HMC5843 Magnetometer
    • Not much of a choice here.
  • US Digital E4P-100-079-HT Encoder
    • A couple weeks before the competition I panicked and thought that I needed a wheel or drivetrain encoder (probably not true) and so I added this on the motor shaft the Tuesday before the competition.
  • Maxbotix LV-MaxSonar-EZ3 Rangefinder
    • My code gets data from this, then disregards it and drives into walls. Ultimately I decided that there wasn't enough time to get this up and running in a way that wouldn't be a liability. So, my obstacle avoidance ended up being careful waypoint placement and a bit of luck.
My code runs three loops, nominally at 100Hz, 10Hz, and 1Hz. Here's what each one does.
  • 100Hz
    • Check for user input (autonomous mode or emergency stop). Since I only had a 2-channel transmitter, I mapped the extreme steering limits to these inputs. Also turns off autonomous mode if GPS fix is lost.
    • Update the DCM. I pretty much blindly copied this from the APM software. The magnetometer needs roll/pitch values for calculating the heading.
    • Calculate motor velocity (counts/sec) from encoder change since the last 100Hz loop. The encoder itself is read by pin change interrupts. I found that I had trouble monitoring high speeds (~150000 counts/sec and up), but it might have been a side effect of the monitoring code, since I think the encoder-reading code is less than <10 instructions per interrupt. That's blazing though, since 100000 counts/sec is about 25MPH on my car.
    • Control the velocity with a PID controller. The encoder lets me do closed-loop control on the throttle input to the ESC. In retrospect this probably wasn't necessary.
    • Update the servo outputs, or relay the inputs from the receiver if in manual mode.
  • 10Hz
    • Update the indicator lights (A = autonomous, B = GPS fix).
    • Read the latest data from the GPS, compass, and rangefinder.
    • Calculate distance to the target waypoint.
      • <4m, slow down in preparation for steering.
      • <2m, increment the waypoint index (waypoint achieved).
    • Calculate distance to the last waypoint.
      • >4m, speed back up.
    • Calculate the absolute heading to target waypoint (GPS data only).
    • Calculate the heading error (absolute heading - compass heading).
    • Scale the steering output linearly to the heading error. This is pretty crude, and might have caused my trouble in the 3rd race.
  • 1Hz
    • Spit out human-readable debug information over serial.
And that's it! I tried to do some fancy stuff with the rangefinder, detecting obstacles approaching at close to vehicle speed (stationary obstacles straight ahead) and then making the car swerve to avoid them. It worked too poorly and so I took it out, since I figured it would probably hurt more than help.

The last little bit is dealing with GPS coordinates (latitude and longitude). I converted them immediately to Cartesian coordinates on a plane. In a small area, this works very well. I had two sets of conversion factors, one for Pasadena and one for Boulder.

Compass mounting calibration was key for getting this to work. My method was setting a waypoint, pointing the vehicle toward the waypoint, and changing an offset parameter until the heading error was close to 0.

I was able to avoid the barrels and get the arch bonus by careful waypoint placement to minimize the effect of GPS error (waypoints far apart). Also, I was lucky.

SparkFun AVC
I came to Boulder Thursday night without working throttle/steering controllers and no waypoint code written, but I managed to work it out Friday morning and afternoon, testing in my friend's apartment's parking lot. Friday evening I tried to write obstacle avoidance but scrapped it and slept instead.

Saturday morning I got to SparkFun a little early and set up my waypoints (7 of them), and ran some test runs. I made it around about half the time, doing better after I altered the steering trim to eliminate a leftward (and water-trap-ward) drift.
  • Race 1
    • At Turn 1, I got tangled up with another competitor. My robot achieved its waypoint, turned sharp, and lodged a steering wheel between the other bot's drive wheel and chassis, stopping us both. This was unfortunate. I think SparkFun has a great picture of this.
    • I tried to complete the course anyway, but the GPS data seemed to be poor and I had to hit the emergency stop to avoid going into the pond.
  • Race 2
    • Right after Race 1, I moved my GPS module to a different spot and carried my car around the course, watching the steering. Things seemed to be much better, but it's also possible that the improving weather helped just as much.
    • I also got paranoid about the pond and added some code to reduce the speed on that stretch, reducing the possibility of jumping the curb and giving me more time to activate the emergency stop.
    • The race went great, I made it through the arch and felt quite good about things when I made it to Turn 2. It seemed like my car was going slow, and I realized that I didn't add code to speed back up after the pond. D'oh, that's what I get for mucking around with things. I ended up doing most of the race at 60% desired speed.
    • Right before Turn 4 I went straight through the biggest pothole on the course (filled with water), but the electronics stayed dry and I made it across the finish line at 1 minute, 25 seconds (0 minutes, 55 seconds after the 30 second arch deduction). That put me in second place, behind Team Minuteman at 26 seconds post-deduction.
  • Race 3
    • Having recorded a good time in Race 2, I went all out, getting rid of the pond slowdown and doubling my speed parameter.
    • Something went horribly wrong and right off the starting line I headed for the curb, hitting that before going berserk and crashing into a stroller off-course, breaking my right front caster block and bearing carrier.
    • There are two things I can think of that might have happened.
      • My crude steering controller is unstable at high velocities (most likely).
      • The first waypoint somehow got marked as achieved, and the car started going for the second waypoint.
    • The car wasn't drivable without spare parts I don't have, so I missed out on the mass run.

I ended up with 3rd place and $100, which is much better than I expected. Congratulations to Team Tobor and Team Minuteman, from what I've read, heard, and observed, they were both running very slick systems. Thanks to SparkFun for putting this competition on, I'll definitely be back next year!

Edit: I've dumped my code here. Use at your own risk.

Monday, January 10, 2011

Ubuntu in Windows with VirtualBox

I've used Windows all my computing life, and will for the foreseeable future. However, for certain things, it's very useful, sometimes necessary, to have a computer running Linux available for use. I tried setting up a separate computer for this, but I goof off often enough that it wasn't working out.

Enter VirtualBox. It lets you set up virtual machines running "guest" operating systems within your "host" operating system. Someone's already made an excellent tutorial on setting up VirtualBox on Windows to run Ubuntu:

I am running Windows 7 as my host OS and Ubuntu 10.10 Desktop as my guest OS, with Virtual Box 4.0.

Virtual machines have been around for a while, and Windows 7 Professional actually includes a downloadable feature called XP Mode to run Windows XP on a virtual machine. VirtualBox makes it very easy though, the setup required to get to the above screenshot is minimal. Networking worked for me without any extra setup, and keyboard/mouse transitions are almost seamless.

One thing that isn't in the guide above is setting up Ubuntu's resolution to match the VirtualBox window size. It's pretty simple.
  1. On your virtual machine windowbar, select Devices -> Install Guest Additions...
  2. This puts the Guest Additions in the virtual machine's CD drive. Mount it within Ubuntu, by selecting Places -> VBOXADDITIONS_4.0.0_69151.
  3. A window will pop up showing the contents of the CD. There should be a button marked "Open Autorun Prompt". Click it, and let Guest Additions install.
  4. When done, "eject" the CD from the Devices menu, and restart the virtual machine. From now on Ubuntu will resize its resolution to the VirtualBox window size. There's also some other cool features available in the Machine menu, like Seamless Mode.
The last modification I did to my setup was to allow SSHing and SCPing to my Ubuntu machine. VirtualBox necessarily passes all network traffic through the host OS, so an attempt to SSH or SCP to the guest will look like an attempt to the Windows host, which won't work. The solution is to add a networking rule to forward that traffic to the guest. Since Windows doesn't have anything using port 22, we can keep it simple.
  1. Shutdown your virtual machine and close all VirtualBox windows.
  2. Open up a command prompt in Windows. Start -> Programs -> Accessories -> Command Prompt
  3. Execute the following command, replacing YOUR_VM_NAME with your virtual machine's name. This creates a rule called "ssh" for your virtual machine, forwarding host port 22 to guest port 22.
     > C:\Program Files\Oracle\Virtualbox\VBoxManage.exe modifyvm "YOUR_VM_NAME" --natpf1 "ssh,tcp,,22,,22"  
  4. Open VirtualBox and restart your virtual machine. You will probably get a Windows firewall alert, allow VirtualBox what it is asking. Your virtual machine can now accept SSH connections from your local network if you're behind a router, or from anywhere on the Internet if you're directly connected or in your router's DMZ. 
That's all the VirtualBox setup I've needed. Almost all the benefits of Linux without the drawbacks of actually switching over!

Sunday, January 9, 2011

Insignia Infocast 3.5"

Best Buy had the Insignia Infocast 3.5" on sale for $40 after Christmas, so I bought one online and finally tracked down a unit for pickup in Glendale last week. It's essentially a rebranded Chumby One, which is a device that nobody legitimately needs to have, but that has found a niche market with people who (among other things) want internet access on their alarm clock. It also runs Linux and is easily hackable by design, which is why I got it.

Insignia Infocast 3.5" from Best Buy
  • 454MHz Freescale i.MX233 ARM "applications processor"
  • 64MB RAM
  • 1GB MicroSD storage
  • 320x240x16 touchscreen
  • 802.11b/g wireless
  • 1x external USB 2.0 port
  • 3-axis accelerometer
  • Internal speaker and microphone
There's also a bunch of hidden features on the board, like a 3.3V serial port, composite video out, and digital I/O pins. The hardware developer has a post about this on his blog.

The first thing to do is to void your warranty and get at the SD card to make a backup copy. Almost all the software is on the card, making it very hard to "brick" the Infocast as long as you can restore the card to its original state. There's also a recovery mode activated by powering on while pressing the touchscreen that can save you from minor mishaps.

1. Carefully remove the volume knob.
2. Remove the back shell, held on by 4 recessed Phillips screws.
3. Separate the shell. It is still attached via the whip antenna.
4. Slide the metal cage to the right to remove the MicroSD card.
Once you get the card out, you can pop it into your card reader and make an image (Win32DiskImager on Windows or dd on Linux). Now if you screw up beyond repair, you can start fresh by reimaging a card. I actually didn't do this until after I'd futzed around a bit, so my image is not quite factory-fresh.

Someone else has done a much more detailed teardown of the Infocast 3.5" (here).

There's a lot that the stock Chumby software can do, including streaming internet radio and looking at pictures of cats, but that's not as interesting as using it as an embedded computer. Most of the related easter eggs are detailed on the Chumby Wiki, which is a good place to start. There's a great guide on how to strip down the Chumby One, which I used as a reference to create my own startup scripts.

My barebones boot screen
I assigned a static IP to the Infocast, put it on my router's DMZ, and registered a hostname with a free dynamic DNS service (, pointing to my cable modem's IP that changes every few days. The Infocast is running a dynamic DNS client (inadyn) that updates DynDNS whenever this happens. Note, if you do this, you should set passwords for the root and default users (or disable SSH access).

Next up I think I'll play with the accelerometer and drawing things on the screen. Eventually I'd like to get it interfaced to a UVC webcam.