A wireless Fuel Tank monitor

I saw an excellent write-up on how to monitor fuel levels in an oil tank using ultrasonic sensors over on hackaday.  In his blog, alaskanshade details how he used Arduino and an ultrasonic sensor to log the data and measure fuel levels.  I really like the idea of monitoring fuel levels using this setup, so I had to give it a try.  I also wanted to incorporate the following design goals:

  1. Perform all-wireless data acquisition
  2. Ability to see current fuel level on the internet/web-page
  3. Log all data to a sql database/web-server using deviceLogger
  4. Battery life should last a long time, at least six months without having to change batteries

Forgive my lack of drawing skills, here is a diagram of the whole system:

deviceLogger system

In a nutshell, the process works like this:

  1. The sending unit pings the tank with the ultrasonic sensor and calculates the gallons (see attached gist for code, I found some code online that I adapted for use here. I’d give credit, but I can’t remember which site(s?) I found it on anymore)
  2. The entire system shuts down using the excellent LowPower library for Arduino.  After about one minute, it wakes back up and does another measurement.  After 15 measurements/minutes we send the current running median (another great Arduino Library) of the measurements. At this point, the whole process repeats.
  3. On the receiving end, there is an Arduino with an nrf24l01 module and ethernet shield (see my previous post on getting these two to work together if needed).  The receiver publishes some text/xml to a web page.
  4. The deviceLogger reader script periodically checks this page for new data.  It then writes the data to a mySQL database.  The deviceLogger php application then serves up the graphs and current data.

I ended up using one of my protoBoard pcbs on this project, and it worked out very well.  It fit perfectly in the 2″ pvc that I used to build the sensor housing.  Here’s some images from the build:

This shows a 4-AA battery holder, but I've since swapped it out for a 3-AA holder
The complete setup, all components. I later switched to a 3-AAA holder instead.


tank reader protoboard
This is a custom PCB I call a protoBoard. It basically just maps most of the atmega328’s pins to solder pads/screw-term pads.
You can see the snoot that was added to avoid the ‘multipathing’ issues that I experienced previously. Works great!
The ultrasonic sensor at the bottom of the unit.
PVC sheet cut to shape for bottom of the sending unit (You can find this material at a sign-supply shop)
Bottom of the unit with 1/2″ PVC installed for snoot.
Everything fit inside the 2″ PVC easily.
Top cap is just a slip fitting. I suppose you could use screw-on version if you cared to.

tankReader4 tankReader2

Sending unit uses 2" PVC to connect to tank.
Sending unit installed on tank.

Sending unit installed on tank

One thing that I noticed in the course of this project was that I was getting some strange readings from time to time, and sometimes readings would just be completely off from what I knew to be the current tank depth.  I had a theory that some of the erroneous readings may have been caused by multiple echoes bouncing off of the many internal facets of the tank (multipathing).  I decided to try adding a ‘snoot’ of 1/2″ pvc pipe to the end of the ultrasonic sensor to better guide the send signal towards the surface I actually wanted to measure (the fuel sitting at rest in the tank).  This seems to work very well.  Once I placed the snoot on the sensor, I immediately began receiving good readings without error.  I do still have some bad-value rejection and median-smoothing in the Arduino sketch though.  And as you can see from the screenshots, I still get fluctuations in the ultrasonic readings that work out to about a +/- 1 gallon level of accuracy over the course of a day:

This is the summary screen on deviceLogger
This is the summary screen on deviceLogger


You can see that there is still some fluctuation in readings even when rejecting bad values and median-smoothing
You can see that there is still some fluctuation in readings even when rejecting bad values and median-smoothing. I think to expect anything more would be a little unreasonable for a sensor that cost about $1.25

I also made a few modifications to the newPing library settings that changed the amount of time delay between pings on the ping_median() method.  This was done because the aforementioned multipathing/echo issues seem to present themselves once again if you don’t wait long enough between pings.  I adjusted the time from 29ms up to 1000ms.

As mentioned above, the sketch also uses the excellent LowPower library.  I used LowPower to power down the Atmega328 for about a minute at a time between readings.    This should allow the three AAA batteries to last about one year before needing to be replaced.

If you want to use this code, but have a different sized tank, you should be able to adjust the values for variables ‘tankHeight, tankWidth, and tankLength’.  As long as your tank maintains standard ob-round dimensions/shape, it should work fine.

Here’s the sketches: