Go Down

Topic: Most accurate way to measure speed of a car (Read 8002 times) previous topic - next topic


At the moment I'm building a massive controller for my car (BMW M3 E36). It's eventually going to control and read lots of devices on my car and operate via Bluetooth with my mobile phone.

I've started with the basics - a race timer.  This can read my speed and RPM and do some logging, timing and distance calcualtions.

I've got this working pretty well, I experimented with 2 different ways of measuring the speed, using pulses detected from my rear diff at a rate of 9 pulses per revolution.

I measured the timings, a pulse width of approx. 20ms was around 25mph. I then coded my idea and fine-tuned the readout with a GPS speedo.  Just out of interest I also coded an alternate idea I had which measured the revolutions and time and calculated the speed based on the circumference of my tyre. I'll quickly describe each method below.

Method 1 - Reading the pulse width

Set an interrupt for the speed sensor pin.
When this interrupt fires measure the pulse width by comparing the micros() from the last interrupt with the present micros()
If the pulse width is within sensible limits store this value in an array and move the pointer along 1
When the pointer reaches the end, jump back to the start

When you come to read the speed, I took the mode of the array which contained the last n samples.  (I can increase the size of the array, n, to give me more error tolerance but less instant readings)
I then do the following to turn the pulse width into a speed in mph.   speed = <a fixed number that I worked out> / pulseWidth;

Method 2 - Reading the revolutions per amount of time

Set an interrupt for the speed sensor pin.
When the interrupt fires add 1 to the revolutions variable.

When you read the speed you look at the time since the last reading and the number of revolutions counted, then reset the time and revolutions ready for the next reading.
Speed in mph = revolutions x circumference of tyre / time between readings

Now what I found was that using method 2, I only got very discrete speed readings.  Let's say you sample the speed every 100ms, this means that at a certain speed you will either get 10 or 11 pulses every 100ms.  However the difference in mph between 10revs/100ms  and 11revs/100ms is quite a lot.  So my speedo would go up in 5mph steps for example.

So I guess I should stick with method 1, which I have only made accurate but comparing the output to a GPS speedo and making a number up that makes the calculation work. However I'm still worried that this method may be inaccurate. Because it comes down to measuring the pulse width in micro seconds, which at high speed is a very small % change in pulse width for a large change in speed. To make this worse I'm going to change from using my diff sensor, to using an ABS sensor, which will change from 9 pulses per revolution, to either 20 or 40 (I can't remember which).

The end goal is, to as accurately as possible measure both speed and distance.  I then want to be able to time how long it takes to travel exactly ΒΌ mile to the nearest 100th second. That's about 200 revolutions of my wheel, so potentially 18,000 samples or even more when I switch to the ABS sensor.

So what do you guys reckon the best way to do this is?


Does your car have an OBD port ? ..   http://en.wikipedia.org/wiki/On-board_diagnostics  ,


If I understood you correctly, your two methods of measuring speed are to measure the length of the pulse from the diff sensor, or count the number of pulses in a period.

Since one of the things you want to know is distance, I think it is important that you measure this directly (by counting pulses) rather than trying to measure speed and then integrate it to show cumulative distance. I don't just mean count the pulses and work out your speed from that - I mean that the total number of pulses IS your distance traveled. (You can scale this to whatever units you want to display the distance in when you come to display it, but keep the raw pulse count as your underlying storage.)

You haven't said what you want the speed for, but if it's for driving a display then I suggest you produce a rolling average. Although the circular buffer you're using does this already, you could do it with less code and using less RAM if you just implement an exponential decay, for example newAverage = ((90 * oldAverage) + (10 * newSample)) / 100. The averaginbg / smoothing approach could be used for any method of measuring the speed. Typically, measuring the interval between pulses works better at lower speeds and counting the number of pulses in an interval works better at higher speeds. You will have to decide which speed range you want to work best, or perhaps change the algorithm depending on the current speed if you feel it's important enough.

Note that all of these methods will be sensitive to changes in tyre pressure and tread depth (just like any other speedo based on wheel rotations) so when you are calibrating it be aware that the calibration will be affected by subsequent changes. You probably want to calibrate it to minimise the error for a part-worn tyre at typical pressure.

It's not hard to add a GPS sensor to an Arduino and this would give you an alternative methods of measuring speed and distance. Since the GPS position fix gives relatively poor resolution, this would work better at higher speeds. But being able to track your absolute position over time might be of interest to you, especially if you also add acceleration sensing (also easy to do).

If you want the distance measurement to be preserved after the Arduino is switched off then you will need to save it in persistent storage. The Arduino has a small EEPROM built in, which can be used easily for this sort of thing, but note that it only has a limited number of write operations so you want to avoid writing the mileage frequently. One option is to add an external circuit to let the Arduino work out when it is being powered off, and use that as a trigger to save the current reading. But perhaps you don't need that sort of thing.


Thanks for your detailed reply, it's confirmed a lot of what I was thinking.

I've actually got a separate counter for distance anyway, as you said this make much more sense.  Every pulse is exactly 1/9th of my tyre circumference. I started off with the pulse width speed measurement, then implemented the counter for distance and this is why I then went back to seed if the counting method could be used for speed as well.

I know what you mean about the rolling average, I've used this method before in sound sampling to get an "ambient sound level".  The only reason I went for the array is that I wanted mode, not average.  The main reasoning behind this was that I figured that the only errors in the data would really be if it some how missed a pulse, and say one of the values out of the last 10 would be double the rest.

When I was using a scope it did miss the odd pulse, but having tested the arduino it seems to be pretty reliable, and I might even just compare the last 2 pulse widths.

I guess if I was to build this to the nth degree I could include a GPS and even have an auto calibration that runs whenever a reliable GPS speed is captured and have the unit adjust itself. That would be pretty cool.

The main thing I'll be using this for though is displaying a heads-ups speed in mph, which doesn't need to be super accurate. Secondly when "race timer mode" is activated. It wait's untill you are stopped for 1 second, then when you start moving it starts timing.  It returns the 0-60mph time and the 1/4 mile time + speed accross the line. Then it stops the timing.  I'm also getting it to return the raw data via serial at this point.  Max 2000 samples, 1 per 10ms.

My next decision is what data to return,  speed or distance traveled.  Obviously one is a derivative of the other, but then that brings me back to which is more accurate,  speed based on pulse width, or distance based on pulse count.  I've not got this far yet and I'm sure once I have the raw data it should tell me.


If the 'race timing' you're referring to is drag race timing then it would probably work better to use an accelerometer to detect movement rather than speed determined from a wheel sensor. Using the wheel sensor you will have a significant and variable rollout before you get a valid speed reading.


Calculating speed using an accelerometer would only be accurate for a few moments off the line. The only practical way is to use GPS.

In a previous discussion someone mentioned that car manufacturers are required to configure their speedometers to never report slower-than-actual speed and that they have to be accurate to within ~10mph? I know on my car that it will report its speed ~30mph when actual speed is 20mph. YMMV (literally) if you try to use the car's speedometer.


Feb 26, 2013, 06:53 pm Last Edit: Feb 26, 2013, 06:57 pm by PeterH Reason: 1

Calculating speed using an accelerometer would only be accurate for a few moments off the line.

The main point of the accelerometer would be to detect the instant that movement started.

In a previous discussion someone mentioned that car manufacturers are required to configure their speedometers to never report slower-than-actual speed and that they have to be accurate to within ~10mph?

I can't quote the law requiring it, but I understand that type approval in the UK requires cars to provide drivers with a reliable way of telling when specific speeds are exceeded. This implies that the speedo is allowed to over-read (within limits) but not to under-read.


Accelerometers:  I see what your saying, but I've already got an accelerometer based racetime, and some software for my phone that uses a combination of GPS + Acceleration, but neither are consistent or accurate enough.  The problem is I'm dealing with high speed and 100ths of a second.  For example the accelerometers become less accurate accurate unless your accelerating in a straight line on level ground. And 10Hz GPS isn't fast enough on it's own to be accurate.

Speedos: Forget the standard speedos in a car, I'm not using this.  I'm using a 9 tooth hall sensor on the rear diff at the moment and I will be changing to use a 48 tooth hall sensor on the front wheel. the main reason for this is that the car is RWD and spins the back wheels very readily, so as long as I stay in a straight line the front will be more accurate. At the moment 9 teeth is enough for me to read low speeds, but 48 teeth would be better. 1 pulse = 219mm and at 1mph (if my maths is correct) that's 0.48seconds per pulse, but this time quickly decreases, 8mph is 1 pulse per 60ms.

So it is a little slow at the start, but this will drop to around 1/5th the time when I swap to the 48 tooth ABS sensor. Although that also might make reading the pulse width much more difficult 1mph = 91ms, 32mph = 2.8ms, 128mph = 710us and so on.


Accelerometers:  I see what your saying, but I've already got an accelerometer based racetime,

I'm not proposing that you use the accelerometer to calculate the speed - only to detect when the vehicle starts accelerating. It will be more consistent than waiting for the wheel position sensor to trigger one or more times.

It's possible to combine an accelerometer and GPS to provide a very accurate position and hence speed - I have a data logger that tracks the absolute position to fractions of a meter - but it requires rocket science to work out the mathematics and I'm not suggesting you try to replicate that on your Arduino.  


What about a tachometer or rotary encoder attached to the motor or a wheel?
My GitHub:


Reading just the post title, my first thought was drive by a cop going too fast. You'll be informed EXACTLY how fast you were going.  :)
The art of getting good answers lies in asking good questions.


I would not read the pulse width but the period between pulses, this will not be subject to much variation.

If you need a fast(ish) display update there is always a trade off between measuring period and pulses, one is good for slow speeds and the other for fast speeds. In the past I've used both and swapped algorithms at a certain speed.

Rob Gray aka the GRAYnomad www.robgray.com

Go Up