So far i get a hall sensor and a raspberry pi 3. The hall sensor has 3 wires. I connected 2 of them for power it up (12v) and on the signal one i put a voltage divider to get around 3V on the output. I assembled it on a hand drill machine for simulate rotation and get signal.

Searching on the web i found the pigpio library and also a demo code which i tried but is not work as expected so i have few questions related to this:

The code i used :

#!/usr/bin/env python

# read_RPM.py
# 2016-01-20
# Public Domain

import time
import pigpio # http://abyz.me.uk/rpi/pigpio/python.html

class reader:
   A class to read speedometer pulses and calculate the RPM.
   def __init__(self, pi, gpio, pulses_per_rev=1.0, weighting=0.0, min_RPM=5.0):
      Instantiate with the Pi and gpio of the RPM signal
      to monitor.

      Optionally the number of pulses for a complete revolution
      may be specified.  It defaults to 1.

      Optionally a weighting may be specified.  This is a number
      between 0 and 1 and indicates how much the old reading
      affects the new reading.  It defaults to 0 which means
      the old reading has no effect.  This may be used to
      smooth the data.

      Optionally the minimum RPM may be specified.  This is a
      number between 1 and 1000.  It defaults to 5.  An RPM
      less than the minimum RPM returns 0.0.
      self.pi = pi
      self.gpio = gpio
      self.pulses_per_rev = pulses_per_rev

      if min_RPM > 1000.0:
         min_RPM = 1000.0
      elif min_RPM < 1.0:
         min_RPM = 1.0

      self.min_RPM = min_RPM

      self._watchdog = 200 # Milliseconds.

      if weighting < 0.0:
         weighting = 0.0
      elif weighting > 0.99:
         weighting = 0.99

      self._new = 1.0 - weighting # Weighting for new reading.
      self._old = weighting       # Weighting for old reading.

      self._high_tick = None
      self._period = None

      pi.set_mode(gpio, pigpio.INPUT)

      self._cb = pi.callback(gpio, pigpio.RISING_EDGE, self._cbf)
      pi.set_watchdog(gpio, self._watchdog)
   def _cbf(self, gpio, level, tick):

      if level == 1: # Rising edge.

         if self._high_tick is not None:
            t = pigpio.tickDiff(self._high_tick, tick)

            if self._period is not None:
               self._period = (self._old * self._period) + (self._new * t)
               self._period = t

         self._high_tick = tick

      elif level == 2: # Watchdog timeout.

         if self._period is not None:
            if self._period < 2000000000:
               self._period += (self._watchdog * 1000)

   def RPM(self):
      Returns the RPM.
      RPM = 0.0
      if self._period is not None:
         RPM = 60000000.0 / (self._period * self.pulses_per_rev)
         if RPM < self.min_RPM:
            RPM = 0.0

      return RPM

   def cancel(self):
      Cancels the reader and releases resources.
      self.pi.set_watchdog(self.gpio, 0) # cancel watchdog

if __name__ == "__main__":

   import time
   import pigpio
   import read_RPM

   RPM_GPIO =4
   RUN_TIME = 600.0
   SAMPLE_TIME = 2.0

   pi = pigpio.pi()

   p = read_RPM.reader(pi, RPM_GPIO)

   start = time.time()

   while (time.time() - start) < RUN_TIME:

      RPM = p.RPM()




And now questions: Q1: When i run this code i get number of rpms which i think is very close to reality. The number increase if i press harder on drill or decrease when i decrease teh speed, but if i stop the drill i still get values of rpm's which are decreasing to 0 in few seconds. Why i don t get 0 when i stop the drill?

Q2: "Optionally the number of pulses for a complete revolution may be specified. It defaults to 1." - where is that in code? I wasn t able to find it and change it because in my case should be 2 instead 1

Q3: Also i was not able to understand the weighting part and also where to change it

Thank you in advance



I don't remember but the code may well use a rolling average to calculate the RPM. This helps smooth the data.


The code as given is instantiated with

   p = read_RPM.reader(pi, RPM_GPIO)

The class initialiser is defined with

   def __init__(self, pi, gpio, pulses_per_rev=1.0, weighting=0.0, min_RPM=5.0):

In Python this means

  • if you don't specify pulses_per_rev it defaults to 1.0
  • if you don't specify weighting it defaults to 0.0
  • if you don't specify min_RPM it defaults to 5.0


Instantiate with

   p = read_RPM.reader(pi, RPM_GPIO, pulses_per_rev=2.0)


The weighting says how much to consider the old RPM when a new RPM is available. The default 0.0 says to ignore the old reading. Try using values between 0.0. and 1.0 to see the smoothing effect.

Instantiate with

   p = read_RPM.reader(pi, RPM_GPIO, pulses_per_rev=2.0, weighting=0.5)


   p = read_RPM.reader(pi, RPM_GPIO, weighting=0.5)
| improve this answer | |
  • Thank you very very much for your answers. I really appreciate this. Btw - is that possible to read simultaneous 2 rpms? From 2 different pins? I guess i will use same lib and double variables that read rpm;s – user3036295 Feb 22 '17 at 19:50
  • @user3036295 You can use multiple instances of the class at the same time, e.g. for the first p1 = read_RPM.reader(pi, RPM_GPIO_1, pulses_per_rev=2.0), for the second p2 = read_RPM.reader(pi, RPM_GPIO_2, pulses_per_rev=3.0, weighting=0.1) etc. The limit will be the number of pulses per second which can be handled by Python, about 9000 for early Pis, 30000 for a Pi2, and 60000 for a Pi3. – joan Feb 22 '17 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.