Background
I am trying to get a particle sensor to work with the Raspberry Pi (model B+
). I am using the Shinyei PPD42N6
(datasheet here).
The sensor outputs a digital signal with pulses ranging from 10-90ms. According to the datasheet, the concentration of particles detected (pcs/283ml) is a function of the low pulse occupancy time (i.e., the total time that the input waveform is low over some specified sample interval). Sample code for the Arduino can be found at this Wiki page.
I am trying to re-write the sample code on the Raspberry Pi so that it has the same functional behavior. My first concern was that the Raspberry Pi would not be reliable due to the OS interrupts that would likely occur during the sampling period. @joan notified me that his PiGPIO
library is able to count pulses to within 10-20us. However, I am having difficulty getting his library to work in the context of this problem. Here is the code that I have written:
import time
import pigpio
# Setup the Shinyei input
RX = 24
GPIO.setup(RX, GPIO.INPUT)
duration = 0
starttime = 0
sampletime_ms = 30000 # sample time (ms)
lowpulseoccupancy = 0
ratio = 0
concentration = 0
prev_tick = None
def cb_high(g, l, t):
global prev_tick, duration, lowpulseoccupancy
if prev_tick is not None:
duration = pigpio.tickDiff(prev_tick, t)
lowpulseoccupancy += duration
def cb_low(g, l, t):
global prev_tick
prev_tick = t
pi = pigpio.pi() # Connect to local Pi.
cb1 = pi.callback(RX, pigpio.FALLING_EDGE, cb_low)
cb2 = pi.callback(RX, pigpio.RISING_EDGE, cb_high)
try:
while True:
if ((time.time() - starttime) > (sampletime_ms / 1000)):
ratio = lowpulseoccupancy/((sampletime_ms)*10.0)
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62
print ("Concentration = {0} pcs/0.01cf".format(concentration))
lowpulseoccupancy = 0
starttime = time.time()
except KeyboardInterrupt:
cb1.cancel()
cb2.cancel()
pi.stop() # Disconnect from local Pi.
Each time a transition occurs from a high state to a low state the prev_tick variable is set. When a transition from low to high occurs, the difference between the current tick t and the previous tick prev_tick is calculated (e.g., the total duration in which the signal was low). This duration is added to the lowpulseoccupancy time, which is used in the main loop of the main thread.
This code leads to extremely odd behavior. I get numbers that are out of this world, and very inconsistent.
Does anyone see any obvious issues with this code? If not, do you have any suggestions as to how this problem could best be solved?