Go Down

Topic: Using two flow sensors connected to one Arduino. (Read 5809 times) previous topic - next topic

KapteinFredrik

Sep 23, 2012, 09:32 pm Last Edit: Sep 23, 2012, 09:42 pm by KapteinFredrik Reason: 1
Hi.

My friend and I, are trying to figure out a way to use two flow sensor to read a fuel consumption. The first one is for main fuel flow into a pump. The other one is for return fuel from the injector and back to the fuel tank. So, if we call the main fuel sensor for sens1 and the return for sens2 the mathematics will be like this: sens1-sens2=actually fuel consumption.

How do we program two sensors together. How can we get one of the sensor values to be subtracted from the other sensor value?

We tried to use "NbTopsFan++" but it did not work.

We use two of these sensors http://www.btflowmeter.com/en/products/flow-meters-lowflow-flowmeters-low-flow-turbine-flow-meter-fuel-flow-meters-diesel-fuel-flow-meter-watermeters-paddlewheel-flow-meter-oil-flow-meter-oilflowmeter-waterflowmeter-water-meters-turbineflowmeter-oilflowmeter/low-flow-flowmeters-fch-m-pom-series-0002-8-lpm/fch-m-pom-lc-08-lpm-97478617-lc.html

Thanks for your help  8)

Best regards, Fredrik
Best regards, Fredrik

MarkT

The short answer is get one sensor working, then add another, then use the '-' operator on the results.  But there's v. similar posting recently that might be relevant: http://arduino.cc/forum/index.php/topic,123039.0.html
[ I won't respond to messages, use the forum please ]

KapteinFredrik

Something like this?

Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);

byte sensorInterruptA  = 0; 
byte sensorInterruptB  = 1;
byte sensorPinA        = 2;
byte sensorPinB        = 3;

float calibrationFactor = 50;

volatile byte pulseCount;

float flowRate;
unsigned int turFuel;
unsigned int returFuel;

unsigned long oldTime;

void setup()
{
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("                ");
  lcd.setCursor(0, 1);
  lcd.print("                ");
 
  Serial.begin(38400);
 
  pulseCount    = 0;
  flowRate      = 0.0;
  turFuel       = 0;
  returFuel     = 0;
  oldTime       = 0;
 
  attachInterrupt(sensorInterruptA, pulseCounter, FALLING);
  attachInterrupt(sensorInterruptB, pulseCounter, FALLING);
}

//hovedprogrammet i loop.

void loop()
{
  if((millis() - oldTime > 1000)
  {
    detachInterrupt(sensorInterrupt);
   
    flowRate = ((1000.0 / (millis() - oldtime)) * pulseCounat) / calibrationFactor;
   
    oldTime =millis();
   
    flowrate = (turFuel - returFuel) / 8500;
   
    unsigned int frac;
   
    Serial.print(int(flowRate));
    Serial.print(".");           
    frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC) ;
   
    Serial.print(" ");             
    Serial.print(flowRate);
   
     lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 0);
    lcd.print("Flow: ");
    if(int(flowRate) < 10)
    {
      lcd.print(" ");
    }
    lcd.print((int)flowRate);   
    lcd.print('.');             
    lcd.print(frac, DEC) ;     
    lcd.print(" L");
    lcd.print("/min");
   
    pulseCount = 0;
   
    attachInterrupt(sensorInterrupt, pulseCounterA, FALLING);
    attachInterrupt(sensorInterrupt, pulseCounterB, FALLING);
  }
}

void pulseCounter()
{
  pulseCount++;
}
   
   
   
   
Best regards, Fredrik

binooetomo

I think we can use PinChangeInt

One Digital input for each FlowSensor

Lets say the variable to hold Fuel Consumption is 'fc'.
First PinChangeInt (The forward) will add 1 to fc, and the second (The return) will substract 1 from fc

The main loop only check for time periode.
When the periode reached, calculate the real fuel consumption basd on fc and your sensor spec (pulse/galon). That if you want consumption per time

Alternatively, if you easy about acuration, you can put freq devider (prescaler) between the Forward-Sensor and First PinChangeInt.

I'm pretty sure soon you will also want to look at the RPM.

Have a nice hack
-bino-

KapteinFredrik

I think I am into something here:

Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);

byte sensorA = 0;
byte sensorB = 1;
byte sensorPinA = 2;
byte sensorPinB = 3;

float calibrationFactor = 50;

volatile byte pulseCount;

float flowRate;
unsigned int turFuel;
unsigned int returFuel;

unsigned long oldTime;

void setup()
{
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");

Serial.begin(38400);

pinMode(sensorA, INPUT);
pinMode(sensorB, INPUT);

pulseCount  = 0;
flowRate    = 0.0;
turFuel     = 0;
returFuel   = 0;
oldTime     = 0;

attachInterrupt(sensorA, pulseCounter, FALLING);
attachInterrupt(sensorB, pulseCounter, FALLING);
}

//hovedprogrammet i loop.

void loop()
{
if((millis() - oldTime > 1000))
{
detachInterrupt(sensorA);
detachInterrupt(sensorB);

flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

oldTime =millis();

flowRate = (sensorA - sensorB) / 8500;

unsigned int frac;

Serial.print(int(flowRate));
Serial.print(".");
frac = (flowRate - int(flowRate)) * 10;
Serial.print(frac, DEC) ;

Serial.print(" ");
Serial.print(flowRate);

lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("Flow: ");
if(int(flowRate) < 10)
{
lcd.print(" ");
}
lcd.print((int)flowRate);
lcd.print('.');
lcd.print(frac, DEC) ;
lcd.print(" L");
lcd.print("/min");

pulseCount = 0;

attachInterrupt(sensorA, pulseCounter, FALLING);
attachInterrupt(sensorB, pulseCounter, FALLING);
}

void pulseCounter()
{
  pulseCount++;
}


Or what do you think? I get a problem in one of the last lines in this code. Can anyone help with that problem?

Regards, Fredrik.
Best regards, Fredrik

binooetomo

Why you Attach two interupt pin to the same Function ( pulseCounter() ) ?
SensorPinA have to always *increase* the counter, and
SensorPinB have to alwayas *decrease* the counter.

I did it using PinChangeInt Library,
but here is the basic operation using attachInterupt


Code: [Select]


long lastMillis=0;
long curMillis=0;
int RptInterval=1000 ;

int SensorPinFwd = 2;
int SensorPinRtr = 3;
int FlowClick = 0;

void setup(){
   
    pinMode(SensorPinFwd, INPUT);
    pinMode(SensorPinRtr, INPUT);


    attachInterrupt(SensorPinFwd, FuncFlowFwd, FALLING);
    attachInterrupt(SensorPinRtr, FuncFlowRtr, FALLING);

    lastMillis=millis();
    curMillis=lastMillis;

    /*
    And do other setup for serial and LCD here
    */
}

void loop(){
    curMillis = millis();
    if (curMillis-lastMillis >RptInterval) {
        doReport;
        lastMillis = curMillis;
    }
   
}

void FuncFlowFwd(){
    FlowClick=FlowClick+1;
}
void FuncFlowRtr(){
    FlowClick=FlowClick-1;
}
void doReport(){
    /*
    Do any calculation and report/display here
    */
}


KapteinFredrik

Thanks for help binooetomo, but I can't get this to work properly. Actually, nothing work properly here right now. This works like a charmike a charm: https://github.com/practicalarduino/WaterFlowGauge/blob/master/WaterFlowGauge.pde

I have also tried to modify my first sketch to work, but nothing happends after compiling, uploading and opening the serial monitor.

I am so far here:
Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);

byte sensorInterruptA = 0;
byte sensorInterruptB = 1;
byte sensorPinA = 2;
byte sensorPinB = 3;

float calibrationFactor = 4.5;

volatile byte pulseCount;

float flowRate;
unsigned int flowRateA;
unsigned int turFuel;
unsigned int returFuel;

unsigned long oldTime;

void setup()
{
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");

Serial.begin(9600);

pinMode(sensorPinA, INPUT);
pinMode(sensorPinB, INPUT);
digitalWrite(sensorPinA, HIGH);
digitalWrite(sensorPinB, HIGH);

pulseCount           = 0;
pulseCount           = 0;
flowRate             = 0.0;
sensorInterruptA     = 0;
sensorInterruptB     = 0;
oldTime              = 0;

attachInterrupt(sensorInterruptA, pulseCounter, FALLING);
attachInterrupt(sensorInterruptB, pulseCounter, FALLING);
}

//hovedprogrammet i loop.

void loop()
{
  if((millis() - oldTime > 1000))
  {
  detachInterrupt(sensorInterruptA);
  detachInterrupt(sensorInterruptB);

  oldTime =millis();

  flowRate = (sensorInterruptA - sensorInterruptB) / 8500;
 
  flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
 
  flowRateA = (flowRate / 60) * 1000;
 
  unsigned int frac;

  Serial.print(int(flowRateA));
  Serial.print(".");
  frac = (flowRateA - int(flowRateA)) * 10;
  Serial.print(frac, DEC) ;
 
  Serial.print(" ");
  Serial.print(flowRateA);

  lcd.setCursor(0, 0);
  lcd.print(" ");
  lcd.setCursor(0, 0);
  lcd.print("Flow: ");
  if(int(flowRate) < 10)
  {
    lcd.print(" ");
  }
  lcd.print((int)flowRate);
  lcd.print('.');
  lcd.print(frac, DEC) ;
  lcd.print(" L");
  lcd.print("/min");

  pulseCount = 0;

  attachInterrupt(sensorInterruptA, pulseCounter, FALLING);
  attachInterrupt(sensorInterruptB, pulseCounter, FALLING);
  }
}
  void pulseCounter()
{
  pulseCount++;
}


Regards, Fredrik
Best regards, Fredrik

robtillaart

fiddled a bit with your code:
+ use #define for those vars that are not changeable
+ made 2 different IRQ's one for counting the IN pulses and one for counting the out pulses
+ changed some var names to reflect what they meant like litersperminute
+ use a copy of millis() in the if block as millis() might change during the block (accuracy)
+ probably screwed up the math but you should be able to fix that relative easily
+ made some vars local instead of global (reduce scope)

have a look and give it a try (not tested as I don't have an I2CLCD nearby :)
Code: [Select]

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16, 2);

// as these are const one better use #defines
#define IRQ_A 0
#define IRQ_B 1
#define PIN_A 2
#define PIN_B 3

// a separate counter per channel
volatile unsigned long countIN = 0;
volatile unsigned long countOUT = 0;
unsigned long oldTime  = 0;

void setup()
{
  lcd.begin(16, 2);

  Serial.begin(9600);

  pinMode(PIN_A, INPUT);
  pinMode(PIN_B, INPUT);
  digitalWrite(PIN_A, HIGH);
  digitalWrite(PIN_B, HIGH);

  attachInterrupt(IRQ_A, CounterIN, FALLING);
  attachInterrupt(IRQ_B, CounterOUT, FALLING);
}

void loop()
{
  // use a var for value of millis, as it might change in the if .... block
  // due to slow serial prints
  unsigned long now = millis();
  if((now - oldTime > 1000))
  {
    unsigned long duration = now - oldTime;
    oldTime = now;

    // use names that indicate the unit!
    // don't know if all math is correct anymore
    // 8500 pulses per liter?
    float liters = (countIN - countOUT) * 0.000117647; // faster than divide by 8500.0
    float litersPerMinute = (1000 * liters)/duration / 60; // optimized 16.66667*liters/duration

    Serial.print(duration);
    Serial.print(",");  // separate by comma's so you can copy output to Excel easily.
    Serial.println(litersPerMinute, 3);     // print a float with three decimals

    int LPM = litersPerMinute;               // implicit conversion to int
    int frac = (litersPerMinute-LPM)*10;
    lcd.setCursor(0, 0);
    lcd.print("Flow L/min: ");
    lcd.print(LPM); 
    lcd.print(".");   
    lcd.print(frac); 
    lcd.print(" ");
  }
}

void CounterIN()
{
  countIN++;
}

void CounterOUT()
{
  countOUT++;
}

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

KapteinFredrik

Hi Rob and thanks for your help with this!!  :) This looks very good, but this sketch did not work as I hoped it would, but I think you are into something good there. I will try to understand more of it tomorrow. I dont either have the LCD, but my companion will test it when he finnishes his work in the North Sea  :P

Regards, Fredrik
Best regards, Fredrik

robtillaart


The code is definitely not correct (some parts are missing) but should inspire you to improve your coding skills.

Hopes it helps! Succes!

PS, please post your final result when it works
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

KapteinFredrik



The code is definitely not correct (some parts are missing) but should inspire you to improve your coding skills.

Hopes it helps! Succes!

PS, please post your final result when it works


Thanks so much :) Sure, I will post the final result, if other also are planning to do similar  8)

Regard, Fredrik
Best regards, Fredrik

robtillaart

That's the idea of open source, sharing and learning and building on top of each other.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

KapteinFredrik

Code: [Select]

#define IRQ_A 0
#define IRQ_B 1
#define FlowA 2
#define FlowB 3

volatile unsigned long countIN = 0;
volatile unsigned long countOUT = 0;
unsigned long oldTime  = 0;
float flowRate;

volatile byte pulseCountIN;
volatile byte pulseCountOUT;
volatile byte pulseCount;

float liters;

void setup()
{
  Serial.begin(57600);
 
  pulseCountIN = 0;
  pulseCountOUT = 0;
  pulseCount = 0;
  flowRate = 0.0;

  pinMode(FlowA, INPUT);
  pinMode(FlowB, INPUT);
  digitalWrite(FlowA, HIGH);
  digitalWrite(FlowB, HIGH);
 
  liters = 0.0;

  attachInterrupt(IRQ_A, CounterIN, FALLING);
  attachInterrupt(IRQ_B, CounterOUT, FALLING);
}

void loop()
{
  unsigned long now = millis();
  if((now - oldTime > 1000))
  {
    unsigned long duration = now - oldTime;
    oldTime = now;

    liters = (countIN - countOUT);
    float litersPerMinute = (1000 * liters)/duration;
    Serial.println(litersPerMinute, 3);   
    int LPM = litersPerMinute;           
   
    pulseCount = pulseCountIN - pulseCountOUT;
       

    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount);
    unsigned int frac = (flowRate - int(flowRate))*10;
    Serial.print("pulseCount: ");
    Serial.print(pulseCount, DEC);
    Serial.println(" ");

       
    pulseCountIN = 0;
    pulseCountOUT = 0;
   
    attachInterrupt(IRQ_A, CounterIN, FALLING);
    attachInterrupt(IRQ_B, CounterOUT, FALLING); 
  }
}

void CounterIN()
{
  countIN++;
  pulseCountIN++;
}

void CounterOUT()
{
  countOUT++;
  pulseCountOUT++;
}


This is my last version of the sketch, and now it works! Thanks so much for your help :D  I will keep developing this sketch to work more properly. I added two more volatile bytes, because the first sketch did not work.
Best regards, Fredrik

robtillaart

Super that it works now,

some remarks

Code: [Select]
if((now - oldTime > 1000))
I would use >= 1000   
and the additional ()'s do not add anything :)


no need to
Code: [Select]
    attachInterrupt(IRQ_A, CounterIN, FALLING);
    attachInterrupt(IRQ_B, CounterOUT, FALLING); 

at the end of every loop, as you do not detach them (you shouldn't)

writing
Code: [Select]
float litersPerMinute = (1000.0 * liters)/duration;
makes explicit that the math is done in float (it is, as liters is already float, but just looking at the original line it could have been integer math)


for the readability I would group the math and the display statements in the loop, something like
Code: [Select]
void loop()
{
  unsigned long now = millis();
  if((now - oldTime >= 1000))
  {
    // TIME MATH
    unsigned long duration = now - oldTime;
    oldTime = now;

    // FLOW MATH
    liters = (countIN - countOUT);
    float litersPerMinute = (1000.0 * liters)/duration;
    int LPM = litersPerMinute;           
    pulseCount = pulseCountIN - pulseCountOUT;
    pulseCountIN = 0;
    pulseCountOUT = 0;

    flowRate = (1000.0 / duration) * pulseCount);
    unsigned int frac = (flowRate - int(flowRate))*10;

    // DISPLAY RESULTS
    Serial.println(litersPerMinute, 3);   
    Serial.print("pulseCount: ");
    Serial.print(pulseCount, DEC);
    Serial.println("  ");  // to remove trailing digit when printed on lcd iso serial
  }
}


How many pulses do the devices give per liter?


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

KapteinFredrik

#14
Dec 25, 2012, 05:55 pm Last Edit: Dec 25, 2012, 06:00 pm by KapteinFredrik Reason: 1
Thanks. I have cleaned up a bit more here, but its not perfect yet. The whole system is not accurate enough. I need the sensors to be very accurate for this project, and I think it is something inside here who makes the difference:

Code: [Select]
#define IRQ_A 0
#define IRQ_B 1
#define FlowA 2
#define FlowB 3

volatile unsigned long countIN = 0;
volatile unsigned long countOUT = 0;
unsigned long oldTime  = 0;
float flowRate;



volatile float pulseCountIN;
volatile float pulseCountOUT;
volatile float pulseCount;

float liters;

void setup()
{
  Serial.begin(57600);
 
  pulseCountIN = 0.0;
  pulseCountOUT = 0.0;
  pulseCount = 0.0;
  flowRate = 0.0;

  pinMode(FlowA, INPUT);
  pinMode(FlowB, INPUT);
  digitalWrite(FlowA, HIGH);
  digitalWrite(FlowB, HIGH);
 
  liters = 0.0;

  attachInterrupt(IRQ_A, CounterIN, FALLING);
  attachInterrupt(IRQ_B, CounterOUT, FALLING);
}

void loop()
{
  unsigned long now = millis();
  if(now - oldTime >= 1000)
  {
    unsigned long duration = now - oldTime;
    oldTime = now;

    liters = (countIN - countOUT);
    float litersPerMinute = (1000 * liters)/duration;   
    int LPM = litersPerMinute;           
   
    pulseCount = (pulseCountIN - pulseCountOUT) / 10000.0 * 3600;
       

    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount);
    unsigned int frac;
    Serial.print("Liter per time: ");
    Serial.println(pulseCount, 4);
     
    pulseCountIN = 0;
    pulseCountOUT = 0;
     
  }
}

void CounterIN()
{
  countIN++;
  pulseCountIN++;
}

void CounterOUT()
{
  countOUT++;
  pulseCountOUT++;
}


When I connect the hoses and sensors to the water faucet, the sensors gives me this: results
Liter per time: 23.4000
Liter per time: 24.1200
Liter per time: 24.8400
Liter per time: 25.2000
Liter per time: 25.5600
Liter per time: 24.8400

...and that is not what I had expected.
The engines I develop this flow meter to, uses between 3 and 50 liters per hour.

Do you understand what I have done wrong?

Cheers, Fredrik

Best regards, Fredrik

Go Up