## Speed sensor calculation using Python

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Speed sensor calculation using Python

There are 2 methods for calculating speed using Python.

The first method is using "pre-defined interval".
The second method is using "calculated interval".

Before we dive straight into the code let me show you the setup of this project. What we need are RaspberryPi, hall effect sensor or reed switch and small magnet. You can use either one of the sensor and the code would be pretty much the same.
The hall effect sensor that I'm using is of Unipolar type. Depending on how you setup the magnet on the spinning mechanism, it will decide which type of hall sensor is suitable for you. Unipolar sensor can only get triggered on one side of the sensor. Bipolar sensor has the ability to detect magnet in both directions.

Reed sensor is a much simpler device to use for this project . I will show you how to use both sensors.
As this project is just a prototype for the wheel of our motorcycle/car, I'm using a cpu fan as a replacement for the real wheel.
The magnet is mounted on the flat surface of the fan.

Hall effect sensor has 3 pins or legs. There are VCC, Ground and Output.
Connect the VCC to 3.3V . (correction! I wrote 5V earlier)
Ground as usual.
And output to any GPIO that you wish. If everything is connected, you are good to go.

CALCULATED INTERVAL METHOD

(CODE)

Code: Select all

#!/usr/bin/python3
import RPi.GPIO as GPIO
from time import sleep
import time, math

dist_meas = 0.00
km_per_hour = 0
rpm = 0
elapse = 0
sensor = 12
pulse = 0
start_timer = time.time()

def init_GPIO():					# initialize GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(sensor,GPIO.IN,GPIO.PUD_UP)

def calculate_elapse(channel):				# callback function
global pulse, start_timer, elapse
pulse+=1								# increase pulse by 1 whenever interrupt occurred
elapse = time.time() - start_timer		# elapse for every 1 complete rotation made!
start_timer = time.time()				# let current time equals to start_timer

def calculate_speed(r_cm):
global pulse,elapse,rpm,dist_km,dist_meas,km_per_sec,km_per_hour
if elapse !=0:							# to avoid DivisionByZero error
rpm = 1/elapse * 60
circ_cm = (2*math.pi)*r_cm			# calculate wheel circumference in CM
dist_km = circ_cm/100000 			# convert cm to km
km_per_sec = dist_km / elapse		# calculate KM/sec
km_per_hour = km_per_sec * 3600		# calculate KM/h
dist_meas = (dist_km*pulse)*1000	# measure distance traverse in meter
return km_per_hour

def init_interrupt():
GPIO.add_event_detect(sensor, GPIO.FALLING, callback = calculate_elapse, bouncetime = 20)

if __name__ == '__main__':
init_GPIO()
init_interrupt()
while True:
calculate_speed(20)	# call this function with wheel radius as parameter
print('rpm:{0:.0f}-RPM kmh:{1:.0f}-KMH dist_meas:{2:.2f}m pulse:{3}'.format(rpm,km_per_hour,dist_meas,pulse))
sleep(0.1)
Using calculated interval method is better and more precise than pre-defined interval.
Here, we make use of the time.time() module in Python to precisely measure time duration of each interrupt interval.
We are using add_event_detect() to take advantage of the GPIO pin interrupt event handler.
Here we use one callback function called "calculate_elapse(channel)". This function will get called anytime interrupt event happens.

TRY to grab this concept in order to understand this code.

We are using ONE magnet mounted on one of the fan blade and ONE hall effect sensor
mounted on a static surface on our fan chassis.

Therefore, we could come up with an assumption that 1 complete rotation will be made whenever 1 interrupt event occurs.

From that assumption, we could determine the time duration of 1 complete rotation in our callback function.

So, lets take a look at the callback function in the code. It is named "calculate_elapse(channel)". In that function, we have
3 main global variables. Global variables are made so that their values can be used outside that local function which
in our case, our local variable is the callback function named "calculate_elapse(channel)". The globals are:

- pulse
- start_timer
- elapse

1) pulse : a counter variable used to count the number of interrupts. it can also be used to calculate total distance travelled
by the wheel.
2) start_timer : a time variable that stores the initial timestamp before an interrupt occurs and stores the current timestamp
after the interrupt has occurred!
3) elapse : time duration of 1 complete rotation by subtracting the timestamp during interrupt instance with start_timer which holds
the initial timestamp before that interrupt occurred.

After we have calculated the elapse, we immediately set our new start_timer with the current timestamp so that it can be used to
calculate our next elapse value if new interrupt occurs.

Now that we have our global elapse value, we can move on to next function which is "calculate_speed(r_cm)". this function will be called
in our main loop. This function takes in one parameter which is the radius of wheel in centimeter (you could use meter if you wish).
As the global elapse value is now accessible in this function, we can calculate the speed of the wheel using simple mathematical
formula.

First, we have to make sure that our elapse value is not Zero to avoid DivisionByZero error.

Round Per Minute (rpm) can be calculated using : rpm = 1/elapse * 60
where 1 is referring to 1 complete rotation and 60 is referring to 60 seconds.

circ_cm (wheel circumference) can be calculated using : 2 x pi x radius

dist_km (distance moved in km) can be calculated using : dist_km = circ_cm/100000

km_per_sec (speed in KM/s) calculated using: km_per_sec = dist_km / elapse

km_per_hour (speed in KM/h) calculated using: km_per_hour = km_per_sec * 3600

That's all for the CALCULATED INTERVAL METHOD! You can try it with your Raspberry Pi and get the result printed on the terminal. Good luck!
Last edited by Yazidapple on Tue Jun 14, 2016 9:32 am, edited 1 time in total.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

### Re: Speed sensor calculation using Python

Yazidapple wrote: Hall effect sensor has 3 pins or legs. There are VCC, Ground and Output.
Connect the VCC to 5V .
Ground as usual.
And output to any GPIO that you wish. If everything is connected, you are good to go.
This is ok only if the hall has a OC output. If it's a RC output you can damage your pi powering it with 5V
Here, we make use of the time.time() module in Python to precisely measure time duration of each interrupt interval.
probably if you want to "precisely measure time duration of each interrupt interval" you should use pigpio.
Pigpio timestamps interrupts when they occurr, in your code you use the (not so) precise python time.time() when the callback is executed.

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

Massi wrote:
Yazidapple wrote: Hall effect sensor has 3 pins or legs. There are VCC, Ground and Output.
Connect the VCC to 5V .
Ground as usual.
And output to any GPIO that you wish. If everything is connected, you are good to go.
This is ok only if the hall has a OC output. If it's a RC output you can damage your pi powering it with 5V
Here, we make use of the time.time() module in Python to precisely measure time duration of each interrupt interval.
probably if you want to "precisely measure time duration of each interrupt interval" you should use pigpio.
Pigpio timestamps interrupts when they occurr, in your code you use the (not so) precise python time.time() when the callback is executed.
thanks for the feedback bro. i'll try to improve this code and the setup! still learning anyway

joan
Posts: 15787
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

### Re: Speed sensor calculation using Python

http://abyz.co.uk/rpi/pigpio/examples.h ... ead_RPM_py shows a method using pigpio.

You might be interested in viewtopic.php?f=37&t=90243

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

joan wrote:http://abyz.co.uk/rpi/pigpio/examples.h ... ead_RPM_py shows a method using pigpio.

You might be interested in viewtopic.php?f=37&t=90243
Thanks so much! Thats really what I was looking for before I started working with this project.

am3u
Posts: 1
Joined: Tue Jul 26, 2016 6:22 pm

### Re: Speed sensor calculation using Python

but how much accurate is it

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

am3u wrote:but how much accurate is it
the accuracy is quite acceptable for small and simple project where you just wanna create a simple speedometer to calculate the speed of your bike / motobike. as mentioned our friend above, pigpio method is the most accurate implementation.

Onkarb68
Posts: 2
Joined: Mon Jan 23, 2017 1:23 pm

### Re: Speed sensor calculation using Python

Can anyone please tell which RPM sensor has got best accuracy for Raspberry pi3 model B?

ilman
Posts: 22
Joined: Wed Mar 08, 2017 5:08 am

### Re: Speed sensor calculation using Python

i've tried the code and i get a normal result overall. but reading can't back to 0 if rotation get stopped. how did it happen?

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

ilman wrote:i've tried the code and i get a normal result overall. but reading can't back to 0 if rotation get stopped. how did it happen?

actually its just because there's simply no logic for it in the code
i just found a speed sensor (rotary disc) for Arduino on this website.
https://brainy-bits.com/blogs/tutorials ... th-arduino

i think you can use that code as reference to modify the Python code.

Code: Select all

#include <OneWire.h>
unsigned int counter=0;

void docount()  // counts from the speed sensor
{
counter++;  // increase +1 the counter value
}

void timerIsr()
{
Timer1.detachInterrupt();  //stop the timer
Serial.print("Motor Speed: ");
int rotation = (counter / 20);  // divide by number of holes in Disc
Serial.print(rotation,DEC);
Serial.println(" Rotation per seconds");
counter=0;  //  reset counter to zero
Timer1.attachInterrupt( timerIsr );  //enable the timer
}

void setup()
{
Serial.begin(9600);

Timer1.initialize(1000000); // set timer for 1sec
attachInterrupt(0, docount, RISING);  // increase counter when speed sensor pin goes High
Timer1.attachInterrupt( timerIsr ); // enable the timer
}

void loop()
{
// just leave it empty if you have nothing else to do in your program
}

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

Onkarb68 wrote:Can anyone please tell which RPM sensor has got best accuracy for Raspberry pi3 model B?
are you asking for devices that could be used as speed sensor for Raspberry Pi?
any hall effect sensor or even a simple reed switch would suffice.

gurudattakr123
Posts: 2
Joined: Wed Mar 15, 2017 4:07 pm

### Re: Speed sensor calculation using Python

How can we change this code so that rpm and kmph must come back to 0 when wheel is not rotating?

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

gurudattakr123 wrote:How can we change this code so that rpm and kmph must come back to 0 when wheel is not rotating?

will work on that. as for now you could try to search for other alternatives. i would recommend you to use Arduino for speedometer project instead of Pi.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

### Re: Speed sensor calculation using Python

gurudattakr123 wrote:How can we change this code so that rpm and kmph must come back to 0 when wheel is not rotating?
well probably the program works based on callback, so if no signal is received, no calculation is done.
You can try playing with pigpio's watchdogs
http://abyz.co.uk/rpi/pigpio/python.html#set_watchdog
you should setup, in the callback, a watchdog on the GPIO so that if no callback is called within the timeout, the watchdog will call it and you'll return 0
Obviously in every callback you should cancel the previous watchdog and setup the new one.

RaMaSen
Posts: 3
Joined: Sun Jun 11, 2017 7:55 pm

### Re: Speed sensor calculation using Python

Hi,

The calculation methods I can comprehend,
however........ I want to use a ble sensor instead of an GPIO sensor for my project (I have a Major dislike towards Cords when it can be done Wireless).
I get data from my ble sensor but can't use it nor calculate the RPM from it.
The point for me is:
I have my sensor mounted Under my bike pedal, it sends data to my Rpi3 on my bikes handlebar.
My Rpi3 has a Blinkt! hat on it and I want it to respond to my pedling stance.
example:
20-45 Rpm on my pedal/crank -->> Blinkt! goes Red flashing
46-60 Rpm on my pedal/crank -->> Blinkt! goes Green flashing.
60-90 Rpm on my pedal/crank -->> Blinkt! goes Blue flashing

I wish to use it for a Constant stance in biking.

I Really don't know where y missing link is.

Life is not just "good' when you open your eyes, it's Really GOOD when you realize you have another day to LIVE!

Yazidapple
Posts: 24
Joined: Wed Mar 23, 2016 3:06 pm

### Re: Speed sensor calculation using Python

RaMaSen wrote:
Wed Sep 27, 2017 9:26 pm
Hi,

The calculation methods I can comprehend,
however........ I want to use a ble sensor instead of an GPIO sensor for my project (I have a Major dislike towards Cords when it can be done Wireless).
I get data from my ble sensor but can't use it nor calculate the RPM from it.
The point for me is:
I have my sensor mounted Under my bike pedal, it sends data to my Rpi3 on my bikes handlebar.
My Rpi3 has a Blinkt! hat on it and I want it to respond to my pedling stance.
example:
20-45 Rpm on my pedal/crank -->> Blinkt! goes Red flashing
46-60 Rpm on my pedal/crank -->> Blinkt! goes Green flashing.
60-90 Rpm on my pedal/crank -->> Blinkt! goes Blue flashing

I wish to use it for a Constant stance in biking.

I Really don't know where y missing link is.

what kind of BLE sensor are you using? is your Pi receiving any data from it? mind to elaborate further?

mohamedchihime
Posts: 1
Joined: Sun Apr 08, 2018 4:38 pm

### Re: Speed sensor calculation using Python

hi
can anyone help me if the pulse sensor give wave instead of measuring or there any device work in sending wave for nerve instead of vibration

c17hawke
Posts: 1
Joined: Tue May 22, 2018 9:56 am

### Thanks for this post

This post helped me to interface my raspberry pi 3 with LM393 Chip 1CH Optocoupler Motor Speed Measuring Counter Sensor Module.

RaMaSen
Posts: 3
Joined: Sun Jun 11, 2017 7:55 pm

### Re: Speed sensor calculation using Python

Yazidapple wrote:
Fri Feb 23, 2018 6:40 pm
RaMaSen wrote:
Wed Sep 27, 2017 9:26 pm
Hi,

The calculation methods I can comprehend,
however........ I want to use a ble sensor instead of an GPIO sensor for my project (I have a Major dislike towards Cords when it can be done Wireless).
I get data from my ble sensor but can't use it nor calculate the RPM from it.
The point for me is:
I have my sensor mounted Under my bike pedal, it sends data to my Rpi3 on my bikes handlebar.
My Rpi3 has a Blinkt! hat on it and I want it to respond to my pedling stance.
example:
20-45 Rpm on my pedal/crank -->> Blinkt! goes Red flashing
46-60 Rpm on my pedal/crank -->> Blinkt! goes Green flashing.
60-90 Rpm on my pedal/crank -->> Blinkt! goes Blue flashing

I wish to use it for a Constant stance in biking.

I Really don't know where y missing link is.

what kind of BLE sensor are you using? is your Pi receiving any data from it? mind to elaborate further?
Sure!
I intend to use a wahoo cadence sensor or a metawear RG developmentboard.
Both are still reluctant to hand over data
Life is not just "good' when you open your eyes, it's Really GOOD when you realize you have another day to LIVE!

RaMaSen
Posts: 3
Joined: Sun Jun 11, 2017 7:55 pm

### Re: Speed sensor calculation using Python

Hi there,

A year has pased since i posted here.

Wich ble service i use: Pybluez or bluepy.
I get connection wich the metawear sensor but can’t get a sufficient “zero-crossing point” to be registered as Pulse.
Wahoo sensor is a Drag...... can connect but can’t get data. Wahoo tech dept doesn’t want to help either “we have made Apps for that..... “ they say.
Win10 (PC) has option to read whathoo sensor and get data, so does the metawear portal.
Guess what....... raspberry pi 3B+ does only support win10 iot core (or Vice Versa) Not the services to run the win10 sensor portals!

So, for both wuthoo and metawear nothing open source has been developed to run on a rpi3B(+). Note: a metaHub based on a rpi3B has been developed and is to be used as portal to iot services (so i didn’t buy one Yet).

Foremost-> i get data on the Z axis wich i found strange at 1st due to data around +1 and -1 so i had a hard time to find a 0-crossing wich eventually were the +1/-1 crossings then i got lost in how to get these crossing to act as 0 crossings.

For Now it seems i’m phucked by wanting a ble sensor pedal mounted setup.
Go By Wire a friend said........
Nope! I want the freedom of bluetooth to ride Any bike i want and see my RPM with my Blinkt! on my RPI3B+ !!

Okay, enough ranting done......
Life is not just "good' when you open your eyes, it's Really GOOD when you realize you have another day to LIVE!

christianson
Posts: 9
Joined: Sat Jun 01, 2019 11:46 am

### Re: Speed sensor calculation using Python

I'm working on a similar project. But I want to use three magnets instead of one. How should I apply it

drgeoff
Posts: 12416
Joined: Wed Jan 25, 2012 6:39 pm

### Re: Speed sensor calculation using Python

christianson wrote:
Sat Aug 10, 2019 7:10 am
I'm working on a similar project. But I want to use three magnets instead of one. How should I apply it
Why 3 magnets?

If all 3 magnets are activating one sensor then the speed as calculated above will be 3 times actual. Just divide by 3.

If that is not the case you need to explain in much more detail.
Quis custodiet ipsos custodes?

AMGHOME
Posts: 6
Joined: Tue Oct 08, 2019 9:54 am

### Re: Speed sensor calculation using Python

Thank you for posting this code. I bought a maplin wind speed sensor from the net E27AF. It has a reed switch in it. After hooking it up in the way you mentioned, I ran your code - excellent.
The maplin has 2 magnets. I needed to know gust speed and average speed. There are posts above about what happens when the rotating device stops - showing the last non-zero reading. People asked about other units. Also the code needed some rationalisation for my purposes

All fixed in the version below. Someone else will have to work out multiple sensors.

I am still wondering about calibration. It seems to be reading a bit low. I've done a later version of the code below with a calibration routine if anyone wants it.

Code: Select all

#!/usr/bin/python3

#https://lb.raspberrypi.org/forums/viewtopic.php?t=151465

import RPi.GPIO as GPIO
from datetime import *
from time import sleep
import time, math

#process params
dist_meas = 0.00
olddist_meas=0.00 #last loop
km_per_hour = 0
mph=0
knots=0
rpm = 0
elapse = 0
pulse = 0
gust=0#last gust
avg=0#last average

sleeptime=.1#secs between reporting loop
gustint=3#secs to calc gust (>sleeptime)
avgint=45#secs to trigger average calc (>gustint)
secsnoread=6#number of seconds rotor is stationary before a 'no read' is declared and set result to zero - depends on inertia of your rotor in light >no wind
errortime=90#number of seconds of no activity before error/stationary warning is shown - set high after debugging
loopcount=0#a 'nothing is happening' counter
r_cm=7.2 #cm wheel radius as parameter (assumed centre of cups)
sensor = 22#BCM
magnets=2#how many magnets in your rotor? (code assumes one sensor though)

#startup numbers
circ_cm = 2*math.pi*r_cm	    # calculate wheel circumference in CM (1 rotation)
dist_km = circ_cm/100000/magnets	    # convert cm to km (rotation/magnets)
start_timer = time.time()           # for interrupt function
gust_timer = time.time() #start of this gust timing
gustm_start=dist_meas #start of this gust distance
avg_timer = time.time() #start of this average timing
avgm_start=dist_meas #start of average distance

def init_GPIO():			    # initialize GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(sensor,GPIO.IN,GPIO.PUD_UP)

def calculate_elapse(channel):	    # callback function
global pulse, start_timer, elapse
pulse+=1			    # increase pulse by 1 whenever interrupt occurred
elapse = time.time() - start_timer	    # elapsed time for a half rotation causing a pulse (edit for maplin sensor 2 magnets)
start_timer = time.time()		    # let current time equals to start_timer

def calculate_speed():
global rpm,olddist_meas,dist_meas,km_per_hour
try:
rpm = 1/elapse * 60/magnets              # 2 interrupts per rotation made
km_per_hour= dist_km / elapse * 3600	    # calculate KM/hour
dist_meas = dist_km*pulse*1000    # measure distance traverse in meter
if dist_meas==olddist_meas:
km_per_hour=0
rpm=0
return km_per_hour
except ZeroDivisionError:
pass

def calcgust():
global gust_timer,gustm_start,avg_timer,avgm_start,gust,avg

gustime = time.time() - gust_timer	    # how long since start of gust check?
if gustime >= gustint: #then calc average speed over gust time
gustkm=(dist_meas - gustm_start)/1000#how far since start of gust check
thisgust=gustkm/gustime*3600
#print('gust',gustime,gustkm,thisgust,gust)
if thisgust>gust:
gust=thisgust
gust_timer = time.time()#reset
gustm_start=dist_meas

avgtime = time.time() - avg_timer	    # how long since start of avg check?
if avgtime >= avgint: #then calc average speed over avg time
avgkm=(dist_meas - avgm_start)/1000#how far since start of avgcheck
thisavg=avgkm/avgtime*3600
#print('avg',avgtime,avgint, avgkm,thisavg)
avg=thisavg
avg_timer = time.time()#reset
avgm_start=dist_meas
gust_timer = time.time()
gustm_start=dist_meas
if avg!=0:
report('average')
gust=0 #reset max gust over average duration as well
avg=0 #and reset avg in case of calm

def report(mode):
if mode=='realtime': #comment this mode if you want a quieter report, or use
mph=km_per_hour/1.609344
knots=km_per_hour/1.852
#print(datetime.now().ctime(),'{0:.0f} RPM, {1:.1f} Km/h, {2:.1f} MPH, {3:.1f} knots'.format(rpm,km_per_hour,mph,knots))
#print(datetime.now().ctime(),'rpm:{0:.0f}-RPM kmh:{1:.1f}-KMH dist_meas:{2:.2f}m pulse:{3} elapse:{4}'.format(rpm,km_per_hour,dist_meas,pulse,elapse))
elif mode=='average':
#print(datetime.now().ctime(),'{0:.1f} Gust, {1:.1f} Average (both Km/h)'.format(gust,avg))
print(datetime.now().ctime(),'{0:.1f} Gust, {1:.1f} Average (both MPH)'.format(gust/1.609344,avg/1.609344))
#print(datetime.now().ctime(),'{0:.1f} Gust, {1:.1f} Average (both Knots)'.format(gust/1.852,avg/1.852))
elif mode=='error':
print(datetime.now().ctime(),'dead calm or connection fault')#report rotor still stationary
else:

def init_interrupt():
GPIO.add_event_detect(sensor, GPIO.FALLING, callback = calculate_elapse, bouncetime = 20)

if __name__ == '__main__':
init_GPIO()
init_interrupt()
while True:
olddist_meas=dist_meas
calculate_speed()
calcgust()
if olddist_meas!=dist_meas:
loopcount=0
report('realtime')
else:
loopcount+=1
if loopcount==secsnoread/sleeptime:#its stopped, force show a zero as it might be 'between magnets' and show last value
report('realtime')
if loopcount==20/sleeptime:#after each 60 secs,
report('error')
sleep(sleeptime)

rishav_0602
Posts: 2
Joined: Tue Oct 13, 2020 5:19 pm

### Re: Speed sensor calculation using Python

Hello, I just have one doubt in your program (I am a beginner). What is the use of the 'channel' parameter you used in the time elapsed function ????

AMGHOME
Posts: 6
Joined: Tue Oct 08, 2019 9:54 am

### Re: Speed sensor calculation using Python

Hi looking at the code, I don’t think it does anything. It’s been a while. There seems to be a mismatch between the calling function and the function itself. Also channel isn’t declared or initialised anywhere. So I think it’s not needed. Hope that helps? Are you trying to run the code?