Water Flow Sensor - Looking for Advice



  • TL;DR: Looking for help getting a water flow rate sensor working on my Gpy/Expansion Board 3.1, new to MicroPython and struggling. My desired output would be in L/min.

    What I've done so far:

    I have a Gpy with expansion board V3.1. I've successfully connected to LTE over hologram and wifi to PyBytes. I have a novice understanding of Arduino but MicroPython is new to me.

    Here is an Arduino example of what I am trying to do:

    // reading liquid flow rate using Seeeduino and Water Flow Sensor from Seeedstudio.com
    // Code adapted by Charles Gantt from PC Fan RPM code written by Crenn @thebestcasescenario.com
    // http:/themakersworkbench.com http://thebestcasescenario.com http://seeedstudio.com
    
    volatile int NbTopsFan; //measuring the rising edges of the signal
    int Calc;                               
    int hallsensor = 2;    //The pin location of the sensor
    
    void rpm ()     //This is the function that the interupt calls 
    { 
     NbTopsFan++;  //This function measures the rising and falling edge of the hall effect sensors signal
    
    
    } 
    // The setup() method runs once, when the sketch starts
    void setup() //
    { 
     pinMode(hallsensor, INPUT); //initializes digital pin 2 as an input
     Serial.begin(9600); //This is the setup function where the serial port is initialised,
    
    
     attachInterrupt(0, rpm, RISING); //and the interrupt is attached
    } 
    // the loop() method runs over and over again,
    // as long as the Arduino has power
    void loop ()    
    {
     NbTopsFan = 0;      //Set NbTops to 0 ready for calculations
     sei();            //Enables interrupts
     delay (1000);      //Wait 1 second
     cli();            //Disable interrupts
     Calc = (NbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate in L/hour 
    
    
     Serial.print (Calc, DEC); //Prints the number calculated above
     Serial.print (" L/hour\r\n"); //Prints "L/hour" and returns a  new line
    }
    

    I have the following sensor: https://www.digiten.shop/collections/counter/products/digiten-g1-2-water-flow-hall-sensor-switch-flow-meter-1-30l-min

    I currently have it plugged in to 3.3V and GND with Data going into P16.

    According to the spec sheet on the website:

    Frequency: F=7.5 * Q (L / Min) error: ± 2% current can not exceed 10mA, 450 output pulses/liters, F=Constant * units of flow (L / min) * time (seconds)
    Flow range:1-30L/min
    Maximum current:15 mA(DC 5V)
    Working voltage range:DC 5-24 V
    Load capacity:≤10 mA(DC 5V)
    Output Waveform:Square Wave,output pulse signal.
    Sensor:Hall effect

    I have tried several bits of code to try and read data off the sensor, but I am having trouble getting anything to work or be useable.

    This code looks great but my lack of understanding things still has kept me from being able to actually run it and print back any values.

    class RPM:
        
        def __init__(self, pin):
            self._pin = Pin(pin,mode=Pin.IN)
            self._intvl = 0
            self._pin.callback(Pin.IRQ_RISING,handler=self._callback,arg=self)
            self._timer = Timer.Chrono()
            self._timer.start()
    
        def _callback(self,obj):
            self._intvl = self._timer.read_ms()
            self._timer.reset()   
    
        def rpm(self):
            return 60000 / self._intvl 
    

    I was able to modify this tutorial: https://core-electronics.com.au/tutorials/pycom/hc-sr04-ultrasonic-sensor-with-pycom-tutorial.html to receive back some data but it only reads values at a very low speed and then stops reporting at higher 'speed'. I'm not sure if this is a limitation of the 3.3V or that I am headed down the wrong path with the code:

    import utime
    import pycom
    import machine
    from machine import Pin
    
    echo = Pin('P16', mode=Pin.IN, pull=Pin.PULL_DOWN)
    
    # Ultrasonic distance measurment
    def distance_measure():
    
        # wait for the rising edge of the echo then start timer
        while echo() == 0:
            pass
        start = utime.ticks_ms()
    
        # wait for end of echo pulse then stop timer
        while echo() == 1:
            pass
        finish = utime.ticks_ms()
    
        # pause for 20ms to prevent overlapping echos
        utime.sleep_ms(500)
    
        # calculate distance by using time difference between start and stop
        # speed of sound 340m/s or .034cm/us. Time * .034cm/us = Distance sound travelled there and back
        # divide by two for distance to object detected.
        distance = ((utime.ticks_diff(start, finish)) * 60)/7.5
    
        return distance
    
    while True:
        print(distance_measure())
    

    Returns:

    -1360.0
    -1528.0
    -1008.0
    -576.0
    -104.0
    -8.0
    -8.0
    -24.0
    -96.0
    

    I tried several versions of code reading DHT sensors with Time / Interrupts, but I had no success getting anything to report back from the flow sensor.

    If I read the pin as analog I can get a value of 4095 (3.3V) at rest and the higher the pressure on the sensor it goes to 0, however I get a mixture of 'false zeros' between readings.

    import machine
    import utime
    
    
    while True:
        adc = machine.ADC()             # create an ADC object
        apin = adc.channel(pin='P16', attn = machine.ADC.ATTN_11DB)   # create an analog pin on P16
        val = apin()                    # read an analog value
    
        print(val)
        utime.sleep_ms(50)
    
    

    Will return:

    335
    102
    0
    0
    0
    112
    0
    108
    245
    0
    

    If I read it using pulses_get I cam able to get occasional sets of data, but not consistently.

    # get the raw data from a DHT11/DHT22/AM2302 sensor
    from machine import Pin
    from pycom import pulses_get
    from time import sleep_ms
    
    pin = Pin("P16", mode=Pin.OPEN_DRAIN)
    pin(0)
    sleep_ms(20)
    pin(1)
    data = pulses_get(pin, 100)
    
    print(data)
    
    

    will return:

    [(0, 18010), (1, 4217), (0, 17331), (1, 4174), (0, 17341), (1, 4187), (0, 16935), (1, 3256), (0, 16397), (1, 3296), (0, 16500), (1, 3384), (0, 16175), (1, 2554), (0, 15749), (1, 2675), (0, 15883), (1, 2785), (0, 15641), (1, 2039), (0, 15258), (1, 2168), (0, 15405), (1, 2332), (0, 15202), (1, 1634), (0, 14856), (1, 1770), (0, 15051), (1, 1934), (0, 14836), (1, 1291), (0, 14534), (1, 1453), (0, 14738), (1, 1638), (0, 14551), (1, 1023), (0, 14274), (1, 1198), (0, 14467), (1, 1361), (0, 14305), (1, 764), (0, 14030), (1, 945), (0, 14212), (1, 1114), (0, 14069), (1, 541), (0, 13798), (1, 705), (0, 13980), (1, 883), (0, 13818), (1, 329), (0, 13577), (1, 489), (0, 13768), (1, 671), (0, 13623), (1, 128), (0, 13385), (1, 299), (0, 13566), (1, 476), (0, 26622), (1, 129), (0, 13418), (1, 303), (0, 6703), (1, 173), (0, 6043), (1, 51)]
    

    I am guessing the solution has to do with RMT or something but I'm out of ideas. If anyone is able to give me guidance in the right direction I would be greatly appreciated! - Thanks



  • Hello,

    As per the device's datasheet, the minimum working voltage for your sensor is 4.5 VDC, so I don't think it would work with it connected to 3.3 VDC. Probably why you're getting zeroes, because there's nothing on the output of the sensor. Also note that in the Arduino example, the sensor is connected to 5V, which the Arduino can produce - GPy can't.

    Also, you have to be careful when connecting the signal of the sensor into the GPy, because the sensor will output a square wave between 0 and Vss, where Vss is the supply voltage for the sensor (5V for example). The GPy's pins can only receive an input of up to 3.3 VDC, so you will need a voltage divider prior to your input pin to bring the voltage down. If not, you would most likely damage the pin.

    Regarding the example code with the RPM class, it looks like it should work...

    Best,

    Dan



  • With a little help from someone at work I was able to get the RPM code running and print values however I am only reading zeros.

    I tried running the referenced Arduino code on an UNO with the sensor to ensure it was working correctly and everything works perfectly.

    In the end I really just need to port over what is happening in the Arduino code over to MicroPython to run on the Gpy. I feel like that is what I should capture with the follow code, but that is not the case.

    import machine
    from time import sleep
    from machine import Timer
    from machine import Pin
    
    
    class RPM:
    
        def __init__(self, pin):
            self._pin = Pin(pin,mode=Pin.IN)
            self._intvl = 0
            self._pin.callback(Pin.IRQ_RISING,handler=self._callback,arg=self)
            self._timer = Timer.Chrono()
            self._timer.start()
    
        def _callback(self,obj):
            self._intvl = self._timer.read_ms()
            self._timer.reset()
    
        def rpm(self):
            return self._intvl
    
    while True:
        data = RPM('P16')
        print(data.rpm())
        sleep(1)
    
    

Log in to reply
 

Pycom on Twitter