Friday, March 25, 2011

GPS, Gyro, and Compass Errors

Continuing to flail, here. I still don't have reliable navigation working and I'm a month away. That sounds like a lot of time but it's a flash in the pan. I'm very nearly screwed.

My recent test runs suggest various possible errors in the navigation sensors. Here's what I've come up with so far based on two test runs last night and some offline analysis of the raw sensor data.

GPS Errors

I equipped Data Bus with the iGPS-500 and collected data for both GPS units simultaneously. I thought because the Locosys was getting a fix that it was to be trusted.

But it's been unreliable. Last night the iGPS-500 was the only one of the two modules getting a fix... inside the house!  A multi-satellite fix, at that.  Long story short the iGPS-500 frequently seems to produce better data.

Below, the iGPS is pictured in blue, the Locosys LS20031 in green. It's all over the map. In my other test run,  the iGPS did ok, but went squirrely in the upper right near the big tree. The Locosys looked better in terms of shape but was offset about 50 feet.

The dark red path above is the dead reckoning plot using compass. The lighter red is the dead reckoning plot produced offline with a perl script, using raw gyro data with a hand-tuned gyro bias. It's easily the closest to reality.

Compass Error

I wanted to see if the compass simply had a bias so I tried correcting and replotting for 20 degrees then 25 degrees.

The pink path below is the original on-board dead reckoning plot. The green is the same plot rotated 20 degrees and the blue, 25 degrees. The red plot is the hand-tuned gyro-based dead reckoning.

Clearly the issue isn't a simple bias.  The compass heading does not seem to change with the correct proportion during turns.

Part of that may be due to the tilt from the convex surface of the road throwing off the heading. Possibly also because the road itself slopes slightly downhill. I don't really know for sure. I need to...

  • recalibrate the compass with the on-board calibration routine
  • gather data a few more times from a site with flat ground
  • experiment plotting my prior 3 test runs
  • if the error is still there, determine the nature of the error

If the error isn't due to the sloping street, and if I can describe the error in state space form along with the heading and heading rate (gyro), then I 'should' be able to build a Kalman Filter to deal with it.

Gyro Error

I had been trusting the compass most. It looked so good on a graph. But I was wrong. Using it to plot dead reckoning shows the real truth. I hadn't really trusted the gyro until now.

Experimenting with different bias values, the gyro provides the best dead reckoning information and in fact the best positioning information. It appears that the biggest contributor of error is the bias (or drift of the bias). Which suggests that if could only find a way to calibrate for the bias, I'd have reliable navigation.

The plot shows dead reckoning plots with different bias values. The purple plot shows a previously measured bias of 2027 (that's the raw, 12-bit ADC conversion value, approximately equal to 2.4496V). The blue corresponds to 2028 (2.4508V), green to 2029 (2.4520V). So I tried 2028.5 (2.4514V), the red, and I think that's probably the closest match.

I can't just take an average at standstill because I tried averaging the first several seconds of the data before the robot started moving. The resulting plot was off quite a bit from reality. So... is there a bias that comes into play when in motion, or during turns? Or was it due to temperature effects?

At worst, maybe I can make test runs and hand calibrate bias until the plots look right, and somehow correlate that to temperature. What super sucks is that we're talking about nailing the bias down to the nearest half a millivolt.

Dead Reckoning Integration Error

All the off-line plots were done by integrating heading and distance measurements every 20ms intervals, an order of magnitude more often than the robot's onboard code. Yet, the difference between the plots is pretty negligible. So integration error doesn't seem to play in.

I wonder if there's some distance error due to using straight line interpolation to represent the curved vehicle path. If that error was large, I'd expect to see a bigger discrepancy in plot length visible at the end of the path in the lower left part of the pic above. Instead, the length of the two plots are within 10cm of each other.

Kalman Filtering, Fusion

Maybe this is inexperience talking but at this point I don't see how Kalman filtering can possibly make use of the massive compass and gps errors to stand any chance of correcting for bias on the gyro and producing reliable heading information. I would expect a Kalman filter would basically tune out the measurements from GPS and compass to the point of ignoring them.

Oh yeah, almost forgot, I still have to dodge barrels.

And I haven't done squat with obstacle detection let alone avoidance.

Yup, I'm Screwed

Now I'm struggling to get a reliable 5V power supply for the robot that can deal with massive voltage sags from the BEC under heavy acceleration.

And as of last night, I'm fighting with that stupid, buggy RC switch board again. It switches off control of the MCU but doesn't switch on transmitter control. Great.

And on top of everything else, my espresso machine has been broken for a week and my efforts to revive it last night were in vain.

I'm just not winning right now.

But hey, I'm not complaining. Ok, maybe I am.

Meanwhile, you may wonder why I'm bothering to write all this when I should be working on the robot. Believe me I have been working very hard on the 'bot. These posts help me to collect my thoughts. Also, I feel more accountable to get busy when the time permits.

Tuesday, March 22, 2011

AVC Bot: Dead Reckoning

Eeek!  Only 30 days left before race day!!

You may be wondering what happened. Why Data Bus crashed repeatedly.

I've a high level of confidence that GPS error and, to a lesser degree, heading error were the causes. As I continue to collect more and more test run data, GPS plots show pretty substantial position errors, even when the GPS has a very good fix (HDOP of 1.2 or less).

I've been planning all along to supplement GPS fix information with dead reckoning computations and I've finally gotten the software bugs worked out. Here are the plots I collected last night showing errors in GPS and dead reckoning position estimation.

The Plots

In each test run I'm starting at the exact same geographic location: the intersection of a concrete seam and the asphalt at the end of my driveway. I've plotted the point in Google Earth, and I've initialized the dead reckoning code with those coordinates as starting points.

In general, all the dead reckoning plots have the right shape, but seem to get the distances a bit wrong and they appear rotated counter-clockwise by several degrees. The GPS plots at best have the right shape but are off by around 50' in various directions. At worst, the fix data is nearly unusuable.

I'm taking distance and heading measurements every 200ms and the GPS sends fix information just as often. But the GPS data is obviously much noisier, hence the jagged lines as in the plot above and below.

So what does it all mean?  

  • At slower speeds, the wheel encoders effectively have less resolution, increasing error
  • Distance calculation error is propagating throughout the run
  • The compass appears to have an offset of several degrees
  • The GPS may be updating too quickly to get accurate results for the slow speeds traveled
  • Google Earth undoubtedly has some positional error
And what do I do about it?

I could optimize the tradeoff between calculation frequency and encoder resolution. The main distance problem is likely wheel circumference error propagating. More on long paths than short ones.

Last night I drove the robot in a straight line for a known distance and captured the total number of encoder ticks. The original circumference measurement was 3% too large.

I'll calibrate the compass with the onboard calibration and using a compass. I can calibrate it to a known straight feature in Google Earth, too.

To improve GPS readings, I'll try setting the update rate to 1Hz and see if that improves accuracy. I'll reinstall the iGPS-500 and gather data for both units and compare.

Google Earth introduces some error that I'll have to address next.

Beyond Individual Sensors

Ultimately there's a limit to each sensor's accuracy and precision and to calibration methods. Using statistical methods to fuse sensor input should improve accuracy.

I really have no idea if it is possible to get down to sub-meter accuracy navigating a 240m path while driving around barrels and colliding with other robots. I hope so. I better find out pretty darn quickly.

Friday, March 18, 2011

AVC Bot: Kill Switch

Dramatic, automated, high speed crashes, robotic parts flying, babies wailing in the background, gnashing of teeth... now that's what I call fun times!  And it describes perfectly what happened during the Maiden Voyages of Data Bus.

I had a remote kill switch installed. Turn on the RC remote and the robot would drop out of its main loop, turn off the throttle and steering... and crash anyway.

Remote kill switches are a good idea but if I could've taken control of the robot remotely I could've avoided crashes and saved having to chase after the wayward robot on foot. I could've driven it back to me.

Time to implement a combination kill switch / remote takeover circuit. Turn on the RC transmitter and immediately take control of the robot, steering it to safety, applying the brakes, etc.

I started with this website and circuit design.

WARNING: I'm not making any expressed or implied guarantees about the reliability or performance of this circuit. It's your responsibility to determine the best method of implementing safety measures for your situation.

Nevertheless, I hope this discussion is helpful and, perhaps, encourages other roboticists (and particularly AVC competitors) to implement remote kill switches and even 'take control' devices on their autonomous robots.

In subscribing to the Open Source Hardware ideal, the Eagle files for this and other Data Bus electronics can be found here --- Warning: the Rev 0.1 board has a couple bugs!

Detect Servo Pulses

First trick: a circuit to detect servo pulses. The circuit on the website above does this.

It implements a high pass filter, buffers the signal with an op amp, and rectifies it to build up a voltage in a capacitor. The output is high when the transmitter is on, low when it is off.

I modified the rest of the circuit for my own purposes. I wanted to build something quickly with parts on hand so I can get back to testing and refining the robot.

The "Switch"

I selected a 74*244 tri-state octal bus driver* as I had several on hand and it was an easily implemented solution. The 74*244 has two sections consisting of 4 inputs and 4 outputs (see picture).

Each section has an active-low enable that connects the section's inputs to their respective outputs. My circuit needs to switch between MCU servo signals and Radio servo signals so here's how I wired it up.

Certainly, a number of analog switches with smaller form factors than DIP-20 are available.

The Switch Driver

Note that each "servo" output and each "esc" output are tied together above. Only one of the sections of the *244 will be enabled at any given time, so between the detection circuit and the switch circuit, some "logic" driver circuitry was needed.

I breadboarded the heck out of the circuit to be sure it'd work. I had to try various configurations and designs before arriving at one that seemed to work reliably and which provided TTL/CMOS compatible high and low logic voltages.

The voltage signal from the detection circuit (left, middle line above) is amplified through the other half of the dual op amp.

Why? Servo pulses occur only about every 50ms and last only 1-2ms, and the pulses out of the filter are even shorter, so there's not a lot of current going into that 4.7uF capacitor. Its voltage is pretty low, too.

The amplifier has high input impedance so it doesn't draw down the capacitor voltage. When the transmitter is on, the circuit amplifies the signal to peg it near the supply rail, comfortably above the *244's threshold voltage. That way there's enough voltage and current to drive the *244 enable pin.

To drive the opposite enable pin a small signal transistor (2N2222A in this case) in common emitter configuration inverts the detect signal, drawing a tiny current out of the 4.7uF capacitor through a current limiting resistor and driving the opposite pin low (about 0.2V, well below the *244's threshold voltage) when the transmitter is on.

When the transmitter is off, the capacitor signal is at 0V. Thus, no base current is available to drive the NPN transistor, so only a minimal voltage drop occurs from current drawn through the collector resistor. Its output voltage is very near Vcc.

Recycling Components

I wanted to build the circuit with parts on hand, minimize board size, and avoid drilling holes. I'm sick of drilling holes.

Well, I didn't have any 74*244s or LM258 op amps in SOIC packages. But I did have some surface mount components that I could reclaim from some boards I salvaged out of PCs, CD and DVD players, and other audio equipment.

The board has a mix of size 1206 and 0603 resistors and capacitors. It also uses a tiny, salvaged 4mm, through-hole, 4.7uF electrolytic cap.

Beggars can't be choosers so I was stuck with some odd component values that I had to test on the breadboard before I could use them on the PCB. Fortunately the circuit seems relatively tolerant to variations in most of the components.

I also borrowed a (tiny!) SOT-23 2N2222A's from another project of mine that's on hold.


I've been honing my PCB fab skills over the last several months and have some new-to-me techniques to share.

I used the toner transfer method I've been practicing to fabricate the board with 16 mil traces. I etched it in Ferric Chloride in a warm water bath, a new technique that significantly speeds up etching time. The first attempt was over-etched because I left the board in too long.

I drilled holes with the rotary tool in a drill press as usual, then tossed the SMDs on after tinning and coating the board with flux paste to hold the parts in place.

I did the reflow on my reflow skillet. Then I used toner transfer method to "silkscreen" the board and, another new technique, sprayed the top of the board with clear gloss acrylic paint which I think makes the board look more professional. In fact, all the Data Bus boards are sprayed this way.

Note the two brown wire jumpers...
I soldered the through-hole parts on, and this time tried polishing the copper side with the rotary tool and a brass wire wheel, and then sprayed the bottom with acrylic. Looks nice. That should help prevent corrosion. I may go back and do this on the other Data Bus boards.


Filed under "colossal goof-ups" are the following:

I realized only after I'd plugged in everything that the robot's new ESC outputs 6VDC not 5VDC. Oops. What'd I fry? Possibly the original 74LS244 I selected.

But, by some absolute miracle, it turns out all the other 5V devices on the robot were tolerant to 6V! I seriously dodged a bullet there.

I switched the *244 for a 6V-tolerant 74HC244 and wired in a Pololu 5V regulator to power the mbed and attached 5V devices.

Next, I discovered that I had reversed the enable signals to each of the 'switches' on the *244. Argh! The quickest solution was to use jumper wires. I pulled the 244, bent pins 1 and 19 horizontally so they would no longer engage in the socket, soldered on wires, and plugged the wires into the appropriate socket holes. It worked!

Oh, and the input/output connectors are mislabeled. Oops. I hope that doesn't bite me on race day. (I hope I didn't just jinx myself)


I incorporated some changes into the Rev 0.2 version of the board in case I need to re-do it at some point, probably in preparation for 2012. I fixed the enable wiring bug and I made space for a SOT-223-sized, 5V, 1117 LDO regulator.

Ideally I'd probably switch over to a dedicated, DPDT analog switch IC. I'd likely keep the DIP-8 op amp as it makes single layer layout much easier.

But, I can make this board work. I need to focus my remaining time and energy on object avoidance and improving the accuracy and precision of the robot's navigation.

* So now Data Bus has a bus driver on board...

Tuesday, March 15, 2011

AVC Bot: Maiden Voyage Video!

Here's video from Saturday's maiden voyage of Data Bus! Test run on the 13th, video on the Ides of March. Fitting.

Friday, March 11, 2011

A Cheap GPS Enclosure

Well, I'm down to the wire. Saturday my friends and family will either come over and see my robot crash spectacularly or actually succeed in its maiden mission.

After Saturday, I'll be slowing down the pace of blog posting to once or twice weekly until the big day. Hopefully the deluge of posts this week has been entertaining.

Meanwhile, for Saturday a GPS is somewhat important. With the Locosys LS20031 GPS back in business, it was time to mount it. But it's just a bare board with four holes in it. No protection from the elements.

What if it snows or rains during the 2011 Sparkfun AVC? What if a piece of gravel kicks up in just the wrong way?

I thought and searched and finally decided on a perfect, compact, $4 enclosure: a container of Oral B Guide dental floss!  (Or, use the floss first and it's free!)

Open the lid, crack the case, pull out the metal floss cutter and the floss, and the tinted window. Then clip the floss spool post.

LS20031, upside down, stuck to case back
Using double sided sticky tape, affix the antenna side of the GPS module to the back of the case. Don't stick the bottom side, because the only thing there to stick to is the very fragile RF shield which will pop off (ask me how I know)

Hope the connector fits...
Cut a hole in the case for your 4-pin connector (Vcc, TX, RX and GND. There are two ground pins; solder a jumper across those). Now guesstimate where the hole goes in the lid, mark it, and cut.

Ooo, I nailed it!
I sliced off the bumpy printing on the back and stuck on a simple label with packing tape.

Not bad for $4 and a few minutes' work
It's not waterproof, but it offers much more protection than the bare module and should fend off light rain or snow.

For an added bonus, the GPS indicator LED is clearly visible through the case as a red glow. Cool.

Thursday, March 10, 2011

AVC Bot: Wheel Encoders

My AVC robot and Pokey my firefighting robot have some things in common. Right before I started working on the AVC robot, I was installing wheel encoders on Pokey and had...
I used the lessons learned on Pokey to implement wheel encoders on Data Bus.


Since I don't have enough spare pins to read a separate counter IC's value, and rather than complicate the overall design with a separate microcontroller communicating over SPI or I2C, the mbed microcontroller will interrupt for each individual encoder trigger from each of the rear wheels. I may even add front wheel encoders, but I doubt it.

What resolution to pick?  On the one hand, I don't want to overload the processor. It's got plenty to do: gyro, compass, and ranger sensors have to be updated in near real time at a fairly high rate, around 20-50Hz. On top of the fact that a lot of computation will be happening to estimate heading, position, bearing to waypoint, and so on.

On the other hand, to improve navigational accuracy, the robot will be incorporating distance data traveled at a given heading to estimate vehicle position (supplemented by GPS).

If I update the gyro heading at 50Hz, then it makes sense to update the distance data just as often. So I need enough stripes to offer reasonable resolution at 20ms intervals, but not too many that servicing the interrupts takes away from other processing. I haven't determined what that balance is, yet.

My Wheel Encoder Generator java application hard at work
Just for testing, I arbitrarily chose 8 stripes. With a 4.1" diameter wheel traveling at 20mph (unlikely) that's a maximum of 8 interrupts per revolution on rising and falling edges, or one interrupt every 4.6ms. That should barely tax the processor.

The current revision of the encoder discs use 16 black stripes for 32 edge triggers per revolution.

Pokey's encoder interface

The IR Reflectance sensors are breakout boards from Sparkfun using the QRE1113 SMD sensors. They work fine on the 3.3V that powers most of the electronics on board.

I started by using the circuit and board I designed for Pokey, initially, but found it woefully unsuitable. At low speeds and standstill it would tend to give many false readings.

I implemented a schmitt-trigger circuit using the same LM393 comparator. (Schematic and Board here)

It seems to work more reliably at all speeds now.

Schmitt trigger encoder interface installed
Encoder Discs

I used foam core, cut to friction fit inside the 2.8" RC truck wheels. I didn't have to be very precise in my cutting and I wasn't. Hopefully no one will notice and make fun of me on race day.

The encoder disc pattern was generated with my handy Wheel Encoder Generator (soon to be released to the world in beta) application. I printed the patterns on self-adhesive paper and stuck them to the foam core and inserted them into the wheels after some trimming.

Sensor Mounting

There aren't a lot of places to mount the reflectance sensors on the ElectrixRC Circuit. The best place I could come up with was the rear bearing carriers.

They have a flat spot with enough material present that I felt I could drill another hole, mount a bracket securely, but not compromise the part's strength too much.

The brackets are made of brass strip, 1" long with a 90 degree bend at the end for mounting the sensors.

I probably don't have to do much about tuning their clearance or aligning them radially to the wheel. They seem to work fine in this location, triggering the interface board, even at faster wheel speeds as you can see below.

Electronics Testing

To make sure the interface board was sending out a good pulse train, I did some testing on the oscilloscope and it looks like the signal is coming in cleanly to the board, and from the board.

Raw encoder signal
Signal out of the schmitt trigger interface board

For distance, I set up pin interrupts on the mbed for the input pins rising and falling and then counting the number of pulses from each wheel encoder. One can compute speed by dividing by the sampling time and taking the average.

Even with 32 ticks per revolution, this isn't the best way to compute speed if you are checking the counter frequently and your robot is going slowly. Another option is to count the time between pulses to compute speed. It's best to compute time between the rising edges of the signal in case the on time and off time don't quite match.

It's also possible to estimate heading rate based on the difference in the distance traveled by each wheel if you know the track width and have precisely calibrated each wheel's encoder system.

The encoder sensors installed

A later version of the wheel encoders

Wednesday, March 9, 2011

AVC Bot: Adding a Compass

From previous posts you probably deduced that Data Bus, my 2011 Sparkfun AVC entry, now has a compass. I forgot to write about its selection and installation.

Experience with gyro data collection led me to the conclusion that a compass would be really helpful with vehicle navigation. Why?

A gyro tends to have drift that can be hard to predict. GPS updates come too infrequently and are too unreliable as a reference source. A compass offers frequent updates (20Hz  in this case) and a reliable source of steady state heading information.

Selecting a Compass

Sparkfun HMC6352 breakout
Having spent a fairly big pile of money on this robot so far and with my hobby fund dwindling rapidly, a high end compass was out of the question.

Two cheap options presented themselves, a simple Honeywell HMC6352 two-axis magnetometer/compass and a 3-axis magnetometer from Sparkfun.

I had (and still have) my hands full with other mathematical problems that are smacking me to the curb, so having to figure out an algorithm for a tilt-compensated compass was very unappealing.

Plus, the robot is going to be on flat ground at all times and body roll should be minimal. A tilt-compensating compass would be nice but the robot can live without one.

The Honeywell compass won out. It's ridiculously simple to use.

Interfacing the Compass to mbed

The compass is an I2C based device. At it's simplest, you query and it tells you your magnetic heading. To make matters easier, someone had already written a nice, full-function, mbed driver library. So I used it. Like this:

#include "HMC6352.h"

HMC6352 compass(p28, p27);              // Driver for compass

int main() {
    // Initialize compass; continuous mode, 
    // periodic set/reset, 20Hz measurement rate.
    compass.setOpMode(HMC6352_CONTINUOUS, 1, 20);

    // read compass, convert to float
    compassHdg = compass.sample() / 10.0;       

    // Correct for local declination
    compassHdg -= declination;

    // Clamp to 0-360
    if (compassHdg < 0.0) compassHdg += 360;    

    // ...


Compasses are sensitive to iron and current. I mounted mine as far away from screws, the main battery cables, and the steering servo as possible. In fact, I rotated the battery 180° so that the main cables exit the back of the robot, far, far away from the compass.

The compass is currently affixed with double-sided tape to a 2" high "bridge" made of brass that's mounted to the main lexan base. It's final location and mounting scheme are still in the works.

Magnetic Declination

If you've played with compasses at all, you probably know that the error between magnetic and true heading varies all over the globe because the Earth's magnetic field isn't perfectly uniform. The error is called magnetic declination.

If only one could figure out how much the error was at any geographic location... but wait: you can!

Not only is there an online calculator available, but also Geomagix, a downloadable trial application for Windows.

There's more. A magnetic survey was conducted just a year ago in 2010, meaning the utmost in accurate information. How cool is that?

Download the Geomagix code and the 2010 cof file and you're good to go.  Declination at my house: +8.91305°

Now I can configure the robot with the correct declination at the Sparkfun Building or wherever else Data Bus runs.

Tuesday, March 8, 2011

Precision Gyro Calibration

Updated version for 2012

Heading accuracy is going to be kind of important and in my data captures thus far, there is a slight discrepancy between the compass and gyro readings.

Notice the slight discrepancy after long heading changes.
It's possible that the gyro is experiencing some drift when held at a relatively steady rotational rate. It does track the compass heading well in the long run. But I wanted to see if the scale factor was correct or not.

So I decided to make use of my high precision rate gyro calibrator.

High Precision Gyro Rate Calibrator
This is a 1970's Realistic Lab-400 direct drive turntable (it's a surprisingly good-sounding deck, I might add). I would've used my Technics SL-QD33 quartz drive table for greater precision but it's not in such an accessible location.

The Theory

It's really pretty simple. We're talking about a straight line function that, given a voltage, returns a heading rate of change.

Remember y-intercept form?

Where y is heading rate of change r, x is voltage v, m is actually the inverse of the scale factor SF in degrees/sec, and b is the y-intercept aka the gyro's null value N.

We find the slope (m aka scale factor) by getting two or more x, y points. The turntable can spin at 45 rpm (270°/sec) and 33-1/3 rpm (200°/sec)

Once we know m, we can solve for b. This is all high school algebra stuff. Which is probably why it took me a bit for the memories to come flooding back (hey, it's probably been 25 years! Yes, I am that old).

So let's get our data points.

Data Collection

To get the null value I collected data with the robot perfectly at rest.  To get the 33-1/3 and 45 rpm data, I placed the entire robot, all 5 lbs of it, on a large, empty, inverted can on top of the platter to raise the robot up above where it might rip off my turntable's arm while spinning.

After removing the headshell with my precious cartridge and stylus, I balanced the robot and turned it on to collect data.

But wait. How do I know if the built-in strobe light is precise enough? I don't. And it matters.

I hooked up a high intensity white LED to a breadboard Arduino, and coded up a 50Hz blinker program (tuned with DMM to 3 significant digits).with a 25% duty cycle. The platter is marked for 50Hz and 60Hz.

/* Blinking LED
 * ------------
 * Blinks an LED at 50Hz e.g., for turntable calibration

int ledPin = 8;

void setup()
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output

void loop()
  digitalWrite(ledPin, HIGH);   // sets the LED on
  delayMicroseconds(4960);      // Tests show ~40usec for code exec
  digitalWrite(ledPin, LOW);    // sets the LED off
  delayMicroseconds(15000);     // total, approx 50Hz

Turns out the strobe was off by a percent or two. (Hm, I may have to modify my turntable with a better calibrated strobe...)

I manually spun up the platter and engaged the motor. Since it's a big, powerful motor, it had no problem spinning a 5 lb weight for a few minutes.

Data Analysis

Here are the gyro plots (click to enlarge):

Obviously there's some noise in the signals. I wrote a quick perl script to average the results for the stationary (0°/sec) , 45 rpm (270°/sec) and 33.33 rpm (200°/sec) data captures.


$sum = 0.0;
$count = 0;


while (<>) {


  @data = split(/\s+/);

  if ($data[$GYRO] ne 'NaN') {
    $sum += $data[$GYRO];


print "Sum: $sum  Count $count  Avg ";
print $sum/$count if ($count != 0);
print "\n";

The output:
  • 33.3: Sum: 6743185  Count 2247  Avg 3000.97240765465
  • 45: Sum: 10857452  Count 3247  Avg 3343.84108407761
  • 0: Sum: 10281588  Count 5072  Avg 2027.12697160883
The ADC used for the gyro is 12 bit and the scale range is 0-5V. To convert the reading to a voltage, multiply by 5.0 ... actually 4.95V according to the DMM

Ok! We now have our points, (2.445V, 0°/sec), (4.041V, 270°/sec) and (3.627V, 200°/sec) and we can find the slope aka scale factor.

Assuming I did all the measurements right, the actual scale factor of the device varies slightly from the 6 mV/°/sec specified in the datasheet. Best not assume...

Double Checking

What if I double check the slope by solving for it using other points? I get 5.886mV (-0.476%) and 5.893 mV/°/sec (-0.353%) versus the 5.91 mV/°/sec.

Not bad. Some of the error may be due to doing null data collection the next day. Perhaps there was some temperature effect.

If the gyro reading had been 2.444V, the scale factors would've been within 0.015% of each other.

Another double check is to solve for the predicted null value from the first two points (45 and 33.3 rpm)

The predicted null voltage agrees with the measured voltage to 4 significant digits.

Eliminating Voltage Errors!

EDIT: Coming back to this a few weeks later, and re-reading the datasheet, the null and sensitivity are proportional to voltage.

The datasheet recommends using a ratiometric ADC. Simply, use the same supply for the gyro and the ADC's analog voltage reference. That's just what I did.

Therefore, I don't need to include supply voltage in the calculations above!  Instead of calculating scale factor in terms of volts/°/sec, calculate it in terms of LSBs/°/sec.

That is, find SF in terms of the raw ADC conversion value. Calculate slope from raw ADC values (in bold below).

Then, in code when it comes time to convert to °/sec, calculate using the bias (null) and SF in raw ADC value.

float gyroRate(unsigned int adc)
  return ((float) adc - 4027) / 4.898;

Other Considerations

Temperature will no doubt affect null and sensitivity somewhat. I'd need to calibrate again for at least two different temperatures to calculate the influence of temperature. I need to see if the additional accuracy is needed by the system or not.

To further reduce error, I could improve the numerical integration approach.

Integrating the Gyro signal more frequently than 20Hz should reduce error accumulation over time.

The integration function can be improved. The simple approach that I'm currently taking is to simply add the fixed gyro voltage to a running sum.  That's a 0th order interpolation function also known as the rectangle (or midpoint) rule.

Rectangle rule, from Wikipedia
A 1st order interpolation function, the trapezoidal rule, would reduce error and is not computationally intensive.

Trapezoidal rule, from Wikipedia
There are other interpolation functions. But I can't afford to over-engineer the solution given how much more work I have to do in other areas.

One of my readers, (who has become a trusted adviser!) and blog author of the excellent Guy NXT Door blog, suggests the numerical integration error is negligible compared to other errors. He and I have been working on IMU issues at the same time and comparing notes.

Anyway, no sense in over-engineering with so much else to work on!

Monday, March 7, 2011

AVC Bot: Maiden Voyage in 5 days!

I'll post a few more updates this week as we count down the few remaining days until...


...has its maiden voyage in front of friends and family.

Oh, did I not tell you? I've come up with a name for the robot.


I'll post an article all about the wheel encoders I installed on Data Bus over the weekend. I was going to use a circuit I built for Pokey, but it sucks in this application and caused all kinds of jitter and erroneous readings.

I decided to implement a simple schmitt-trigger comparator circuit. The breadboard prototype seemed to work brilliantly, so I just finished fabricating and populating the PCB. It appears to work as intended. Whew.

The hardware lays the necessary groundwork for the robot to reliably determine vehicle speed and distance traveled. On Saturday I may have to navigate solely by dead reckoning. We'll see.

Ideally I plan to supplement GPS position fix information with dead reckoning information for enhanced precision and accuracy.


Mysterious geometries...
I just despise trial-and-error programming. I wasted tons of time on Pokey doing just that a few years ago. This time around I want to mathematically model as much as I can.

Case in point: steering. I'll write up a complete article later. Suffice it to say, I wanted to find a mathematical function to turn a relative bearing (to the next waypoint) into a steering value so the robot exhibits a consistent and predictable steering behavior.

I have a feeling this is going to be advantageous when it comes time to dodge barrels and other robots.


New ESC, Motor!
Truth be told, my robot isn't supposed to dodge any other robots. It's hopefully going to simply outrun them! You can't run into them if they're all behind you!

That means the robot has to go pretty fast, which has other implications about which I'll be posting soon, too. One of the upshots of outrageous speed is that the robot will have to apply brakes when approaching obstacles and turns.

The stock ESC doesn't have a decent braking system so I ordered an ESC with proportional brakes along with a more powerful motor. (Insert evil laugh here). As you can see, they already arrived in the evening mail.

In reality, I probably won't need a faster motor because the robot's speed is limited by sensor range. Maybe. Depending on how much time and luck I have.

For Saturday, to keep things simple, I'll have the robot travel at a fairly slow, constant speed.

Kalman Filtering

Kalman Filtering is still kicking my butt (or, my brain's butt... or...?).

I probably don't strictly need it for Saturday but I'll most likely need it for the competition. Either that or I'll have to implement some other type of filtering and sensor fusion.

Alright, enough for tonight. Back to work... more updates in the next few days.

Friday, March 4, 2011

AVC Bot: Fixing Problems

When things do go to crap, sometimes you just have to go to bed and try again tomorrow.

This wasn't one of those times.

I took a deep breath, dove in, and start hacking and slashing at the problems one by one.

Better GPS Data
I yanked the dead LS20031 and installed the iGPS-500 in its place. I'm glad I put pin headers on the motherboard for both my GPS modules. After a few code tweaks, I did a test run with the new GPS. Here's the track plot.

Now that's more like it.
While there's several feet worth of error in the GPS position, that's better than several blocks' worth of error! This kind of data I can at least work with.

Overall, I'm feeling a lot better about the iGPS-500 than I did about the Locosys module. I don't know what it was, bad juju? I've just not had good luck with 'em so far. To be fair, poor mounting was probably causing most of the problems.

Hopefully the SiRF III can handle the urban canyon and trees at the SFE building almost as well as the Locosys' MTK chip.

It doesn't have to be perfect; I plan to supplement the GPS with other sensors that the robot can rely on more heavily when the GPS signal craps out.

The 1Hz update rate isn't bad and I guess I can live with 4800bps. Funny how all the "must haves" turn into "who cares?" when you're getting desperate.

Check out the speed plot.  Though I can't cross check the speed, the numbers are far more plausible than the those from the Locosys, and the shape of the curve looks approximately right given the maneuvers I was doing with the truck.

Far more realistic speed plot. Top speed 20mph downhill!
The GPS was seeing 1.2-1.8 HDOP which isn't bad. It's not great, but the important part here is that I'm getting decent heading, speed, and position data.

Calibrating the Compass
Next up, I figured I better calibrate the HMC6352 compass I added (more on that in another post). The mbed library that's available for the device is very fully featured including a method to enter or exit the calibration mode.

I wrote up some quick code to calibrate the compass and performed the calibration.  Heading data was already looking better in the basement here. The test run is even better yet:

Gyro and Compass now agree. GPS is close, but delayed
Notice how the compass and gyro heading estimate readings track pretty closely.  The only gyro calibration I've done is just by trial and error eyeballing the plots so I should be able to improve gyro accuracy even further.

And it looks like the compass is pretty responsive, meaning I can use the compass for turning as well as steady state.

Data Logging
I switched from logging to a microSD card to logging to the built-in mbed filesystem / USB drive.  It seems to be working reliably so far.

The reason I didn't use the built-in drive to begin with was because uSD logging on Arduino was so easy, because it has less storage space, and the mbed LocalFilesystem library warning scared me.

But there's no need to fear. Recovering the drive is easy. I've done it twice now. :)

The built-in disk is easy, reliable*, and more convenient than the SD card. Just plug the mbed into the computer's USB and there are your files.

Hydra Heads
Another problem came up. My gyro stopped working. I must have introduced some problem with the main AVC code but was able to fix it after updating and republishing my ADC128S mbed library. I hate these problems that come out of nowhere and invariably burn up an hour or two. But it comes with the territory I guess.

*I had problems crop up with the built-in disk again and so I revised the logging code slightly and it seems to be reliable again. We'll see. It's incredibly frustrating to waste lots of time capturing data only to find out you captured exactly bupkis.

Maiden Voyage, Take Two
Now maybe I can finally get back to collecting some usable data.

I have to because the maiden voyage is rescheduled for March 12!

Looking Up?
In summary, I'm not totally screwed anymore. Although I really wished I hadn't bricked my $60 GPS. And I still have a ton to get done.

I take it back. The LS20031 is alive and well! The GPS module's backup battery was complete drained (I probably shorted it out while resoldering the shield). After recharging for awhile, it is back to normal and getting a good, multi-satellite, 3d fix. WHEW!