Our robot has the camera, two Hall-Effect (GTS) sensors, the gyro, and (maybe) the accelerometer. It is driven by two small CIM motors. I have not gotten the accelerometer to work, and I desperately need to know the speed of the robot (accurately if possible).
Don’t assume that the default routine runs at any speed. It can vary from 26.2ms at the minimum up to nearly half a second (before you trigger the Blinking Red Light of Death). Instead, use one of the four available PIC timer modules. Look around for information on how to use them to tell time…
Knowing speed is actually harder than any one has made it out to be.
Shaft encoders are limited by the slip of the wheels. (They tell you how fast you SHOULD be going, not how fast you are going)
Accelerometers are limited by the huge amounts of noise they generate. If you want a cheap accelerometer… Analog devices makes some 5v ones that will plug right into an analog input on the RC. ADI iMems Sensor
Keep in mind that an accelerometer isn’t at all useful if you hit something. Additionally you have to integrate them to get velocity.
What you really need is an external reference. Something like using the camera on an orthogonal plane to your plane of motion to compute differences in the images and compute distance based on the shift.
In general this is a very nontrivial problem and is something I’m working on as a Master’s Thesis in Computer Engineering.
That doesn’t mean you can’t fudge it a little bit.
We did this last year and they worked great. Unfortunately at the Championship we had to remove one because of a weight problem. We used 4 inch skyway solid wheels and an IR quadrature encoder. The only problem I ever saw with them was wheelies (which we did a lot of), but if you just want a top speed they’d be great.
To get a very accurate reading of speed from encoders requires interrupts, as you’re very likely to be recieving more than one click per 26.
You could count the number of clicks per a known time period, or time period per click. In both cases, you need to have an interrupt fire when the encoder sends a signal. Kevin Watson’s interrupts package at kevin.org gives an amazing example of how to do this.
Once you know clicks/time or time/click, you can make a ratio of distance/click (d = 2 pi * wheel_radius / clicks_per_rotation) and compute it.
If you want to do clicks/time, the simplest way is have an interrupt increment a counter for each side, and then use the default loop for timing. The default loop runs approximately every 26.2 ms, so the speed for each side would be counter/.026 in clicks/second. (You probably want to use milliseconds to avoid decimals.) However, that 26.2 milliseconds is not always accurate, so you may instead want to use a timer that is guaranteed to run at a certain rate. See Kevin Watson’s interrupts example for how to use timers. Using a timer, you can instead take readings over some arbitrary time period, say, 25ms, and be almost guaranteed of the 25ms.
This year, we chose to do it a bit differently, we only had about 4 clicks per 26.2ms loop, giving us an awful precision. We considered computing every 2-4 loops, but instead settled on measuring the time between clicks. To do this, set up a timer considerably faster than your encoder will send values. (We chose .5ms or 1ms, I believe) and incremement a “clock” for each encoder every time the timer fires. Then, when the encoder sends a value, save that time to an array. 1/that time is the clicks/time, which again derives to the velocity.
However, this method has some problems. Firstly, if you don’t get a reading for a long time, you’re stuck with your old ones. To avoid this, simply assume that you’re going at least as slow as 1/clock if the clock is considerably bigger than the past few readings. Also, this method can give somewhat inaccurate, noisy readings. We found it necessary to average a few readings, and discard ones that are very far off from the last one. In the end, it all worked out and we ended up with a solid PID controller functioning off of this velocity reading. (However, this controller was not set up to go backwards. To drive backwards, we just switched the sides of the sensors and outputs.