I'd try just taking a reading every four or five seconds and then average those over maybe ten readings.
YMMV
I'd try just taking a reading every four or five seconds and then average those over maybe ten readings.
YMMV
I guess I would need to create a new integer, something like "int filtered_values = ( read distance every 5 seconds then average out every 10 readings);"
Then use this new integer "filtered_values" in the coding to light up the NeoPixels.
What would be the codes/formulas to accomplish the filtering?
I am learning Arduino slowly via online courses, but this is all new to me...
Can any one provide some example codes for the filtering?
Cheers
How could I implement the RunningMedian library (#include <RunningMedian.h>) to my sketch?
Install the library from the library manager then add
#include <RunningMedian.h>
at the top of your sketch. See library docs for usage.
Yes, I did this, but not sure on how to implement the codes in my sketch...
Still searching..
Ok I think I got it this time, seem to work perfectly according to serial outputs...
When placing the sensor on top of a bottle of water, I can shake the bottle to simulate gas moving inside the tank and serial outputs show a very linear readouts, taking a second or two to update the outputs ... "RunningMedian distance = RunningMedian(50);"
Here is the sketch that I will try on the tractor:
/* This example shows how to use continuous mode to take
range measurements with the 6 pin VL53L0X module. It is based on
vl53l0x_ContinuousRanging_Example.c from the VL53L0X API.
The range readings are in units of mm.
Original source: https://github.com/adafruit/Adafruit_VL53L0X
Modified by Ahmad Shamshiri for RoboJax.com
Date modified: May 31, 2018 at 19:25 at Ajax, Ontario, Canada
Watch the instruciton video for this code https://youtu.be/S2jaAQEv3Yo
Pin connection
VL53L0X Pin Arduino Pin
VCC 5V
GND GND
SDA A4 or SDA if available
SCL A5 or SCL if available
GPIO1 leave it unconnected
XSHUT D12 (digital 12 or pin 12)
*/
#include <Wire.h>
#include <VL53L0X.h>
#include <Adafruit_NeoPixel.h>
#include <RunningMedian.h>
VL53L0X sensor;
RunningMedian distance = RunningMedian(50);
#define PIN A0 // // WS2812 chip - Data In
#define Pixel_Number 16
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixel_Number, PIN, NEO_GRB + NEO_KHZ800);
void updateStrip(int ledsToLight, uint32_t colorOn, uint32_t colorOff){
for(int x = 0; x < Pixel_Number; x++){
if(x < ledsToLight) {
strip.setPixelColor(x, colorOn);
} else {
strip.setPixelColor(x, colorOff);
}
}
strip.show();
}
struct Level {
int ledsToLight;
uint32_t color;
};
#define max_colors 3
Level colors[max_colors] = {
{3, strip.Color(255,0,0)},
{5, strip.Color(255,128,0)},
{16, strip.Color(0,255,0)},
};
uint32_t getColor(int ledsToLight){
uint32_t ret = strip.Color(0,0,255);
for(int x = 0; x < max_colors; x++){
if (ledsToLight <= colors[x].ledsToLight){
ret = colors[x].color;
break;
}
}
return ret;
}
void setup()
{
pinMode(12,INPUT_PULLUP);
digitalWrite(12,HIGH);
strip.begin();
Serial.begin(9600);
Wire.begin();
sensor.init();
sensor.setTimeout(500);
// Start continuous back-to-back mode (take readings as
// fast as possible). To use continuous timed mode
// instead, provide a desired inter-measurement period in
// ms (e.g. sensor.startContinuous(100)).
sensor.startContinuous();
}
void loop()
{
// This is to Filter Noise and jumping readouts from the sensor to provide linear outputs
int range = sensor.readRangeContinuousMillimeters();
distance.add(range);
range = distance.getMedian();
range = range -55; // This is to calibrate the sensor so it read 0 when set on flat surface
Serial.print("Distance: ");
Serial.print(range);
Serial.print("mm");
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
Serial.println();
delay(100);
int ledsToLight = 0;
int distancetotop = ( range );
if(distancetotop < 60 ) {ledsToLight = 16;}
else if(distancetotop > 60 && distancetotop < 72 ) {ledsToLight = 15;}
else if(distancetotop > 72 && distancetotop < 84 ) {ledsToLight = 14;}
else if(distancetotop > 84 && distancetotop < 96 ) {ledsToLight = 13;}
else if(distancetotop > 96 && distancetotop < 108 ) {ledsToLight = 12;}
else if(distancetotop > 108 && distancetotop < 120 ) {ledsToLight = 11;}
else if(distancetotop > 120 && distancetotop < 132 ) {ledsToLight = 10;}
else if(distancetotop > 132 && distancetotop < 144 ) {ledsToLight = 9;}
else if(distancetotop > 144 && distancetotop < 156 ) {ledsToLight = 8;}
else if(distancetotop > 156 && distancetotop < 168 ) {ledsToLight = 7;}
else if(distancetotop > 168 && distancetotop < 180 ) {ledsToLight = 6;}
else if(distancetotop > 180 && distancetotop < 192 ) {ledsToLight = 5;}
else if(distancetotop > 192 && distancetotop < 204 ) {ledsToLight = 4;}
else if(distancetotop > 204 && distancetotop < 216 ) {ledsToLight = 3;}
else if(distancetotop > 216 && distancetotop < 228 ) {ledsToLight = 2;}
else if(distancetotop > 228 && distancetotop < 240 ) {ledsToLight = 1;}
else if(distancetotop > 240 ) {ledsToLight = 0;}
if (ledsToLight == 0) {
doFlash();
} else {
auto colorOff = strip.Color(0,0,0);
auto colorOn = getColor(ledsToLight);
updateStrip(ledsToLight, colorOn, colorOff);
}
}
void doFlash(){
auto color = strip.Color(0,0,0);
if((millis() / 540) & 1 != 0){
color = strip.Color(255,0,0);
}
for (int x = 0; x < Pixel_Number; x++){
strip.setPixelColor(x, color);
}
strip.show();
}
I will confirm it all of this is working in real life...
Cheers
OK, even if my setup was working perfectly on the bench, I found out the Laser VL53L0X module is not a good working solution to detect gas levels after testing my setup on the tractor fuel tank, probably because of the irregular shape of the shallow gas tank (approx 8" deep) and light not being reflected by gasoline due sensor not hitting gasoline at a perpendicular angle.
I did some more research and discovered that the best way to accomplish this would be to use a Digital Barometric Pressure Sensor Module connected to a small tube that would go all the way to the bottom of the tank.
I just ordered a couple of these modules:
Then will attach a small tube with a weight at the end so it sits on the bottom of the tank.
I will install the sensor inside the gas cap and seal it with UV epoxy resin after testing that everything is working as it should.
Here is a video showing the sensor working for this purpose:
Another one here:
Cheers,
How long do you think the air in the tube will hold that pressure before it equalises.
How long do you think a dry-air sensor will last with diesel fumes.
What sensor with the brown wire is that on top of your tank.
Isn't it easier to just drill a hole on top of the tank, and install a float sensor.
You might one with a short range in a scooter shop.
Leo..
The sensor with brown wire that I was using was a laser type sensor VL53L0X TOF200C.
Because the sensor is installed inside the fuel cap and that the fuel filler neck on the tank is at an angle, the laser is hitting the gas surface at an angle rendering readouts unusable.
Regarding the pressure sensor...
The air in the tube will hold the pressure and should never equalize (if properly sealed).
Also, it's mostly air that will be inside the tube, not gasoline fumes, as the tube will sit at the bottom of the tank. No fumes at the bottom of the tank when gas in the tank as fumes form on top of gasoline.
I read in forums people using pressure sensors to measure heating oil with great success...
I only paid $16 CAD for 3 of those Barometric Pressure Sensor Module on Amazon, so no big deal if one fail...
The reason that I can't use a normal Float Fuel Tank Sending Unit like the one used in cars, is that I would need to remove the cab on top of the tractor, then remove the tractor fender deck to access the top of the tank. This would be laborious.
I will try it, if it works, great, if not, oh well...
Cheers
I asked about the sensor on top of the tank, image post#30.
Wishful thinking. I like that.
There are also fuel pressure sensor for in the fuel line (click).
Leo..
Ok, sensor (switch) on top of the tank, image post#30 is for a low gas level light on the dash, it turn on when gas is below a certain level.
The inline fuel pressure sensor for fuel line you linked is interesting, but a bit pricey.
It also work with pressure caused by liquid level in the tank, so basically the same thing that I should be able to accomplish with my arduino setup.
Cheers
Not really.
The air in between could make the sender dependent on temp, absorption and leaks.
I think you should use a HX710 library for this sensor.
Look through the library manager.
Leo..
Thanks for the heads up...
I think the inline fuel pressure sensor for fuel line you linked is also measuring air pressure relative to atmospheric pressure. Gasoline never come in contact with the sensor as I understand from this video:
Anyhow, great solution for bikes...
Cheers
That video is only for a quick test.
In the application notes you find that the sensor is mounted under the fuel tank.
Interesting project. Keep us updated.
Leo..
I don't know how it's done these days but, I used to have a washing machine with a water level sensor like that. Tube closed at the top with mechanical pressure switch mounted. Outlasted the transmission.
Ok so I guess the sensor measure the pressure caused by a liquid, and not by air...
Either way, it 's a pressure sensor.
Yes I will update this thread whenever I receive the sensors in a few days...
Cheers
I used to have a washing machine with a water level sensor like that. Tube closed at the top with mechanical pressure switch mounted.
The tube is emptied between and after every wash, so minor leaks are not a problem.
Leo..
The gas tank on the tractor is 17L (4.5 gal) and will run the tractor for about 4.5 to 5 hours, after that, I need to refuel.
So, I'm not too worry about minute deviation the fuel gauge could or will show due to variation in temperature and/or atmospheric pressure affecting the maybe 2 or 3 cubic millilitre of air contained inside the 8" of tube, as I will need to refuel after a couple hours of uses, introducing brand new air in the tube on every refill.
Off course I should expect the gauge to show improper fuel level after the tractor is being parked for 8 months or so in the summer time when it's not being used.
I guess the only way to find out is to try it, If it works, great, if not, well I would have learn something doing projects with Arduino, as this is all new to me.
I will let you guys know if it is a success, or a bust...
Cheers
Ok playing with the sketch using the HX710B library, this is what I came up with so far, to incorporate the sensor to my previous code:
However, how do I get the raw data from the pressure sensor to be read in the integer
int brpressure = ( ??? );
#include <Wire.h>
#include <HX710B.h>
#define SCK_PIN 3
#define SDI_PIN 4
HX710B air_press(SCK_PIN, SDI_PIN);
#include <Adafruit_NeoPixel.h>
#include <RunningMedian.h>
HX710B sensor;
RunningMedian distance = RunningMedian(4); // Higher the number, the more filtering it will have
#define PIN A0 // // WS2812 chip - Data In
#define Pixel_Number 16
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixel_Number, PIN, NEO_GRB + NEO_KHZ800);
void updateStrip(int ledsToLight, uint32_t colorOn, uint32_t colorOff){
for(int x = 0; x < Pixel_Number; x++){
if(x < ledsToLight) {
strip.setPixelColor(x, colorOn);
} else {
strip.setPixelColor(x, colorOff);
}
}
strip.show();
}
struct Level {
int ledsToLight;
uint32_t color;
};
#define max_colors 3
Level colors[max_colors] = {
{3, strip.Color(255,0,0)},
{5, strip.Color(255,128,0)},
{16, strip.Color(0,255,0)},
};
uint32_t getColor(int ledsToLight){
uint32_t ret = strip.Color(0,0,255);
for(int x = 0; x < max_colors; x++){
if (ledsToLight <= colors[x].ledsToLight){
ret = colors[x].color;
break;
}
}
return ret;
}
void setup()
{
pinMode(12,INPUT_PULLUP);
digitalWrite(12,HIGH);
strip.begin();
Wire.begin();
Serial.begin(115200);
if ( !air_press.init() )
{
Serial.println(F("HX710B not Found !"));
while(1);
}
}
uint32_t time_update = 0;
void loop()
{
uint32_t rollOver = millis();
if( rollOver < time_update )
time_update = rollOver;
if( millis() - time_update >= 2000UL )
{
uint32_t data_raw = 0;
if ( air_press.read(&data_raw, 1000UL) != HX710B_OK )
Serial.println(F("something error !"));
else
{
Serial.print(F("Data raw of ADC is : "));
Serial.println((unsigned long) data_raw);
}
time_update = millis();
}
}
int ledsToLight = 0;
int brpressure = ( ??? );
if(brpressure < 60 ) {ledsToLight = 16; Serial.print("Volume: "); Serial.print("FULL ");}
else if(brpressure > 60 && brpressure < 72 ) {ledsToLight = 15; Serial.print("Volume: "); Serial.print("16"); Serial.print("L");}
else if(brpressure > 72 && brpressure < 84 ) {ledsToLight = 14; Serial.print("Volume: "); Serial.print("15"); Serial.print("L");}
else if(brpressure > 84 && brpressure < 96 ) {ledsToLight = 13; Serial.print("Volume: "); Serial.print("14"); Serial.print("L");}
else if(brpressure > 96 && brpressure < 108 ) {ledsToLight = 12; Serial.print("Volume: "); Serial.print("13"); Serial.print("L");}
else if(brpressure > 108 && brpressure < 120 ) {ledsToLight = 11; Serial.print("Volume: "); Serial.print("12"); Serial.print("L");}
else if(brpressure > 120 && brpressure < 132 ) {ledsToLight = 10; Serial.print("Volume: "); Serial.print("11"); Serial.print("L");}
else if(brpressure > 132 && brpressure < 144 ) {ledsToLight = 9; Serial.print("Volume: "); Serial.print("10"); Serial.print("L");}
else if(brpressure > 144 && brpressure < 156 ) {ledsToLight = 8; Serial.print("Volume: "); Serial.print("9"); Serial.print("L");}
else if(brpressure > 156 && brpressure < 168 ) {ledsToLight = 7; Serial.print("Volume: "); Serial.print("8"); Serial.print("L");}
else if(brpressure > 168 && brpressure < 180 ) {ledsToLight = 6; Serial.print("Volume: "); Serial.print("7"); Serial.print("L");}
else if(brpressure > 180 && brpressure < 192 ) {ledsToLight = 5; Serial.print("Volume: "); Serial.print("6"); Serial.print("L");}
else if(brpressure > 192 && brpressure < 204 ) {ledsToLight = 4; Serial.print("Volume: "); Serial.print("5"); Serial.print("L");}
else if(brpressure > 204 && brpressure < 216 ) {ledsToLight = 3; Serial.print("Volume: "); Serial.print("4"); Serial.print("L");}
else if(brpressure > 216 && brpressure < 228 ) {ledsToLight = 2; Serial.print("Volume: "); Serial.print("3"); Serial.print("L");}
else if(brpressure > 228 && brpressure < 240 ) {ledsToLight = 1; Serial.print("Volume: "); Serial.print("2"); Serial.print("L");}
else if(brpressure > 240 ) {ledsToLight = 0; Serial.print("Volume: "); Serial.print(" EMPTY ");}
if (ledsToLight == 0) {
doFlash();
} else {
auto colorOff = strip.Color(0,0,0);
auto colorOn = getColor(ledsToLight);
updateStrip(ledsToLight, colorOn, colorOff);
}
}
void doFlash(){
auto color = strip.Color(0,0,0);
if((millis() / 540) & 1 != 0){
color = strip.Color(255,0,0);
}
for (int x = 0; x < Pixel_Number; x++){
strip.setPixelColor(x, color);
}
strip.show();
}
Getting "cannot convert 'HX710B' to 'int' in initialization" when compiling the sketch...
Still learning this stuff...
Any help would be appreciated.
Cheers
Maybe you're biting off more than you can chew.
Start with simple code for only the HX711.
See what values you get printed without pressure, and with the hose 25cm in water.
If you get consistent values that make sense, then try to add the smoothing code.
And test again.
If that works, then convert those numbers to LED numbers.
The code I posted in post#38 seems a lot easier for that than those if/else blocks...
When you have LED numbers printed, then add the LED strip.
Leo..