Flow meter

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Flow meter

Post by adafruit_support_rick »

Probably the "break" in the ISR should be a "continue". But I hate break and continue anyway. Don't know why I did that.
Use this for the ISR instead, and see what happens:

Code: Select all

SIGNAL(TIMER0_COMPA_vect) {
  for (int m = 0; m < NUM_METERS; m++)
  {
    uint8_t x = digitalRead(meters[m].pin);

    if (x == meters[m].lastflowpinstate) {
      meters[m].lastflowratetimer++;
    }
    else
    {
      if (x == HIGH) {
        //low to high transition!
        meters[m].pulses++;
      }
      meters[m].lastflowpinstate = x;
      meters[m].flowrate = 1000.0;
      meters[m].flowrate /= meters[m].lastflowratetimer;  // in hertz
      meters[m].lastflowratetimer = 0;
    }
  }
}

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

Thank you very much! It works with all eight meters. Now I just have to find a way to get to know when one detects no more or more flow than the others. I'll try this on my own first. Thank u very much

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Flow meter

Post by adafruit_support_rick »

No problem - glad to help! :)

User avatar
rbergs
 
Posts: 17
Joined: Thu May 01, 2014 10:15 am

Re: Flow meter

Post by rbergs »

We had an application with a flow meter. We bought the one here (828) but unfortunately the flow was too low for it to catch.

We tried the example code, but found that any time delays and / or com rate changes would affect the count total. What we went to was the hardware interrupts on the Mega we were using. This is independent, for the most part, of what the program was doing.

I don't remember the exact code, but if you look up the hardware interrupt, you make a sub routine that indexes a counter when the interrupt is tripped. The flow meter we were using was ~100,000 counts per liter.

Hope this is somewhat helpful.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

Okay, I am back. As I already said, I want the the motor to shut down when one of the eight flowrates is more than 2 liters/minute different to all the others. Therefore I just have to open an relay. If I had only two meters, I'd do something like this:

Code: Select all

if(flowrate1 - flowrate2 > 2) {
digitalWrite(Relay_STOP, HIGH);
}
But I have no idea how I can compare all eight among themselves without a reference.
I'll attach my whole code, the interesting stuff is in the FLOWMETER section.
Thank you!!!

Code: Select all

//Pump durability tester code
//includes:
//-thermal shutdown circuit
//-motor speed control via relay
//-pump flowrate monitoring


// include the library code for I2C and the LCD shield:

#include "Adafruit_MAX31855.h"
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

#define PIN_ESTOP                          8         // connects to the NC E-Stop button

//#define PIN_I2C_1                          A4        // these pins provide serial communication with the LCD shield
//#define PIN_I2C_2                          A5        // these pins provide serial communication with the LCD shield

#define THRESHOLD_TEMPERATURE_MOTOR        100        // maximum pump temperature for normal operation
#define THRESHOLD_TEMPERATURE_AMBIENT      60        // maximum ambient temperature for normal operation

#define STATE_ESTOP_ACTIVE                 HIGH      // E-stop pin is pulled high internally, then grounded through E-stop button
                                                     // the button is NC, thus pressed means open means not grounded means HIGH
                                     

#define Relay_STOP                          12        // Relay control output 
#define Relay1                              22        // Relay speed1
#define Relay2                              24        // Relay speed2
#define Relay3                              26        // Relay speed3
#define thermoDO                            2         // Data out (shared)
#define thermoCS1                           3         // Chip select for thermocouple 1
#define thermoCLK                           4         // Clock (shared)
#define thermoCS2                           5         // Chip select for thermocouple 2
  
#define time                                double (millis()/1000)/60  // Program runtime.
// Variables will change:
long previousMillis = 0; 

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
// this creates an LCD object that is controlled using the Adafruit library

Adafruit_MAX31855 thermocouple1(thermoCLK, thermoCS1, thermoDO);
Adafruit_MAX31855 thermocouple2(thermoCLK, thermoCS2, thermoDO);

//FLOWMETERS-------------------------------------------------------------------------------------

typedef struct Meter_t
{
  uint8_t pin;
  uint16_t pulses;
  uint8_t lastflowpinstate;
  uint32_t lastflowratetimer;
  float flowrate;
  float wert;
  float lmin;
};

volatile Meter_t meters[] = {                        // initialize meter array
                              { 28, 0, 0, 0, 0.0   }, // meter 1: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 30, 0, 0, 0, 0.0   },  // meter 2: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 32, 0, 0, 0, 0.0   },  // meter 3: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 34, 0, 0, 0, 0.0   },   // meter 2: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 36, 0, 0, 0, 0.0   }, // meter 1: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 38, 0, 0, 0, 0.0   },  // meter 2: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 40, 0, 0, 0, 0.0   },  // meter 3: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                              { 42, 0, 0, 0, 0.0   }   // meter 2: pin, pulses, lastflowpinstate, lastflowratetimer, flowrate
                                                     // add more meters as needed
                            };
#define NUM_METERS (sizeof(meters) / sizeof(Meter_t))

SIGNAL(TIMER0_COMPA_vect) {
  for (int m = 0; m < NUM_METERS; m++)
  {
    uint8_t x = digitalRead(meters[m].pin);

    if (x == meters[m].lastflowpinstate) {
      meters[m].lastflowratetimer++;
    }
    else
    {
      if (x == HIGH) {
        //low to high transition!
        meters[m].pulses++;
      }
      meters[m].lastflowpinstate = x;
      meters[m].flowrate = 1000.0;
      meters[m].flowrate /= meters[m].lastflowratetimer;  // in hertz
      meters[m].lastflowratetimer = 0;
    }
  }
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
  } 
  else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
  }
  
  //FLOWMETERS-------------------------------------------------------------------------------------
}
  
void setup() {
  Serial.begin(9600);
  Serial.print("Flow sensor test!");
// declare the number of columns and rows for the LCD: 
lcd.begin(16, 2);

 //FLOWMETERS-------------------------------------------------------------------------------------

for (int m = 0; m < NUM_METERS; m++)
  {
    pinMode(meters[m].pin, INPUT);
    digitalWrite(meters[m].pin, HIGH);
    meters[m].lastflowpinstate = digitalRead(meters[m].pin);
  }

  useInterrupt(true);
  
   //FLOWMETERS-------------------------------------------------------------------------------------
  
//pinMode(PIN_ESTOP, INPUT_PULLUP);

pinMode(Relay_STOP, OUTPUT);
digitalWrite(Relay_STOP, LOW);
lcd.setCursor(0,0);
lcd.print("Motor ON");
lcd.setCursor(0,1);
lcd.print("VFD Enabled");

 //SPEEDCONTROL-------------------------------------------------------------------------------------

  pinMode(Relay1, OUTPUT);
  digitalWrite(Relay1, HIGH);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Relay2, HIGH);
  pinMode(Relay3, OUTPUT);
  digitalWrite(Relay3, HIGH);
  
   //SPEEDCONTROL-------------------------------------------------------------------------------------
  
} //end of setup()


void loop()
{
// checkEStop();
// checkThermocouples();
 
  //FLOWMETERS-------------------------------------------------------------------------------------
 
 for (int m = 0; m < NUM_METERS; m++)
  {
    
  //average filter
  int i;
  meters[m].wert = 0;
  for(i = 0; i < 50; i++) {
  meters[m].wert += meters[m].flowrate;}
  meters[m].wert /= 50;
  
  meters[m].lmin = meters[m].wert;
  meters[m].lmin *=0.12;
  
   //FLOWMETERS-------------------------------------------------------------------------------------
   
   //SPEEDCONTROL-------------------------------------------------------------------------------------
    
  unsigned long currentMillis = millis();  
 
  if(currentMillis - previousMillis < 20000) {
    digitalWrite(Relay1, LOW);
  }
  else {
    digitalWrite(Relay1, HIGH);
  }

  if(currentMillis - previousMillis > 20000 && currentMillis - previousMillis < 40000) {
    digitalWrite(Relay2, LOW);
  }
  
  else {
    digitalWrite(Relay2, HIGH);
  }

  if(currentMillis - previousMillis > 40000 && currentMillis - previousMillis < 60000) {
    digitalWrite(Relay3, LOW);
  }
  else {
    digitalWrite(Relay3, HIGH);
  }

  if(currentMillis - previousMillis >= 60000) {// reset the timer and start again
    previousMillis = currentMillis; 
  }
  
  //SPEEDCONTROL-------------------------------------------------------------------------------------
    
    //lcd.print(flowrate);
    Serial.print("Meter ");
    Serial.print(m+1);
    Serial.print(" FLowrate: "); 
    Serial.println(meters[m].flowrate);
    Serial.print("Pulses: "); 
    Serial.println(meters[m].pulses, DEC);
    
    
  }
    
    
}  // end of loop()




//void checkEStop()
//{
//  digitalWrite (PIN_ESTOP, HIGH);
//  if ( digitalRead(PIN_ESTOP) == STATE_ESTOP_ACTIVE )  // if Estop button is pressed
//  {
//    digitalWrite(PIN_RELAY, LOW);     // turn off relay to shut down VFD
//    digitalWrite(PIN_RELAY, LOW);      // shut down VFD
//    lcd.setBacklight(RED);              // display warning on LCD
//   lcd.clear();
//    lcd.setCursor(0,0);
//    lcd.print("E-Stop pressed");
//    lcd.setCursor(0,1);
//    lcd.print("RT: ");
//    lcd.println(time);
//    lcd.println( " (min)");
//    while(1)  {}                      // wait for Arduino reset
//  }
  
//} // end checkEStop




//void checkThermocouples()
//{
//  double temperatureMotor = thermocouple1.readCelsius();  // read motor temperature from thermocouple
//  double temperatureAmbient = thermocouple2.readCelsius();// read ambiant temperature from thermocouple
  
//  lcd.setCursor(0,0);                                    // display data on LCD
//  lcd.print("Motor:    ");
//  lcd.print(temperatureMotor);
//  lcd.print(" C");
 
//  lcd.setCursor(0,1);                                    // display data on LCD
//  lcd.print("Ambient:  ");
//  lcd.print(temperatureAmbient);
//  lcd.print(" C");
  
  
//  if (temperatureMotor >= THRESHOLD_TEMPERATURE_MOTOR)       // if temperature is too high
//     {     
//     digitalWrite(PIN_RELAY, LOW);                           // shut down VFD
     
//     lcd.setBacklight(RED);                                  // display warning on LCD
//     lcd.clear();
//     lcd.setCursor(0,0);
//     lcd.print("T_Motor Limit Reached");
//     lcd.setCursor(0,1);
//     lcd.print("RT: ");
//     lcd.println(time);
//     lcd.println( " (min)");
//     while(1)  {}                                            // wait for reset
//   }
     
//   if (temperatureAmbient > THRESHOLD_TEMPERATURE_AMBIENT)   // if temperature is too high
//   {
//     digitalWrite(PIN_RELAY, LOW);                           // shut down VFD
     
//     lcd.setBacklight(RED);                                  // display warning on LCD
//     lcd.clear();
//     lcd.setCursor(0,0);
//     lcd.print("T_AMB Limit Reached");
//     lcd.setCursor(0,1);
//     lcd.print("RT: ");
//     lcd.println(time);
//     lcd.println( " (min)");
//     while(1)  {}                                            // wait for reset
//   }
//  delay (1000);
//} // end checkThermocouples

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: Flow meter

Post by adafruit_support_bill »

When you iterate through the array of meters, keep track of the min and max flow rates that you see. At the end of the loop, compare the min and max. If the difference is more than 2, shut down the motor.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

I did it like this:

Code: Select all

 for (int m = 0; m < NUM_METERS; m++)
  {
    
  //average filter
  int i;
  meters[m].wert = 0;
  for(i = 0; i < 50; i++) {
  meters[m].wert += meters[m].flowrate;}
  meters[m].wert /= 50;
  
  meters[m].lmin = meters[m].wert;
  meters[m].lmin *=0.12;
  
  float lmin_max;
  float lmin_min;
  
  if( meters[m].lmin > lmin_max){
    lmin_max = meters[m].lmin;
  }
   
   if( meters[m].lmin < lmin_min){
    lmin_min = meters[m].lmin;
  }
 
   if( lmin_max - lmin_min > 2 ){
     digitalWrite(Relay_STOP, HIGH);
     lcd.print("Pump failed:");
     lcd.print("???Number???");
   }
    
    //lcd.print(flowrate);
    Serial.print("Meter ");
    Serial.print(m+1);
    Serial.print(" FLowrate: "); 
    Serial.println(meters[m].flowrate);
    Serial.print("Pulses: "); 
    Serial.println(meters[m].pulses, DEC);
    
    
  }
I can't test it right now, but it should work like this, right?

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: Flow meter

Post by adafruit_support_bill »

Code: Select all

  float lmin_max;
  float lmin_min;
These need to be declared outside of the loop. Otherwise they will be re-initialized each time through the loop.

Also, you will want to initialize them: lmin_max should be initialized to 0.0. lmin_min should be initialized to some huge number - at least as large as the maximum expected flow rate.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

Oh yeah I forgot that. Thanks!

i also want to get the number of the pump that failed, is there a way to get it with this method?

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: Flow meter

Post by adafruit_support_bill »

When you detect the minimum or maximum flow rate, you can record the pump that is responsible.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

But I can't say if the minimum or the maximum pump failed, right? I did it like this(declared fail_1 and fail_2 outside the loop):

Code: Select all

 if( meters[m].lmin > lmin_max){
    lmin_max = meters[m].lmin;
    fail_1 = m;
    
  }
   
   if( meters[m].lmin < lmin_min){
    lmin_min = meters[m].lmin;
    fail_2 = m;
  }
 
   if( lmin_max - lmin_min > 2 ){
     digitalWrite(Relay_STOP, HIGH);
     lcd.print("Pump failed:");
     lcd.print(fail_1);
     lcd.print(fail_2);
   }

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Flow meter

Post by adafruit_support_rick »

Don't try to do it all in one step - that's where you're having problems. Instead, scan through all 8 pumps. Remember the min and the max flowrate that you see. Keep track of the pump number with the minimum rate. When you are done, compare the min and the max rates. If the difference is more than 2, shut down the pump with the min flow rate.

Something like this:

Code: Select all

float BANNED = 1000000.0;  //init to some ridiculously large number
float maxRate = 0.0;  
int slowestPump = 0;

for (int m = 0; m < NUM_METERS; m++)
{
  maxRate = MAX(meters[m].flowRate, maxRate);
  if (meters[m].flowRate < BANNED)
  {
    BANNED = meters[m].flowRate;
    slowestPump = m;
  }
}

if ((maxRate - BANNED) > 2.0)
{
  <shut down slowestPump>
}

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

Thank you, but the problem is, that a failed pump could also pump much more than the other ones. Therefore I can't just take the slowest one. I thought about taking the average of all flowrates and then compare that value with the min and max flowrate to see which one is most different. But it is hard to put that into code.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Flow meter

Post by bdellal »

Yhe shutdown procedure is not working correctly. The system is running for 60 seconds and then shuts random down a pump that is not even the lowest. Till that moment it is running and shows on the serial monitor that the flowrates are totally different and the difference is much higher than what I told the program is the maximum.

Code: Select all

 //FLOWMETERS-------------------------------------------------------------------------------------
  float lmin_max = 0;
float lmin_min = 1000;
int pump_max = 0;
int pump_min = 0;


 for (int m = 0; m < NUM_METERS; m++)
  {
    
  //average filter
  int i;
  meters[m].wert = 0;
  for(i = 0; i < 50; i++) {
  meters[m].wert += meters[m].flowrate;}
  meters[m].wert /= 50;
  
  meters[m].lmin = meters[m].wert;
  meters[m].lmin *=0.12;
  
  lmin_max = max(meters[m].lmin, lmin_max);
  if (meters[m].lmin < lmin_min)
  {
    lmin_min = meters[m].lmin;
    pump_min = m;
  }
//}

if ((lmin_max - lmin_min) > 2.0)
{
  digitalWrite(Relay_STOP, HIGH);
     Serial.print("Failed Pump:");
     Serial.print(pump_min+1);
     lcd.print("Failed Pump:");
     lcd.print(pump_min+1);
     while(1)  {} 
}

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: Flow meter

Post by adafruit_support_bill »

Some comments and consistent indenting would make your code a lot easier to follow. Also, the code posted is not complete.

What data type is 'wert'? You may be overflowing it.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”