Pages: [1] 2 3   Go Down
Author Topic: Liquid Usage with a meter from Adafruit  (Read 4852 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Dee Why NSW
Offline Offline
Edison Member
*
Karma: 47
Posts: 2166
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

 
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 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:
// 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
« Last Edit: May 04, 2014, 04:12:00 am by robtillaart » Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 Sorry misread the above post my brain must be more frye than i thought
Code:
/**
 * 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
« Last Edit: May 04, 2014, 04:11:19 am by robtillaart » Logged

Dee Why NSW
Offline Offline
Edison Member
*
Karma: 47
Posts: 2166
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 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.

Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 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
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 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
Logged

Dee Why NSW
Offline Offline
Edison Member
*
Karma: 47
Posts: 2166
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 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
 
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


 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 ? 
Logged

Dee Why NSW
Offline Offline
Edison Member
*
Karma: 47
Posts: 2166
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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

 Pesh
Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 Has any one tryed this sketch ?

Code:
 // 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
« Last Edit: May 04, 2014, 04:12:39 am by robtillaart » Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 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:
#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
« Last Edit: May 04, 2014, 08:35:39 am by Pesho77 » Logged

uk
Offline Offline
Jr. Member
**
Karma: 3
Posts: 81
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 I should have added its this

  
 
Code:
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
« Last Edit: May 04, 2014, 08:36:17 am by Pesho77 » Logged

Pages: [1] 2 3   Go Up
Jump to: