After Jeff replaced his home heating oil tank a few years ago, he regretted not having a mechanical gauge put in the tank. But that gave him a reason for this new project. In this article, Jeff describes how he conceived and built a system to measure how much oil was left in his tank. It uses Arduino, ultrasonic sensors and a smartphone app.
One of my chores as a lad was filling the kerosene heaters in our house. We could get kerosene delivered to our 55-gallon drums in the basement, but I’d have to lug the heater tanks down to the cellar to refill them. I never paid any mind to running out, since there always seemed to be kerosene available. We had two drums, so I guess my dad just bought more whenever we swapped an empty tank for a full one.
Not many households that I know of use kerosene any more. The other options—electricity, oil and natural gas/propane—now all share in the total energy needs of our nation. While coal has also been widely used (my family’s second home had a coal bin and ash pit), we are beginning to phase out those fuels that are the most environmentally unfriendly. Nuclear energy became a big player while I was child. I can remember talk of every family having their own mini nuclear plant in their home. That was also at a time of potential of nuclear war. While we are still at risk of this from some fanatical group, most countries understand this to be a no-win situation.
Today, green energy, such as solar, wind and hydro, have given us a new view of our potential future. Getting there is not an easy road, and many, including myself, are still dependent on oil and other fossil fuels. While my furnace might be highly efficient, it still requires its oil reserves to be constantly replenished. There was a time when every oil tank had a fuel gauge on it. It was up to you to monitor the tank and call for an oil delivery whenever it got low. Today, many delivery companies use the “degree day” to calculate when you will need a delivery, and automatically plan for it—provided that your account is up to date.
DEGREE DAYS
Degree days are measures of how cold or warm a location is, referenced to a standard temperature—usually 65°F (Figure 1). The more extreme the outside temperature, the higher the number of degree days. Degree days are separated by days when the average daily temperature is above and below norm. Cooling Degree Days are required when temperatures are warmer than 65° (CDD65) and Heating Degree Days when temperatures are less than 65° (HDD65). Individual degree days tell us how much warmer or colder the day has been from a normal of 65°. During those times of the year when the temperature drops below normal, HDD65 indicates how much energy in the form of heating is required to bring our indoor temperature up to the norm. During those times of the year when the temperature rises above normal, CDD65 indicates how much energy is required in the form of cooling to bring our indoor temperature down to the norm. This is all an attempt to keep our living environment at a particular comfortable level.

We can calculate the energy we will need to do this based on our living space’s size, insulation factors and fuel type. However, you can easily determine this by monitoring your fuel consumption for a period of time (while maintaining said norm of 65°), and dividing the energy used by the total degree days for that period. Let’s say, for example, the last 30 days the outside temperature was freezing: 32°F. That’s 65° – 32° = 43° × 30 days or 1290HDD65. If you used 100 gallons of fuel oil for that period, 100 gallons/1290HDD65 = 0.08 gallons/HDD65 (each degree day). Now by keeping track of the accumulated (Heating) Degree Days, you could predict your oil usage and know when it was time to fill your tank.
I had my oil tank replaced a few years ago. It was previously buried in the ground. I had just added on to my basement area and, with the extra space, I had a standing tank put inside. I didn’t think of it at the time and didn’t ask to have a mechanical gauge put into the tank. While I regret that now, it did give me reason for this project.
— ADVERTISMENT—
—Advertise Here—
TANK OIL LEVEL
Since one of my super powers isn’t x-ray vision, I needed a way to see inside this oil tank. While the UL label is on the side of my oil tank, inconveniently located against a wall, it still had a paper label with the product #204201 written on it. A quick search of that number led me to Granby Industries, a maker of steel and fiberglass storage tanks. According to its online PDF of that tank, it was spec’d out at 275 gallons. Using the dimensions given, I wanted to verify the tank’s volume. A quick calculation is shown in Figure 2. My calculations are based on using regular shapes. I thought I might be a bit on the high side using the exterior dimensions on the print. However, it looks as though my calculations are about 2% under. Close enough.

FIGURE 2 – I used the tank specs to figure out its volume. The tank’s shape is divided into three segments—two half barrels and a rectangular segment. Keeping the segments simple makes for simple calculations.
For measurement purposes, I’ll be using ultrasonic acoustic measurement. While most ultrasonics I’ve used have been transmitter/receiver pairs, I located a circuit that uses a single-sealed transceiver for $11. This is similar to the devices found on today’s car bumpers used for presence alarms. Since I didn’t have a spare oil tank hanging around, I needed to verify how it operates within the dimensions of the tank. I needed to mock up an actual-sized tank using some cardboard—lots of cardboard.
After rounding up a number of large corrugated cardboard cartons, I proceeded to mock-up a full-sized tank according to the specs I had downloaded. With one bunghole free on the left end of the tank, I needed to know if the ultrasonics would reach the bottom of the tank without interference from the sides or the end of the tank.
As you can see from the photo in Figure 3, the tank model has a fairly open top design, such that I could reach into the interior easily. A couple of wooden rails at the top hold up the movable band that will hold the sensor. Being able to slide this band along the length of the tank allowed me to position the sensor for testing. I was able to receive echoes from the 44″ bottom of the tank with the sensor set at the first bung hole position. I also placed a 1′ cardboard surface at various heights under the sensor, and was able to get some accurate distance measurements. The time and effort to test the instrumentation was important to prove the viability of the idea.

ACOUSTIC TIME OF FLIGHT
The ability of the ultrasonic system to measure distance has to do with measuring the time of flight for an acoustic signal. Upon request, the system sends out a 40kHz burst via an ultrasonic transmitter, and if an object is within the path, an echo bounces back to the ultrasonic receiver. Ultrasonic systems may use a single transceiver or separate transmitter receivers to measure this. When a transmitter has been pulsed, there is a tendency for the transmitting element to continue ringing for a short period of time. Therefore, in a single-transceiver system, the transmitting device must be given a bit of time to stop all vibrations, since these may be seen as a reflection.
A single-transceiver system will therefore have some minimum time (distance) before its transceiver is enabled for receiving echoes. The system I am using has a minimum distance measurement due to this delay. If a separate transmitter and receiver are used, the receiver will never be excited during the transmission period, and therefore the receiver is ready immediately to listen for echoes. These systems have a minimal delay.
I’ll be putting up with this inherent disadvantage, because the physical mounting limitations in a single bunghole require using a single-transceiver system. As mentioned previously, the sensor is similar to those found in car bumpers. It comes sealed into plastic mounting hardware that pops into a hole. This allows it to easily mount into a bunghole cap that has a hole of the proper size in it (Figure 4).

The ultrasonic circuitry has four connections: power, ground, INIT and ECHO. If you bring the INIT line high for greater than 10µs, then the circuitry will send out a burst of 40kHz. The ECHO pin goes high and remains high until the echo pulse has been received. If you measure the width of the pulse, you can calculate the distance to the object (time of flight).
Physics tells us that sound passes through air at a speed of approximately 767mph or 13,500in./s. This means that it travels about 0.34mm/µs. Since a burst must travel twice the distance to an object (out and back), distance to an object is half that (d=0.34mm/2µs.) If we can measure this in microseconds, we can estimate distance to within a millimeter.
— ADVERTISMENT—
—Advertise Here—
1SHEELD FOR ANDROID AND iOS
As usual, I try to incorporate several different elements into each project. I’m not sure where I first saw 1Sheeld, a shield board for the Arduino, since it’s been around for about 5 years. It sounded like a different approach and I like unique products, so I bought one for under $30. The 1Sheeld is a peripheral board that mounts atop any Arduino processor board. It contains a Bluetooth module (HM-10–BTE4.0) and a Microchip Technology ATMEGA162 8-bit microcontroller (MCU). The processor is preprogrammed with its own operating system, if you will, that can link up with a smartphone and gives the user access via UART.
When plugged onto an Arduino, it ties its UART to the Arduino’s UART. This hardware connection must be disconnected via an on-board switch, when you need to program a sketch into the Arduino. Once the sketch has been programmed, you flip the switch and your sketch talks to the 1Sheeld via the UART connection. Alternately (when the switch isolates the 1Sheeld’s TX/RX pins from the Arduino header), you can jumper these to alternate serial pins on the Arduino header (D5-D13). Your sketch can then talk to 1Sheeld via an alternate software serial port and avoid the hardware contention described above. I used the hardware port connection for this project.
The 1Sheeld is loaded with the code not only to handle the connection to your smartphone but also to take advantage of all of the supported phone peripherals. Table 1 contains a list of the peripherals that are supported on the Android App. Note that I’m calling these (phone) “peripherals,” even though 1Sheeld calls them “sheelds.” I found that confusing, because the piggyback hardware board is called the 1Sheeld (OneSheeld). Note that your particular phone must support the peripheral for that device to work with the app.

Unless you write your own peripherals driver, each peripheral you use with the Arduino has a supporting library. Even though 1Sheeld has all its support code within the processor on board, an Arduino library must be installed to use 1Sheeld. It has the communication routines needed to talk with the 1Sheeld processor. Like most libraries, this requires an include
statement.
#include <OneSheeld.h>
Now you are open to using any of the support routines, including those in Listing 1.
OneSheeld.begin();
OneSheeld.isAppConnected();
OneSheeld.waitForAppConnection();
OneSheeld.delay(unsigned long);
OneSheeld.isCallbacksInterruptsSet();
OneSheeld.enableCallbacksInterrupts();
OneSheeld.disableCallbacksInterrupts();
OneSheeld.setOnSelected(void (*userFunction)(void);
LISTING 1 – 1Sheeld support routines
By default, the compiler will attempt to add support for every 1Sheeld peripheral to your sketch. While the support libraries for each peripheral are already in the 1sheeld’s preprogrammed processor, some supporting functions will be compiled into your sketch for every peripheral used. It only makes sense for you to limit these by specifically including only those that you are using. I’m going to use two of these peripherals for this project. First, the Terminal peripheral will display the actual distance measurements of the ultrasonic sensor. I use this as a debug tool to verify measurements. Second, the Text-to-Speech peripheral is the end product of this project: an audio message of oil reserves!
MEASURING WITH ULTRASONICS
As mentioned earlier, most Arduino sketches begin with some basic definitions. As shown in Listing 2, we include the libraries required, the ultrasonic sensor connections we will make, some predefined constants and a couple of variables. From the TankCapacity
, EmptyDistance
(inside height of the oil tank) and the FullDistance
(minimum distance that the sensor can measure), the MMPerGallon
can be calculated. This is the number that will let us calculate the remaining oil reserves. This works out to:
Note that this is forced to be a floating-point number by including a floating-point term (1.00) in the equation.
/* defines for 1Sheeld. to limit space used by 1Sheeld*/
#define CUSTOM_SETTINGS
#define INCLUDE_TERMINAL_SHIELD
#define INCLUDE_TEXT_TO_SPEECH_SHIELD
/* Include 1Sheeld library. */
#include <OneSheeld.h>
/* Define pins for the ultrasonic sensor */
const int trigPin = 9;
const int echoPin = 10;
/* User constants */
const int TankCapacity = 275; // capacity of the tank in gallons
const int EmptyDistance = 1118; // (mm) 44 inches inside height of the tank
const int FullDistance = 180; // (mm) 7 inches minimum distance reported
const float MMPerGallon = (EmptyDistance-FullDistance)*1.00/TankCapacity
/* Variables used to save the results */
int distance; // (mm) reported distance to oil surface
int GallonsRemaining; // oil reserves based on reported distance
LISTING 2 – Here we include the libraries required, the ultrasonic sensor connections we will make, some predefined constants and a couple of variables.
With the basic requirements satisfied, we can add the two required functions for an Arduino sketch (Listing 3). The setup()
function will initialize the necessary I/O (for the sensor) and the 1Sheeld support functions. The loop()
function handles all the processing that will be repeated in a forever loop. This is basically a call to the ultrasonic function to get a distance measurement, calculate the gallons of oil in reserve, send the debug data to the Terminal peripheral and create a text string to send to the Text-to-Speech peripheral.
void setup()
{
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
/* Start 1Sheeld communication. */
OneSheeld.begin();
}
//
void loop()
{
/* Get the current distance from the ultrasonic */
distance = getUltrasonicDistance();
if(distance>EmptyDistance)
{
distance=EmptyDistance;
}
if(distance<FullDistance)
{
distance=FullDistance;
}
GallonsRemaining = (EmptyDistance-distance) / MMPerGallon;
/* Print the distance on the Terminal shield */
Terminal.println(String(distance) + "mm = " + String(GallonsRemaining) + "gallons of oil reserve");
//
String command = "your " + String(TankCapacity) + " gallon oil tank has " + String(GallonsRemaining) + " gallons remaining";
/* Use text-to-speech shield to announce the tank contents orally */
TextToSpeech.say(command);
/* Delay for 5 seconds to give the camera shield enough time for taking and saving the photo */
OneSheeld.delay(5000);
}
— ADVERTISMENT—
—Advertise Here—
LISTING 3 – The setup() function initializes the necessary I/O (for the sensor) and the 1Sheeld support functions. The loop() function handles all the processing that will be repeated in a forever loop.
Finally, let’s look at the last function—retrieving a distance from the ultrasonic sensor (Listing 4). The INIT pin is raised to a logic 1, we wait a delay of 10µs and then lower the INIT pin to logic 0. This gets the sensor transmitting a short burst of 40kHz pulses. The ECHO pin creates high pulse with a duration corresponding to the time of flight for the echoed transmission burst. This high period, t(µs), can be measured with the pulseIn()
command. The distance d(mm) is then calculated using the formula:
/* A function that operates the ultrasonic and returns a reflected distance in mm */
int getUltrasonicDistance(void)
{
/* Variable to save the sound wave travel time in microseconds */
int duration;
/* Variable to save the detected distance in cm */
int distanceReturned;
/* Clocks the trigPin */
digitalWrite(trigPin, LOW); // should already be low
/* delay 2 micro seconds */
delayMicroseconds(2);
/* Sets the trigPin on HIGH state for 10 micro seconds */
digitalWrite(trigPin, HIGH);
/* delay 10 micro seconds */
delayMicroseconds(10);
/* Sets the trigPin on LOW state */
digitalWrite(trigPin, LOW);
/* Reads the echoPin, returns the sound wave travel time in microseconds */
duration = pulseIn(echoPin, HIGH);
/* Calculating the distance */
distanceReturned = duration * 0.34 / 2;
/* Returning the detected distance in mm */
return distanceReturned;
}
LISTING 4 – This function operates the ultrasonic and returns a reflected distance in millimeters.
You may have noticed a few minor issues with the calculations here. My initial tank volume calculations took into account tank shape, whereas my calculations for oil reserves are based on a square tank—with linear volume/distance calculations. This could be made more accurate by determining the volume of oil reserves based on the distance when it falls into the upper and lower barrel-shaped regions. In reality, the decrease in oil level is nonlinear in both the upper and lower half-cylinder areas, so they should be calculated separately. For instructional purposes, I left this calculation simple.
1SHEELD APP
So, what is the 1Sheeld phone app? The apps supplied by 1Sheeld for either Android and iOS allow the 1Sheeld hardware access to the peripherals on a smartphone. For this project and all those sketches that use 1Sheeld, your connection to the project hardware is through a Bluetooth link made between 1Sheeld hardware and the phone app. When you open the 1Sheeld application, you are prompted to scan for Bluetooth transmitters in the area. Mine shows up as 1Sheeld#99.
The application lists all the peripherals available in the library (see Table 1 again). To the right of each is a selection button, which will enable the function if it is supported by your phone. My Motorola G5+ does not support three of the peripherals in Table 1: Temperature, NFC and Pressure. Once you’ve selected those peripherals used in your sketch, you can tap on the triple 1Sheeld outline icon to go to a list of those selected peripherals. Tap on Terminal to bring up the Terminal peripheral. Figure 5 shows this screen displaying distance measurements. You have the option of time-stamping the data as it is being received.

The distance measurements seem to be correct, so let’s turn off the Terminal peripheral and enable the Text-to-Speech peripheral. Immediately, you should begin to hear a message informing you of the tank’s status similar to: “Your 275-gallon oil tank has 72 gallons remaining.” This message is repeated every 5 seconds. You can change the delay in the sketch, or you could enable the Push Button peripheral in the phone and then test for this in the sketch. This would create a button you could press to get an audio message on request. If your mind is anything like mine, it is beginning to run amok with other ways of using the 1Sheeld.
CLOSING THOUGHTS
It is convenient to use the ultrasonic sensor to measure something that is normally hidden from view. The sealed nature of this sensor makes it great for use in dirty environmental conditions. There is also a hazard of using electrical equipment, which can produce a spark, around flammable liquids. This sensor covers these bases quite nicely. I already have another home project I want to use this sensor on. It seems to work very well. I also want to try out the other modes available on this sensor.
The ultrasonic module, along with the Arduino, 1Sheeld and a small prototyping board to make the four connections necessary for the ultrasonic module, fit fairly well into a 3ple Decker Case for Arduino with only minor modifications (Figure 6). The 1Sheeld is an interesting piggyback board for the Arduino. You can wire this up to other MCUs as well, using just power, ground, TX and RX. All that’s necessary is to look at github.com/Integreight/1Sheeld-Firmware website [1] to see how you make use of the preprogrammed library. You can find some examples on www.1sheeld.com [2]. The phone application can also do an OTA (over the air) update of the preprogrammed library. There haven’t been any updates since April 10, 2016 (V1.6) and many links on the site—such as the Forum—seem to be broken. This is a bit disconcerting.

The app is meant to give the user a playground in which to investigate use of the 1Sheeld board. It has some drawbacks—mainly you get single use of the peripherals. This means you can’t add multiple buttons, LEDs or seven-segment display characters. If you wish to use more than one in an application, you must design your own using the available Android SDK. I’m not sure I want to develop my own app for every little project I make. But, for some things, you’ll find this app is all you need. As always, too much to do, so little time.
RESOURCES
References:
[1] www.github.com/Integreight/1Sheeld-Firmware
[2] www.1sheeld.com
AJ-SR04M – Waterproof Ultrasonic Distance Sensor
www.github.com/tomaskovacik/kicad-library/tree/master/library/datasheet/K02-AJ-SR04
1Sheeld – Arduino shield for both Android and iOS
https://1sheeld.com/buy/
3ple Decker Case for Arduino
http://www.physical-computing-lab.com
1Sheeld | www.1sheeld.com
Microchip Technology | www.microchip.com
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JULY 2020 #360 – Get a PDF of the issue
Sponsor this ArticleJeff Bachiochi (pronounced BAH-key-AH-key) has been writing for Circuit Cellar since 1988. His background includes product design and manufacturing. You can reach him at: jeff.bachiochi@imaginethatnow.com or at: www.imaginethatnow.com.