Apr 302011
First of all I want to thank Sparkfun, the competitors, and all the spectators for making the day so much fun.
Tobor after the 2011 AVC. The Xbee got ripped off in the mass start.
I had gone to Sparkfun a few times in the weeks before the 2011 AVC trying to get Tobor back into racing trim and I had zero luck each time. The weather was downright chilly every time I went to test and that just added to my misery. In fact, Tobor had only made it around the course twice before. Once on the morning of the 2010 AVC and once during the AVC with the 2010 winning time of 1:55. I also had big hopes of adding five Maxbotix sonar range finders, but they reported all sorts of nonsense readings while I was at Sparkfun. Even when I pointed the sensors into the sky, I got readings of about fifty inches. I never figure that one out. In addition, one of the sensors decided to start emitting magic smoke for no reason during a test. That one is going back to Maxbotix for some forensic analysis. Of course, the Maxbotix sensors always seemed to worked great at home.
The night before the AVC I was there with a few other competitors in the SFE parking lot, including team AutoCrusher, but I just could not get Tobor to successfully complete a lap. During my best attempt, I got around three sides only to veer into the curb just before turn four, but that’s when I notices that the green LED that indicates GPS lock went out. I also had some telemetry data from another run (Tobor logs run data onto a micro SD card as well as broadcasts the same data back to the laptop via a XBee) that indicated my GPS horizontal accuracy was rapidly increasing to several km! Clearly something was up with the GPS.
I went home in the dark very frustrated an even joked with Sarah that I wasn’t even going to show up for the AVC on Saturday. I sat on the couch, had a few beers, and pondered the situation. On AVC day I got up at 5am, took a look at the snow falling outside, and went to the kitchen table to fiddle with Tobor for a few hours before the race. Sitting on the table I got a GPS lock in about 30 seconds, but if I touched or tapped the GPS unit, I lost lock. Ah ha! Then I took a look at the GPS connection to the DIY drones breakout board: the female connector on the uBlox GPS was pretty green from corrosion (it looks like the flux wasn’t cleaned well) and it was clear that the connection between the GPS and breakout board was very flakey. I sprayed both connectors with flux cleaner and gave them a good scrubbing with a horse hair brush. Then I reassembled the GPS and breakout board and put a few drops of hot glue in between the boards. Now, when I tapped, tugged, or generally abused the GPS unit I kept lock. I was back in the game!

The hot glue GPS fix. The ublox connectors aren’t robust at all. Last year, I just wrapped the whole assembly with a rubber band.
At the 2010 AVC, I had a run where the car “diverged” and went in circles. I assumed this behavior was due to some sort of interference from the wet pavement and the IR curb sensors, but it must have been the dodgy GPS connection. I saw similar behavior the night before at SFE. 
Feeling a bit better about my chances, I woke Sarah up, took a shower, packed, and then we got coffee and headed down the hill to Sparkfun. There was about 2 inches of snow at our place by this point. I was almost hoping for snow at Sparkfun. Those sand tires might work well on the snow.
We got to Sparkfun early and I was able to get Tobor out for a test run. He almost made it around the building, but I had to pause my test run due to some folks on the course. Tobor’s overall performance was much improved, so I tweaked the waypoints and called it good. At this point, I still had not made it around the building fully autonomously. I left the bracket for the Maxbotix sensors on Tobor, but they weren’t even hooked up. Intimidation purposes only.
I also had to poke some holes into the rear tires since the pressure and temperature change from Nederland to Boulder had actually caused the rear tires to buckle inward. I had hoped to do a recalibration on the odometry, but I had to let it slide.
Heat 1
I had set Tobor to have a constant throttle setting for heat run and the setting was just a bit faster than the setting I had used in Heat 1 in 2010. Things went well and I almost made it through the hoop, but the cow catcher hit on the left side of the car and I scraped by on the right side of the hoop. I got around in 1:22, but the last segment of the course was a bit too far north and Tobor charged the finish line by driving right through the crowd in front of the stands. If you look on the video you can see the cow catcher bouncing off of some poor spectators ankle. I thought I was in first place, and was confused later when I saw that Minuteman was actually in first. I never saw him pass me. I had to read Nathan’s blog entry on DIY Drones to find out that Minuteman was stepped on during heat one and he got a do-over because of judge interference.
Heat 2
I bumped the speed up significantly at the start and finish of the course, and only slightly for the portions of the course between turns one and four. I also moved waypoint #2 (the one right after the hoop) one meter to the East and waypoint #4 south a bit to keep Tobor out of the crowd on the home stretch. This run went well (I don’t know my actual time), but I missed the hoop again. This time on the East side by just a few inches.
After heat two I noticed that the Sparkfun judges had awarded me the 30 second deduction for going through the hoop. I was running, so I didn’t see what happened, but my family told me that Tobor had, in fact, gone wide to the East. I told the judges about their error and they joked about an additional 20 second deduction for honesty.
Heat 3
I knew that Minuteman’s time was going to be hard to beat, so for heat three I increased the throttle command to maximum. I had never run Tobor this fast before, but the navigation system seemed to be working amazingly well. I even took off the inert Maxbotix gear to cut down on drag! On run two, I don’t think the curb avoidance system had to do much work at all. I also moved the waypoint #2 half a meter back to the East. I figured that I would get the hoop bonus by successive approximations. 
During the wait for run three, I was kicking myself for not installing the bigger motor. The Tamiya Grasshopper comes standard with a Mabuchi 380 motor. This motor was great for getting a longer run time back in the day when RC cars ran NiCd batteries since the 380 draw a lot less current that the standard 540 motor. Nowadays, folks run brushless motors, so Tobor is at a huge disadvantage when it comes to maximum possible speeds.

Here’s my speed boost for next year. It’s not even one of the “race-tuned” models.
There was nothing I could do except cross my fingers and wait. Heat 3 came and started out great. Minuteman was running faster than Tobor, but he missed the hoop and Tobor made it through. The rest of Tobor’s run was flawless. Minuteman clipped one of the concrete islands and didn’t complete the heat.
I couldn’t believe it, but Tobor beat Minuteman’s time by only one second. You couldn’t script better drama!
Here’s the under-the-hood shot of the rat’s nest. The Arduino Mini monitors channel three on the RC so I can switch to manual control if the Arduino Mega crashes. The openlog stores all the sensor and state data. The gyro is buried under the Mega and the magnetometer is up front away from the steering servo. Two regulators generate the extra current needed for the Sharp IR sensors and GPS. It’s all wired up with wire-wrap and point to point.
This year the curb avoidance system was greatly improved by replacing the three long distance Sharp GP2Y0A700K IR sensors with the more reasonable Sharp GP2Y0A02YK0F IR sensors. The IR sensor from last year had a minimum distance that was just too large and Tobor could end up in an oddball nonlinear limit cycle near curbs. It sort-of worked, but was very suboptimal. I also changed their angle so they looked ahead quite a bit more. I also removed the third straight-ahead looking sensor, since I never came up with a good heuristic to integrate that reading with the other two. In addition, I replaced the old curb avoidance scheme which just fed the range sensor readings into the steering servo with a first order low-pass filter set to a time constant that was about equal to the left-right transit time of the steering servo. This really smoothed out the curb avoidance and rejected sensor noise pretty well. I also added a removable pot bank to the car so that I could adjust system gains without reprogramming Tobor. Unfortunately, I had such poor luck testing, this was never really used. That cow catcher I added seemed to be a good idea. It prevents the car from catching a tire on an obstacle and at high speeds, and curb scrapes are recoverable. 

The navigation system in Tobor 2011 is the same one I used in 2010. I think that flaky GPS connection was the root of all of my problems and Tobor could have gone three for three in 2010 had I fixed it then. I didn’t even change any of the numbers in the noise covariance matrices!

Here’s the state vector for Tobor. This gets updated at 20 Hz.
Tobor runs a six state Extended Kalman Filter at 20 Hz. The sensors either provide four or six measurements depending on if new GPS data is available. Since the ublox GPS runs at 4 Hz, most of the update only fuse dual wheel odometry (two numbers), the gyro (one number), and the magnetometer (one number). Every fifth update uses a bigger H (observer) matrix and GPS gets fused in. That observation has six elements. The EKF uses single precision floating point arithmetic and there are no optimizations. It’s a textbook implementation and I do a matrix inverse 20 times a second. I use the reported horizontal accuracy from the GPS in order to form the GPS covariance. That way is the GPS accuracy degrades, the sensor fusion is still “optimal.” Surprisingly, the time to do the data logging is a significant portion of the loop time. The serial.print() function on the Arduino is pretty slow and I output human readable data. A binary format would free up some processing time to add more states. The Arduino Mega is required for the extra serial port and the RAM to hold the big matrices.

Wheel encoder details. The encoder wheels are laser printed and glued to thin model airplane plywood. They’ve lasted through two wet AVCs! The sensors are the analog Pololu models and I square-up the signal with a Schmidt trigger. There is no provision for going backwards. If you have to back up, you’ve already lost.
I’ve got an identical EKF implemented in Matlab and Tobor logs all the sensor data as well as the state output of the EKF running on the Arduino. As a result, I can re-run any course offline and tune the filter and sensor calibration. For example, driving the car open loop around a known course and stopping exactly where the car started generates sensor data that I can feed through the Matlab copy of the EKF. Running the EKF with GPS turned off allows me to run a second optimizer that adjusts the calibration factors on the wheels (left diameter, right diameter, and separation) in order to minimize an accuracy metric that measured the difference between the start and end points. Last year, the data showed that the rotation angle from the differential odometry was good, but not great. The fusion of gyro data and odometry, however, was pretty impressive. I never spent any significant effort on using just odometry for distance and the gyro for angle. This approach, however, is basically what Minuteman is did. Tobor also fuses a magnetometer into the state estimate, but I’ve got the sensor noise covariance turned way up so local variation in the magnetometer reading don’t affect that state too much, but over longish times, the magnetometer and GPS track give Tobor an accurate estimate of heading. 
Before each run I reboot Tobor and drive in a few circles. I’ve got an adaptive calibration running on the magnetometer and it takes about four circles to get a good calibration. I also drive in a straight line for about ten meters in order to get a GPS track to fuse into the heading. By this point, the EKF state has converged to a good estimate of location and position.
Another key point is that the Tobor state vector is augmented with a gyro bias term. Temperature calibrations can work, but they are just the wrong way to approach the problem. Tobor has plenty of other sensors that give information about angular rate, so you just let the EKF generate an optimal estimate of the gyro bias term as well.
Once you have a good state vector, control is easy. The steering servo is driven by a proportional control term that is given by the difference between the vehicle heading angle and the computed heading to the next waypoint based upon the cars estimated position. There isn’t a need for more complicated control since the steering servo angle sets heading rate and that gets integrated by the car kinematics to give heading angle. Once the state vector says Tobor is withing a certain distance of the waypoint, the waypoint index is incremented. The waypoints on Tobor wrap around, so the car should, in theory, keep going around the course until the batteries die.
Throttle is open loop. There is no need for fancy PID speed control since Tobor had to run at full throttle anyway just to be competitive this year. The only reason to add an I term is to get the steady state error down, but this doesn’t matter since the speed control on these bots isn’t calibrated. You only need D if you can’t get a good enough response time with K alone. Throttle control is just step on the gas.
Some numbers
Tobor’s best time was 55 seconds and Minuteman was only a second behind. Working from my waypoints, the distance around the course is about 270 meters and based on our times Minuteman and Tobor were both doing almost 11 MPH on their best runs. 
Since Minuteman runs in a dead reckoning mode, the starting angle is very important. Each miliRadian of error in its starting alignment results in about a foot of error over the course. That’s a foot of error for every 0.06 deg. Not to bad, but alignment is definitely important.

Finally, the winning speeds this year were about 1.2 m/s, so you only get a GPS update every 30 cm. That’s not so bad, but you need odometry to fill in the blanks. Odometry is very accurate over small distances, but errors grow with time. GPS is bad over short distances, but long time averages are great. Synergy.

I’ll be going through the data logs from the runs and posting tracks soon. 
 Posted by at 2:21 PM
Apr 262011

I’ll post a wrap up on the 2011 AVC soon, but here’s a quick video I made from the footage we gathered.

The mass start is epic. I’m hoping that Sparkfun has better footage of Tobor threading the needle. I lost track of how many flipped bots there were in the first few seconds.

 Posted by at 1:03 AM
Apr 182011

So my obstacle avoidance last year was a total last minute hack. This year, I left things to the last minute again, but I still have time to replace a major hack with something that’s at least reasonable. The jittery steering when obstacle avoidance is turned on is due to the fact that I’m feeding the scaled sensor values directly into a steering offset. Noise in the sensors ends up as noise on the steering servos. And the sensors are pretty noisy.

I’ve implemented a simple first order system to smooth out the obstacle avoidance error signals and it seems to work well. The other thing I’m adding is a bank of pots on the outside of the car. I’m going to use them to adjust some of the system gains so I can run the car, stop it, turn a knob, and re-run the car. I’m hoping that this will increase my iteration rate so I can dial in on a collection of gains that work. Once I have it working, I’ll take the pot values and hard code them into the car. The more system tuning I can do without re-compiling, the better.

Time for bed.

 Posted by at 9:10 PM