Go Down

Topic: Liquid Usage with a meter from Adafruit (Read 5804 times) previous topic - next topic

arduinowater626

Looking at using my recently purchased arduino uno to measure in US gallons amount of a liquid used in a process, and recording data for use to be logged into a spreadsheet. I am wondering what all will be needed or reccomended ie: shields and anything else.

Nick_Pyner

Assuming you don't need to get serious with positive displacement dispensers, there is a swag of hall effect turbine sensors on eBay and it is just a matter of choosing one for size, fittings etc.

I use the Freetronics software from Jaycar. I think instant readout of rate is a hopeless exercise, but measuring quantity is fine. More refined programmes have been discussed on this forum.

You can feed the output direct to Excel using PLX-DAQ which is a freebie macro that effectively makes Excel into a terminal.

Shields depend on what you want, and matters of convenience. I use a home-made shield for the sensors which also incorporates a clock, plus an Ethernet shield which incorporates an SD card, plus another home-made shield carrying a display. Three in all. This is for a remote installation. If you just want to feed data to a PC terminal, a $2 breadboard is probably all you need. No shields.


Pesho77

#2
Apr 13, 2014, 08:35 pm Last Edit: May 04, 2014, 11:12 am by robtillaart Reason: 1
Can you please post the sketch for this im tryin to set up a way to mesure water for a home brew set up and im just getting more an more confused the more i read

ive found this one for Ltr's/hour

Code: [Select]

// 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
}

But im still waiting for my arduino so i cant test it as yet


I would like to do a count up in to one tank then do a count down in to another (ie fill tank 1 then transfer water from tank 1 in to tank 2) so the code would be the same but reversed.  

Pesh

moderatore added code tags

Pesho77

#3
Apr 14, 2014, 09:18 am Last Edit: May 04, 2014, 11:11 am by robtillaart Reason: 1
Sorry misread the above post my brain must be more frye than i thought
Code: [Select]

/**
* Water Flow Gauge
*
* Uses a hall-effect flow sensor to measure the rate of water flow and
* output it via the serial connection once per second.
*
* Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
* Copyright 2009 Hugh Blemings <hugh@blemings.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. http://www.gnu.org/licenses/
*
* www.practicalarduino.com/projects/water-flow-gauge
*/

#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Specify the pins for the two counter reset buttons and indicator LED
byte resetButtonA = 11;
byte resetButtonB = 12;
byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = pin 2; 1 = pin 3
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitresA;
unsigned long totalMilliLitresB;

unsigned long oldTime;

void setup()
{
 lcd.begin(16, 2);
 lcd.setCursor(0, 0);
 lcd.print("                ");
 lcd.setCursor(0, 1);
 lcd.print("                ");
 
 // Initialize a serial connection for reporting values to the host
 Serial.begin(38400);
 
 // Set up the status LED line as an output
 pinMode(statusLed, OUTPUT);
 digitalWrite(statusLed, HIGH);  // We have an active-low LED attached
 
 // Set up the pair of counter reset buttons and activate internal pull-up resistors
 pinMode(resetButtonA, INPUT);
 digitalWrite(resetButtonA, HIGH);
 pinMode(resetButtonB, INPUT);
 digitalWrite(resetButtonB, HIGH);
 
 pinMode(sensorPin, INPUT);
 digitalWrite(sensorPin, HIGH);

 pulseCount        = 0;
 flowRate          = 0.0;
 flowMilliLitres   = 0;
 totalMilliLitresA = 0;
 totalMilliLitresB = 0;
 oldTime           = 0;

 // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
 // Configured to trigger on a FALLING state change (transition from HIGH
 // state to LOW state)
 attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
* Main program loop
*/
void loop()
{
 if(digitalRead(resetButtonA) == LOW)
 {
   totalMilliLitresA = 0;
   lcd.setCursor(0, 1);
   lcd.print("0L      ");
 }
 if(digitalRead(resetButtonB) == LOW)
 {
   totalMilliLitresB = 0;
   lcd.setCursor(8, 1);
   lcd.print("0L      ");
 }
 
 if( (digitalRead(resetButtonA) == LOW) || (digitalRead(resetButtonB) == LOW) )
 {
   digitalWrite(statusLed, LOW);
 } else {
   digitalWrite(statusLed, HIGH);
 }
 
 if((millis() - oldTime) > 1000)    // Only process counters once per second
 {
   // Disable the interrupt while calculating flow rate and sending the value to
   // the host
   detachInterrupt(sensorInterrupt);
   //lcd.setCursor(15, 0);
   //lcd.print("*");
   
   // Because this loop may not complete in exactly 1 second intervals we calculate
   // the number of milliseconds that have passed since the last execution and use
   // that to scale the output. We also apply the calibrationFactor to scale the output
   // based on the number of pulses per second per units of measure (litres/minute in
   // this case) coming from the sensor.
   flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
   
   // Note the time this processing pass was executed. Note that because we've
   // disabled interrupts the millis() function won't actually be incrementing right
   // at this point, but it will still return the value it was set to just before
   // interrupts went away.
   oldTime = millis();
   
   // Divide the flow rate in litres/minute by 60 to determine how many litres have
   // passed through the sensor in this 1 second interval, then multiply by 1000 to
   // convert to millilitres.
   flowMilliLitres = (flowRate / 60) * 1000;
   
   // Add the millilitres passed in this second to the cumulative total
   totalMilliLitresA += flowMilliLitres;
   totalMilliLitresB += flowMilliLitres;
 
   // During testing it can be useful to output the literal pulse count value so you
   // can compare that and the calculated flow rate against the data sheets for the
   // flow sensor. Uncomment the following two lines to display the count value.
   //Serial.print(pulseCount, DEC);
   //Serial.print("  ");
   
   // Write the calculated value to the serial port. Because we want to output a
   // floating point value and print() can't handle floats we have to do some trickery
   // to output the whole number part, then a decimal point, then the fractional part.
   unsigned int frac;
   
   // Print the flow rate for this second in litres / minute
   Serial.print(int(flowRate));  // Print the integer part of the variable
   Serial.print(".");             // Print the decimal point
   // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
   frac = (flowRate - int(flowRate)) * 10;
   Serial.print(frac, DEC) ;      // Print the fractional part of the variable

   // Print the number of litres flowed in this second
   Serial.print(" ");             // Output separator
   Serial.print(flowMilliLitres);

   // Print the cumulative total of litres flowed since starting
   Serial.print(" ");             // Output separator
   Serial.print(totalMilliLitresA);
   Serial.print(" ");             // Output separator
   Serial.println(totalMilliLitresB);
   
   lcd.setCursor(0, 0);
   lcd.print("                ");
   lcd.setCursor(0, 0);
   lcd.print("Flow: ");
   if(int(flowRate) < 10)
   {
     lcd.print(" ");
   }
   lcd.print((int)flowRate);   // Print the integer part of the variable
   lcd.print('.');             // Print the decimal point
   lcd.print(frac, DEC) ;      // Print the fractional part of the variable
   lcd.print(" L");
   lcd.print("/min");
   
   lcd.setCursor(0, 1);
   lcd.print(int(totalMilliLitresA / 1000));
   lcd.print("L");
   lcd.setCursor(8, 1);
   lcd.print(int(totalMilliLitresB / 1000));
   lcd.print("L");

   // Reset the pulse counter so we can start incrementing again
   pulseCount = 0;
   
   // Enable the interrupt again now that we've finished sending output
   attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
 }
}

/**
* Invoked by interrupt0 once per rotation of the hall-effect sensor. Interrupt
* handlers should be kept as small as possible so they return quickly.
*/
void pulseCounter()
{
 // Increment the pulse counter
 pulseCount++;
}

Ive added that so its under my posts hope that doesnt annoy any one .

Pesh
moderatore added code tags

Nick_Pyner



Sorry misread the above post


If you are referring to me, that is the programme I was referring to. I stripped down to just read rate and total, no buttons. This is to go with a turbine sold by Jaycar, but will work with any of that ilk. You just need to change the calibration factor. The three I use all have their calibration in the data on eBay and were then adjusted after testing.

After serious long-term testing, it is clear this rig is extraordinarily accurate, around +/- 0.5% error, which might be as good as the Maddalena meter it was being tested against.

Instant flow rate is useless as the programme stands, but the total flow accuracy suggests that getting an average over ten seconds would work. My commercial meter might be doing the same thing anyway and only updates the display every 30 seconds.


Pesho77


The ebay page says 1% accuracy

I want to use this as a home brew set up so ill have to add some code and butons to select the amount of water to ad to a tank so i hope to use a mechanical ball valve for that and close the valve slowly as the total required water is approched then slow the flow to a trickle then stop on target (as the ball valves take 5 seconds from open to shut).

Then transfer some water to another tank so the same code can be used to count down the liquid level into aother tank (using a second meter)

Pesh

Pesho77


Can you please explain why the meters wont read in Ltr's / min i would like to set up a pump running at 3Ltr's/min is this not possible at all, an average every 10 seconds would be near enough

Pesh

Nick_Pyner

The display update was 1hz. I am dealing with mains pressure water with straight pipe 200mm each side. The actual flow would be about 5 l/min  but the readings are all over the place 2.13, 6.29, 4.96, 3.45, that sort of stuff, and by the time you have understood one reading that is so different from the one before, you have missed the next two. Not that that matters, as you have no idea which one to use anyway.

The problem was not so apparent with my Swissflow axial flow turbine, but that was using the frequency meter on a DMM, I never used it with Arduino. I did have a bad time with it, the problem may actually have been the same, and it may be a characteristic of all hall-effect turbines.

I have not progressed any further with this but rate is vital for me and I have to resolve it. I'm sure it can be fixed by either averaging ten readings or simply making the count period ten times as long, or something like that.

Pesho77


To be honest i only need between 2 an 3 Ltr/s min so if i aim for 2.5 and use an average of 10 readings like you suggest i cant be that far wrong, and once i have it stable i can callibrate a jug or demi john by weighing the water and marking it, and adjust the flow rate to suit 3 L/min ish.

The other way i wanted to use this was to equalise the water flow in to and out of a mash tun (a sparge) but i have a mechanical means (a blichman autosparge) to do this any way and to be honest its over kill but since i have all the pieces in place i may as well give it a go, and if it doesnt work i can remove the code and just use the mechanical device.

But for now im still waiting for my arduino so i cant test any thing

Pesh

Pesho77


So i dont get how quantity can be measured very accuratly but quantity over time cant, am I missing something here?

Surely its just the same measurement but with a bit of maths added in

Pesh
What am i missing ? 

Nick_Pyner

Rate is the problem, not quantity. It's not a matter of maths, it's a matter of scale, and depends on when the quantity is assessed.

For me, as I said, display update is once per second, quantity is litres/day.  For a hydroponic greenhouse operator, rate may be litres/day and never know there might be a problem.

Read reply #7 again. Better still, try it for yourself.

Pesho77


Ill give it a go as soon as i have the bits and time.

Pesh

Pesho77

#12
Apr 18, 2014, 11:35 pm Last Edit: May 04, 2014, 11:12 am by robtillaart Reason: 1
Has any one tryed this sketch ?

Code: [Select]

 // 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
}



Pesh

Pesho77

#13
May 03, 2014, 10:32 pm Last Edit: May 04, 2014, 03:35 pm by Pesho77 Reason: 1
So i have most of the bits i need to start testing but i have a TFT screen not an lCD so i tryed to change the code to suit but now it doesnt work .Ive also found i cant get this to work on windows 8

here's the code i have so far there's something simple ive done wrong i just cant see what

Can any one help please ?

 
Code: [Select]
#include <TFT.h>  // Arduino LCD library
#include <SPI.h>

// pin definition for the Uno
#define cs   10
#define dc   9
#define rst  8

// pin definition for the Leonardo
// #define cs   7
// #define dc   0
// #define rst  1

// create an instance of the library
TFT TFTscreen = TFT(cs, dc, rst);

// Specify the pins for the two counter reset buttons and indicator LED
byte resetButtonA = 11;
byte resetButtonB = 12;
byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = pin 2; 1 = pin 3
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitresA;
unsigned long totalMilliLitresB;

unsigned long oldTime;

void setup() ;


  TFT.begin (16, 2);
  TFT.setCursor(0, 0);
  TFT.print("                ");
  TFT.setCursor(0, 1);
  TFT.print("                ");

  // Initialize a serial connection for reporting values to the host
  Serial.begin(38400);
   
  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  // Set up the pair of counter reset buttons and activate internal pull-up resistors
  pinMode(resetButtonA, INPUT);
  digitalWrite(resetButtonA, HIGH);
  pinMode(resetButtonB, INPUT);
  digitalWrite(resetButtonB, HIGH);

  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitresA = 0;
  totalMilliLitresB = 0;
  oldTime           = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
* Main program loop
*/
void loop()
{
  if(digitalRead(resetButtonA) == LOW)
  {
    totalMilliLitresA = 0;
    TFT.setCursor(0, 1);
    TFT.print("0L      ");
  }
  if(digitalRead(resetButtonB) == LOW)
  {
    totalMilliLitresB = 0;
    TFT.setCursor(8, 1);
    TFT.print("0L      ");
  }

  if( (digitalRead(resetButtonA) == LOW) || (digitalRead(resetButtonB) == LOW) )
  {
    digitalWrite(statusLed, LOW);
  } else {
    digitalWrite(statusLed, HIGH);
  }

  if((millis() - oldTime) > 1000)    // Only process counters once per second
  {
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
    //TFT.setCursor(15, 0);
    //TFT.print("*");
   
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
   
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
   
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
   
    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitresA += flowMilliLitres;
    totalMilliLitresB += flowMilliLitres;

    // During testing it can be useful to output the literal pulse count value so you
    // can compare that and the calculated flow rate against the data sheets for the
    // flow sensor. Uncomment the following two lines to display the count value.
    //Serial.print(pulseCount, DEC);
    //Serial.print("  ");
   
    // Write the calculated value to the serial port. Because we want to output a
    // floating point value and print() can't handle floats we have to do some trickery
    // to output the whole number part, then a decimal point, then the fractional part.
    unsigned int frac;
   
    // Print the flow rate for this second in litres / minute
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print(".");             // Print the decimal point
    // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
    frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC) ;      // Print the fractional part of the variable

    // Print the number of litres flowed in this second
    Serial.print(" ");             // Output separator
    Serial.print(flowMilliLitres);

    // Print the cumulative total of litres flowed since starting
    Serial.print(" ");             // Output separator
    Serial.print(totalMilliLitresA);
    Serial.print(" ");             // Output separator
    Serial.println(totalMilliLitresB);
   
    TFT.setCursor(0, 0);
    TFT.print("                ");
    TFT.setCursor(0, 0);
    TFT.print("Flow: ");
    if(int(flowRate) < 10)
    {
      TFT.print(" ");
    }
    TFT.print((int)flowRate);   // Print the integer part of the variable
    TFT.print('.');             // Print the decimal point
    TFT.print(frac, DEC) ;      // Print the fractional part of the variable
    TFT.print(" L");
    TFT.print("/min");
   
    TFT.setCursor(0, 1);
    TFT.print(int(totalMilliLitresA / 1000));
    TFT.print("L");
    TFT.setCursor(8, 1);
    TFT.print(int(totalMilliLitresB / 1000));
    TFT.print("L");

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
   
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/**
* Invoked by interrupt0 once per rotation of the hall-effect sensor. Interrupt
* handlers should be kept as small as possible so they return quickly.
*/
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}


TIA
Pesh

Pesho77

#14
May 04, 2014, 09:27 am Last Edit: May 04, 2014, 03:36 pm by Pesho77 Reason: 1
I should have added its this

 
Code: [Select]
TFT.begin (16, 2);
  TFT.setCursor(0, 0);
  TFT.print("                ");
  TFT.setCursor(0, 1);
  TFT.print("                ");


Thats causing the error

The error message is " expected unqualified id before '.' token"

Any clues any one ?

Pesh

Go Up