Heeeeelp!! Water flow sensor

:confused: guys need help about this code on flow sensor how can i achieve the accuracy and precision? And i dont understand the code well is anyone there can explain to me about the this and i would like to ask how to calibrate this code actually i already made it but when i measure the water flow it has great error i mean the output seems to double i dont know how to do this :frowning: the code is in this bloghttps://www.homemadecircuitsprojects.com/2017/10/simple-digital-water-flow-meter.html?m=1#comment-form :

Ps. SOMEBODY PLEASE

You might find a better explanation here

If you want to read the rate sensibly, I think it is better to derive an average over say ten readings.

A link to the flow sensor please.

use your pump and pump exactly 5 gallons (or some known quantity)

display how many pulses.

repeat a few times.

Try to duplicate your actual conditions. it is much easier to pump from a tank to a lower tank.
it is harder to pump as the tank gets closer to empty.

if the sensors cost less than a few dollars you might not get exact readings.

a second means of measuring can often help.
a tank level sensor might confirm the readings.

to re-iterate :post a link to your sensor.
and please post your code

Hello,

I was helped by the forum with a flow meter code, this is what we came up with:

const int flowPin = 2;
unsigned long pulseTime = 0;
volatile unsigned long pulses = 0;
volatile unsigned long time = 0;
volatile float seconds = 0.00;
volatile float gallons = 0.00;
volatile float gpm = 0.00;

void pulseCount()
{
  pulses++;
  time = millis();
}

void setup()
{
  pinMode(flowPin, INPUT_PULLUP);
  Serial.begin(9600);
  attachInterrupt(0, pulseCount, RISING); // interrupt on pin 2
}

void loop()
{
  pulseTime = pulseIn(flowPin, LOW);
  
  if (pulseTime != 0) // when flow is active
  {
    seconds = (float)time / 1000;
    Serial.print("Seconds: ");
    Serial.println(seconds);
    gallons = (float)pulses / 5000.00;
    Serial.print("Gallons: ");
    Serial.println(gallons);
    gpm = (float)gallons * 60.000 / (float)seconds;
    Serial.print("GPM: ");
    Serial.println(gpm);
    Serial.println();
  }
}

As far as calibration (that's the pulses if you're using a hall-effect sensor or something similar), I'd piggyback on the other replies - except have something in your code to display the pulses counted. That way, when you have dispensed your fluid and calculated the volume you can correlate it to the pulses in the flow meter. You would basically add [Serial.print(pulses);] somewhere in the code.

For calculating volume - I'd just run the thing into a bucket and weigh it (lbs), divide by 8.33 to get your gallons, do whatever conversions to get the unit you'll be using.

I realized I didn't fully answer the calibration question. Once you have your volume and the un-calibrated pulses displayed, you'll do some math, example for say, 20 lbs and 2000 pulses.

20lbs/8.33gal/lb = 2.4gal

2000pulses/2.4gal = 833 pulses/gal

so, in the part of the code

gallons = (float)pulses / 5000.00;

you would have 833 instead of 5000.

Hope that helps.

Is the sensor using an impeller that is sensed by a hall sensor? Such flow meaters are higly nonlinear depending on the flow rate but that can be improved.

The flow meter on the web page she listed in the OP says it’s a hall effect sensor, but you’re right about them not being super accurate. You have to have a pretty steady flow rate for them to have consistent readouts. If the application is to see how flow varies over time that might present difficulties.

Here is another example of flow meter code where the pulses are called out at the top instead of mid-code - this one I did not write myself, I don’t remember the name of the guy that helped me with it:

#define FLOW_TIMEOUT 1000
#define PULSES_PER_GALLON 5000.00

const int flowPin = 2;
volatile unsigned long lastPulseTime = 0;
volatile unsigned long pulses = 0;

void pulseCount()
{
  pulses++;
  lastPulseTime = millis();
}

void setup()
{
  pinMode(flowPin, INPUT_PULLUP);
  Serial.begin(9600);
  attachInterrupt(0, pulseCount, RISING);
}

void loop()
{
  static bool flowIsStopped = true;
  unsigned long timeRun;
  static unsigned long startTime = 0;
  unsigned long totalPulses;
  float seconds;
  float gallons;
  float gpm;
  
  noInterrupts();
  timeRun = lastPulseTime;
  interrupts();
  
  if(flowIsStopped)
  {
    if(millis() - timeRun < FLOW_TIMEOUT) // flow has started
    {
      startTime = timeRun;
      flowIsStopped = false;
    }
  }
  else
  {
    if(millis() - timeRun < FLOW_TIMEOUT) // still flowing
    {
      if ((timeRun - startTime) % 1000 == 0)
      {
        gallons = (float)pulses / PULSES_PER_GALLON;
        seconds = (float)(timeRun - startTime) / 1000;
        gpm = (float)gallons / seconds * 60;
        Serial.print("Seconds: ");
        Serial.println(seconds);
        Serial.print("Gallons: ");
        Serial.println(gallons);
        Serial.print("GPM: ");
        Serial.println(gpm);
        Serial.println();
      }
    }
    else
    {
      flowIsStopped = true;  // stopped flowing
        
      noInterrupts();
      totalPulses = pulses;
      pulses = 0;
      interrupts();
        
      gallons = (float)totalPulses / PULSES_PER_GALLON;
      seconds = (float)(timeRun - startTime) / 1000;
      gpm = gallons / seconds * 60;
      Serial.print("Seconds: ");
      Serial.println(seconds);
      Serial.print("Pulses: ");
      Serial.println(totalPulses);
      Serial.print("Gallons: ");
      Serial.println(gallons);
      Serial.print("GPM: ");
      Serial.println(gpm);
      Serial.println();
    }
  }
}

Good luck!

this is the code guys tnx for your replies my application is to get the flow of water per minute and the total water that past the sensor but seems i couldnt understand this well

//-----Program Developed by R.Girish-----//
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int X;
int Y;
float Time = 0;
float frequency = 0;
float waterFlow = 0;
float total = 0;
float LS = 0;
const int input = A0;
const int test = 9;
void setup()
{
Serial.begin(9600);
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“Water Flow Meter”);
lcd.setCursor(0,1);
lcd.print("****************");
delay(2000);
pinMode(input,INPUT);
pinMode(test, OUTPUT);
analogWrite(test,100);
}
void loop()
{
X = pulseIn(input, HIGH);
Y = pulseIn(input, LOW);
Time = X + Y;
frequency = 1000000/Time;
waterFlow = frequency/7.5;
LS = waterFlow/60;
if(frequency >= 0)
{
if(isinf(frequency))
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“L/Min: 0.00”);
lcd.setCursor(0,1);
lcd.print(“Total: “);
lcd.print(total);
lcd.print(” L”);
}
else
{
total = total + LS;
Serial.println(frequency);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("L/Min: ");
lcd.print(waterFlow);
lcd.setCursor(0,1);
lcd.print(“Total: “);
lcd.print(total);
lcd.print(” L”);
}
}
delay(1000);
}

Code looks pretty crappy to me. It may work but I believe it is normal practice to use interrupt for this sort of thing. There are times when using a delay to control a loop is legitimate, but I don't think this is one of them, and that may go some way to explain the grief you are having. Even the LCD commands suggest slack practice.

Ayt bro can sorry im just newbie to arduino

Tutorial for interrupts:

https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

which is where I started with the original code I posted. The problem with my first attempt is that it would display the results in a constant stream, which is why the [if (pulseTime != 0)] part was added, as suggested by another forum member.

The idea behind interrupts is that it gets rid of delays and can count every change (pulse) as it happens.

This part of your code:

void loop()
{
X = pulseIn(input, HIGH);
Y = pulseIn(input, LOW);
Time = X + Y;
frequency = 1000000/Time;
waterFlow = frequency/7.5;
LS = waterFlow/60;
if(frequency >= 0)
{

is really the messy part. You can keep track of time with the internal clock [millis()], instead of doing math to come up with the time. Just use math to convert the pulses to volume, and then use the time to convert to flow rate.

If you have a scale that would be the easiest way to determine the volume that went through the flow meter. Metric is even easier than gallons: 1L = 1kg (roughly). You can either dispense exactly 1kg of water (tricky) and count those pulses, or convert whatever the mass is to volume (should be roughly the same in metric), and then divide pulses by that to get pulses/volume. Definitely want to display the pulses somewhere for that though.

Being a newbie is tricky. I've found the forum a great way to get started, but some of the responses may be pretty blunt.

Good luck!

Astra:
just newbie to arduino

We all learn. The code I linked to is common practice, there being other versions around of the same thing. It works well, and I just used it in a stripped-down form. The problem with reading the rate is just a human thing and has nothing to do with actual accuracy. The accuracy of these devices can indeed be remarkably good, and this is borne out by the quantity readings.