2

I have a mass flow meter connected to an Arduino Uno board. I have managed to read the volume flow in L/hour, but now I'm struggling to implement a code that stores the values so that I see the number of Liters used.

For instance, I can see on my monitor this:

0 L/hour

0 L/hour

And if I have some water running through,

10 L/hour

20 L/hour

20 L/hour

Then when I stop the flow it goes back to 0.

0 L/hour

Is there any ways to sum up time instances, get the total number of liters and keep it printed during every instance?

Mathematically is not that difficult (Volume = Volume Flow in L/hour * time), but I don't know how to implement this. Can anyone help with this? It can be in seconds or ms or whatever.

Paul

3 Answers 3

4

What you want to do is integrate the flow rate vs time curve. You have to keep track of the current flow rate. You also need to choose some unit of time measurement; this depends on how often you're sampling the flow rate. For instance, if you sample it every second, then you should convert your L/hr flow rate to L/s. This means a flow rate of 10L/hr is equivalent to 10L/3600s = 0.002778 L/s. So, if you get a reading of 10 L/hr for 10 seconds, 0.002778 L/s * 10 s = 0.02778 L of water flowed through your valve or whatever. An accumulating sum is what you need. You can try something like this:

#define INTERVAL 1000  // sampling interval in millisec
#define HR_TO_SEC 2.778E-4  // number of hours in a second

int curr_rate = 0;  // current flow rate in L/hr
unsigned long lastRead = 0;  // the last time the rate was sampled
float totalVolume = 0; 

void loop(){
  if (millis() - lastRead >= INTERVAL){
    lastRead += INTERVAL;
    curr_rate = getFlowRate();   // or whatever function you call; should take << 1 sec
    totalVolume += curr_rate * HR_TO_SEC;  // update the volume
    Serial.println(totalVolume, 4);
  }
}

This rectangular method is reasonably accurate, depending on your application. If you want a better approximation, google "trapezoidal numerical integration" or "Simpson's method" if you want even better approximation.

5
  • The higher order integration methods achieve better accuracy by leveraging the smoothness of the integrand. Here, since there is a valve, the flow is unlikely to be smooth. If you want better accuracy, you only have to sample at shorter intervals. Sep 25, 2016 at 6:40
  • 1
    Also, I replaced lastRead = millis(); by lastRead += INTERVAL;. Otherwise you have a systematic bias, as the average sampling interval would be larger than INTERVAL. Sep 25, 2016 at 9:56
  • Thank you both for the help. I have managed to implement this code and it does indeed store the data. I have poured 1 L of water through the meter and the monitor reads 1.2 L. Not a huge difference, but I will change the method of integration and we will see if I can correct that. Also, I had to remove "unsigned" for "float totalVolume = 0;". The code would give an error otherwise.
    – Physther
    Sep 25, 2016 at 12:14
  • @Paul You can do as Edgar Bonet says and reduce the interval to 200 ms maybe. Also take care to change HR_TO_SEC to reflect that: convert your interval to hours. If this solves your problem, consider accepting it. Sep 25, 2016 at 13:26
  • Okay. I will do some experiments these days and see how it goes. I will write back! Thank you
    – Physther
    Sep 26, 2016 at 13:00
1

This will be helpful.

reading is your flow meter value in L/Hour

float reading;//value of the flow meter
long startTime;
float total=0;

void setup() {
  Serial.begin(9600);
  startTime=millis();

}

void loop() {
//read your flow meter to reading variable.
 total+=reading*float((millis()-startTime))/3600000.0;
 Serial.println(total);

}
3
  • Thank you very much! I have tried with this code and it keeps giving me 0. Also, I needed to add long startTime=millis(); instead of simply declaring long startTime and then calling it. Is the "reading" function responsible for me getting 0? Does it have to be related to the signal or the pinmode?
    – Physther
    Sep 25, 2016 at 12:07
  • reading is the variable..You must pass your flow meter reading to that variable as a float type. you must enter it before Serial.println() function as I commented. if you can give previous code,I will be able to give full code.
    – user_fs10
    Sep 25, 2016 at 12:24
  • The code can be found here: forum.arduino.cc/index.php?topic=8548.0 (It is too long to post it here). Thank you!
    – Physther
    Sep 26, 2016 at 13:00
1

In a recent comment, you posted a link to a forum thread with the code for reading the sensor. You should have provided this information up front, because it completely changes the problem. It appears that the flow meter sends pulses at a frequency proportional to the volume flow, and the code uses an interrupt to count the pulses over a specified time.

TisteAndii's answer suggests you integrate the flow readings to get a volume. And that suggestion makes perfect sense given the limited information he had available at the time. Now that we know how the flow meter is read, it makes no sense anymore:

  • the interrupt service routine counts a number of pulses that is proportional to the total volume that has gone through the meter
  • the linked code differentiates that reading in order to get the flow
  • you are now integrating that flow in order to get the total volume.

Instead of doing an integration on top of a differentiation, you could just convert the raw reading into a volume. Then you do not have to worry about any approximations done while differentiating or integrating.

In the forum thread it is stated:

Pulse frequency (Hz) in Horizontal Test= 7.5Q, Q is flow rate in L/min.

Writing this in a more mathematically accurate form (i.e. with unit-correctness) gives:

f/Hz = 7.5 Q/(L/min)

where f is the frequency and Q the volume flow.

Given that 7.5 Hz⋅min = 450 pulses, the above equation can be rewritten as

f = 450 pulses/L × Q

or, in terms of integrated quantities:

volume = (pulse count) / (450 pulses/L)

Here is an example code that just convert the pulse count to a volume:

// Calibration constant of the flow meter.
const float calibration = 1/450.0;  // 450 pulses per liter

// How often to print the measured volume.
const uint32_t print_interval = 1000;  // once per second

// Number of pulses counted so far.
volatile uint32_t pulse_count;

// Count the pulses inside an ISR.
void count_pulse() { pulse_count++; }

// Return volume reading, optinally resetting the count to zero.
float totalVolume(bool reset = false)
{
    noInterrupts();
    uint32_t pulse_count_copy = pulse_count;
    if (reset) pulse_count = 0;
    interrupts();
    return pulse_count_copy * calibration;
}

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

void loop()
{
    static uint32_t last_print;
    if (millis() - last_print >= print_interval) {
        last_print += print_interval;
        Serial.println(totalVolume());
    }
}

Note that you may want to reset the count from time to time. I added an optional parameter to totalVolume() for this purpose. If you never reset the counter, it will overflow after approximately 9544 m3.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.