Reputation: 69
I am trying to get a reasonable RPM for a motor. I have a photo-interrupter that sends 0 or 1 if it detects a slit that passes by. My code is as following, what I simply need is to time 0-60 seconds, and add the number of times 1 was detected and then divide it by 60, thus RPM.
I don't want to complicate my code, also keep in mind this is running on the Raspberry Pi with many other scripts and webservers running behind it. So not a bad code like "sleep" that would hog down the entire cpu.
I'm not looking for a crazy accurate measurement, just a reasonable idea of how fast the motor is spinning. Also does the slit size make a difference?
import RPi.GPIO as GPIO
import time
signal = 21
from time import sleep # this lets us have a time delay (see line 15)
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(signal, GPIO.IN) # set GPIO21 as input (signal)
GPIO.add_event_detect(signal,GPIO.BOTH)
try:
while True: # this will carry on until you hit CTRL+C
if GPIO.event_detected(signal): # if port 21 == 1
print "Port 21 is 1/HIGH/True - LED ON"
slit=slit+1 # Counts every time slit passes
else:
print "Port 21 is 0/LOW/False - LED OFF"
rpm = slit/60 # Calculates the RPM
sleep(0.0001) # wait 0.0001 seconds
finally: # this block will run no matter how the try block exits
GPIO.cleanup() # clean up after yourself
Upvotes: 0
Views: 1766
Reputation: 6891
With the reservation that I have never programmed an RPi using Python, this is how I would try to tackle this task:
import RPi.GPIO as GPIO
import threading
signal = 21
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(signal, GPIO.IN) # set GPIO21 as input (signal)
slit = 0
rpm = 0
def increment():
global slit
print("Port 21 is 1/HIGH/True - LED ON")
slit += 1
def count_complete():
global slit
global rpm
rpm = slit/60
print ("RPM = {}".format(rpm))
# reset and restart timer
slit = 0
t = threading.Timer(60, count_complete)
# Bounce will prevent double detection of the same rising edge (for 1 ms)
GPIO.add_event_detect(signal, GPIO.RISING, callback=increment, bounce=1)
t = threading.Timer(60, count_complete)
try:
while True: # this will carry on until you hit CTRL+C
pass # Do nothing but wait for callbacks and timer
finally: # this block will run no matter how the try block exits
t.cancel() # stop the timer
GPIO.cleanup() # clean up after yourself
As can be seen, I have added a callback function that will be called as soon as a rising edge is detected on the input. Here the clit counter is incremented. The bounce parameter is a protection that will stop the program from counting the same slit double.
Setting at 1 ms means that the RPM needs to be (well) below 1,000 or some slits will be missed. It is possible to experiment by removing this. I don't know if it is possible to give a fractional bounce time. That may be another option.
The main program then, stats a timer, that lets the increment run for 1 minute, after which the RPM is calculated and the system reset and a new count is initiated. (There is a risk of a race condition here, where a slit interrupt may happen while doing the calculation. This could be missed in these cases.)
Then in the main loop, nothing happens, except for the program waiting for interrupts (slit, timer or ctrl-c). This is a busy wait, since it will continuously run the pass
statement, doing nothing. Maybe there is a way to improve performance and make the program completely event driven, freeing up the CPU in the mean time, but that is a bigger task than I am attempting here.
Upvotes: 1