Using G1/2" Water flow meter with GrovePi


#1

I’m trying to connect a Water Flow Meter on my GrovePi to read it on the Raspberry Pi. This is the wiki of the G 1/2" Water Flow Meter. It has a rotating wheel that pulses a hall effect sensor. By reading the pulses generated in a given time, it’s easy to compute the actual water flow that runs to the meter. The meter has a given flow pulse that is different for different meters (the same meter exists in 1/8", 1/4", 3/4", 1" and 5/4" diameter, but the flow pulse is different for each meter). On the 1/2" meter, the flow pulse is 7.5. This means that on a frequency of 75 Hz, the water flow is 10 l/min. The water flow is defined by this formula:

Q = pulse_frequency * 60 / 7.5
. Since it's very hard to measury exactly 1 second, it's better to measure both the number of pulses during the measuring time. The formula then becomes:
Q = pulses_measured * 60 / measuring_time / 7.5
.

This for the theory. Now the practical thing: how to connect the meter to the GrovePi and writing the python-script.

The meter has 3 wires: black (GND), red (Vcc +5V) and yellow (signal output, low on pulse, high on no pulse). Since this is a digital meter, I try to connect it to one of the Digital Ports of the GrovePi (D5 in my case). The black wire goes to the GND (pin 4 of the D5-connector), the red to Vcc (pin 3 of the D5-connector) and the yellow to the either pin 2 of the D5-connector (normaly the white wire) or pin 1 of the D5-connector (normaly the yellow wire). To prevent the drifting of the voltage on the signal wire, a pull-up resistor of 10k is placed between the red and the yellow wire of the meter.

This is my python script:

# testflowmeter10.py
# Use Raspberry Pi and GrovePi to test input from Water Flow Meter
# Johan Vandewalle
# Version 0.10
# coding: latin-1
#!/usr/bin/python

# Import modules
import smbus
import time                             # Library to allow delay times
import datetime                         # Library to allow time and date recording
from array import array                 # Library to allow working with arrays
import os                               # Library to allow command line tasks
import unicodedata                      # Library to use unicode characters above value 127
import math                             # library with mathematical functions
import RPi.GPIO as GPIO                 # library with GPIO read- and write functions
import grovepi                          # library with the GrovePi functions
import struct

# for RPI version 1, use "bus = smbus.SMBus(0)"
rev = GPIO.RPI_REVISION

if rev == 2:
	bus = smbus.SMBus(1) 
else:
	bus = smbus.SMBus(0) 

# Define global variables

global WATER_FLOW_PIN
global LOGTIME
global PULSE_OUTPUT_FLOW_METER
global FLOW_SPEED
global VALUE
global FLOWTIME
global STARTTIME

# Set starting values variables

# This is the address of the Atmega328 on the GrovePi
address = 0x04

# Set starting values for global variables
WATER_FLOW_PIN = 5                                               FLOWTIME = 0.0
STARTTIME = 0.0
now = time.time()                                               # Set now to current time in seconds since Epoch
date = datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d_%H:%M:%S")
								# Set date to current time in YYYY-mm-dd_hh:mm:ss format
STARTTIME = now                                                 # Set WORKTIME at current time in seconds since Epoch
FLOWTIME = now
PULSE_OUTPUT_FLOW_METER = 7.5                                   # This sets the output frequency conversion rate (depending on the  Water Flow Meter characteristics)
FLOW_SPEED = 0.0                                                # Set FLOW_SPEED start value at 0.0
LOGTIME = ["2014-04-21_19:00:00","2014-04-21_19:00:00","2014-04-21_19:00:00","2014-04-21_19:00:00","2014-04-21_19:00:00","2014-04-21_19:00:00","2014-04-21_19:00:00"]
VALUE = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]                     # Set array VALUE[0 to 6] with 7 readings, start value at 0.0					

# Definition of functions

# Main function
def main():
	global COUNT
	initialise()                                            # Call function initialise() to initalize port setting
	while True:                                             # Start infinitive loop
		COUNT = 0                                       # Set start value at 0
		read_flow_meter()                               # Call function read_flow_meter
		time.sleep(5)                                   # Pause 5 secs

def initialise():                                               
	pinMode(WATER_FLOW_PIN,"INPUT")

def read_flow_meter():                                          # Function to read Water Flow Meter
	global LOGTIME
	global VALUE
	global COUNT
	now = time.time()                                       # Set now to current time in seconds since Epoch
	STARTTIME = now                                         # Set worktime at current time in seconds since Epoch
	FLOWTIME = now                                          # Set flowtime at currect time in seconds since Epoch
	VALUE[6] = 0.0                                          # Set start value at 0.0
	falling = 0                                             # Set start value at 0
	rising = 0                                              # Set start value at 0
	lus_teller = 0                                          # Set start value at 0
	last_value = 'low'                                      # Set start value at 'low'
	pulse_value = 0
	duration = 0.0
	print( 'Reading Water Flow Meter for 1 second. Please wait ...' )
	while duration < 1.0:
		try:
			pulse_value = digitalRead( WATER_FLOW_PIN )       # Read value from Water Flow Meter
			print( 'lus_teller = ' + str( lus_teller ) + ', pulse_value = ' + str( pulse_value ) )
#			if lus_teller == 0 and pulse_value == 1:
#				last_value = 'high'
			if pulse_value == 0:
                                if last_value == 'high':
                			falling = falling + 1                   # Add 1 to variable low_tick to count the number of changes from high to low (falling pulses)
                                last_value = 'low'
			if pulse_value == 1:
                                if last_value == 'low':
                			rising = rising + 1                     # Add 1 to variable high_tick to count the number of changes from low to high (rising pulses)
				last_value = 'high'
			print( 'falling pulses = ' + str( falling ) + ', rising pulses = ' + str( rising ) +  ', last_value = ' + last_value )
			now = time.time()                               # Set now to current time in seconds since Epoch
			print( 'now = ' + str( now ) )
			date = datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d_%H:%M:%S")
									# Set date to current time in YYYY-mm-dd_hh:mm:ss format
			print( 'date = ' + date )
			FLOWTIME = now                                  # Set FLOWTIME at currect time in seconds since Epoch
			duration = FLOWTIME - STARTTIME                 # Calculate duration of measuring in seconds (float)
			print( 'duration = ' + str( duration ) )
		except TypeError:
			print( "Unable to read the Water Flow meter value" )
		lus_teller = lus_teller + 1                     # Add 1 to lus_teller to count the number of loops
	LOGTIME[6] = date                                       # Set LOGTIME[6] at current time in YYYY-mm-dd_hh:mm:ss format
	VALUE[6] = round( ( ( ( 60.0 / duration ) * falling ) / PULSE_OUTPUT_FLOW_METER ), 2 )
								# Calculate flow speed in l/min, rounded at 2 decimals (60.0 seconds / duration (measuring time in seconds) * number of rising pulses
	print( 'last_value = ' + last_value )
	print( 'falling pulses = ' + str( falling ) )
	print( 'rising pulses = ' + str( rising ) )
	print( 'lus_teller = ' + str( lus_teller ) + ' (number of times through loop).' )
	print( 'now = ' + str( now ) + ' time in seconds from Epoch at last measuring. ' )
	print( 'date = ' + date + ' (stringvalue of time at last measuring).' )
	print( 'duration = ' + str( duration ) + ' (time elapsed between start en ending measuring).' )
	print( 'LOGTIME[6] = ' + LOGTIME[6] + ' (saved time).' )
	print( 'VALUE[6] = ' + str( VALUE[6] ) + ' (saved value in l/min rounded at 2 decimals).' )
	print( CODE[6] + " (" + DESCRIPTION[6] + "). Flow meter readings during 1 second. Number of falling pulses = " + str( falling ) + ". Flow speed = " + str( VALUE[6] ) + " l/min. Logtime: " + LOGTIME[6] )
	falling = 0                                             # Reset start value at 0
	rising = 0                                              # Reset start value at 0
	lus_teller = 0                                          # Reset start value at 0
	duration = 0.0                                          # Reset start value at 0.0

main()                                                          # Call function main

The output isn’t what it should be. If I connect the yellow wire to pin 1 of the D5-connector, the value read with digitalRead(5) is always 1 (it makes no difference wheather water is flowing or not).

If I connect the yellow wire to pin 2 of the D5-connector, the value read with digitalRead(5)is always 255 (it makes no difference wheather water is flowing or not).

What am I doing wrong: is it an error in the script or isn’t this meter suited for connecting to one of the Digital ports? If so, to which port can I connect it?


#2

Hi Johan,
Sorry for the problems. After having a look at the code for Arduino that Seeed has up on the Wiki it looks like the flow meter uses Interrupts.
What it does is that, it stops everything else on the MCU and counts the number of pulses for a second (it can be very fast, at 12L/min, it is 90Hz). The reason it stops everything else is because the reading count is coming in very fast and if the MCU is doing other operations then it can easily lose some pulses coming in.

With the GrovePi firmware running on the MCU and Python doing all the low level stuff like you have implemented, what I think the problem is that the Python code is not running fast enough to detect all the changes in the rise and fall of the pulses. I am sorry to say this but Python is not good enough for this low level stuff.

You can try one thing, write a Python program to just read digital signals without any delay and print them on the screen. If you are able to read all the change in the pulse then you might have a shot at implementing everything in Python.

Most probably you’ll have to modify the GrovePi firmware to put in something similar to Flow sensor sketch and make it send back values periodically to the Raspberry Pi. You can have a look here to see how to add custom sensors: http://www.dexterindustries.com/GrovePi/engineering/grovepi-protocol-adding-custom-sensors/ .

-Karan


#3

hello

how would you connect the flow meter to the grovepi+.

Also, i have tried a wire to wire connection to get the readings from the “grove_flow_read.py” program code, but only getting “error” .

Thanks & regards
Shantanu


#4

We have this now working with the latest firmware for the GrovePi. Just make sure that you are using firmware v1.2.5 on the GrovePi. Run this example https://github.com/DexterInd/GrovePi/blob/master/Software/Python/grove_firmware_version_check.py to find out your firmware version. If it is something else then just burn the firmware by running: avrdude -c gpio -p m328p -U flash:w:grove_pi_v1_2_5.cpp.hex from https://github.com/DexterInd/GrovePi/tree/master/Firmware/Source/v1.2/grove_pi_v1_2_5 folder. Check the firmware version again and then run the flow meter code by connecting it to port D2.

-Karan