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.
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
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.
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
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
*/
}
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
#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++;
}
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
This is my last version of the sketch, and now it works! Thanks so much for your help I will keep developing this sketch to work more properly. I added two more volatile bytes, because the first sketch did not work.
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
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
}
}
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:
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.
The fact that you get ~24 Liter means that the incounter get far more pulses than the outcounter. This makes sense as the device consumes fuel.
About Accuracy
The minimum consumption it can detect is one pulse. If you measure a delta of 1 pulse per second it equals a difference of 1/10000*3600 = 0.36L
Look at your measurements
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 you see the delta's between the measurements are 0.36 or 0.72. That is one or two pulses difference.
The best way to have a better accuracy is to measure the fuel-consumption over the last minute * 60. A delta of 1 pulse will result in a delta of 0.006 L
The best way to do this is to make measurements per second and use them to fill a circular buffer of 60 elements.
I Tried this sketch with my sensors, but one of them shows something like 100 times higher value than the other(about 700 liters per secund). It does not seems that the subtraction function works either as it did before.
What happens if you switch the lines ?
just to test if this happens in the sensor/wiring or in the software?
100 times higher could mean more noise on the line, which is seen as pulses for the interrupt handler. (Or leakage?)
Is the factor a constant or irregular?. If it is a constant (exact 100x) you might just have 2 different devices !
If it is irregular it looks more like noise.
You can add this modification to the sketch to remove the noise. It ignores pulses that are too short after each other.
Be aware that micros() returns multiples of 4. So testing with 8,9,10,11 give the same behaviour.
void CounterIN()
{
static unsigned long lastTime = 0;
if (micros() - lastTime > 10) // to be adjusted
{
lastTime = micros();
countIN++;
}
}
void CounterOUT()
{
static unsigned long lastTime = 0;
if (micros() - lastTime > 10)
{
lastTime = micros();
countOUT++;
}
}