Ultrasonic water tank gauge

Showcase your projects! We love to see what people come up with, so please share your creations here.
Post Reply
Posts: 22
Joined: Wed Nov 02, 2011 10:38 am
Location: Hoppers Crossing

Ultrasonic water tank gauge

Post by dave » Wed Nov 02, 2011 11:08 am

Hi all, here is a litle project I completed yesterday - just in time for a brand new arduino forum!

Basically I wanted an easy way to tell how much water was in each of my rainwater tanks. When the smaller one (Which collects most of the water) is full, I need to pump it around to the larger tank which irrigates the garden etc. In the past the only way I could reliably do this was climb on top of the tank, unscrew the mesh leaf filters on the inlets and shine a torch inside.

So over a couple of weeks I put together a ultrasonic water tank gauge. The idea is relatively simple - the ultrasonic beam from a 'ping)))' sensor goes through the mesh on the inlet and bounces off the surface of the water. A quick calculation gives me the distance to the water surface. Knowing the height from the inlet to the outlet of the tank I can then calculate the actual depth of usable water. Originally I had planned to calculate the volume in litres and display it on an LCD shield, but in the end I mapped this to a servo instead, rotating the arm between 0 and 180 degrees to indicate a range between Empty and Full on a simple scale.

Power is from a 9v transistor battery running through a momentary push button switch.
1. Reach up and sit the sensor on the leaf mesh, push the button.
2. Arduino fires up, ping sensor gets range, servo arm moves, buzzer sounds to indicate reading.
3. Release button, unit powers off and servo arm is frozen in place, lift unit down and see how much water is in the tank!

Parts are pretty minimal,
Freetronics Eleven
Ultrasonic sensor from sparkfun.com
piezo buzzer
small hobby servo from ebay
battery clip, switch and box from Jaycar

With the lid off. The buzzer is hidden under the freetronics eleven.


With the lid on, showing the gauge.

I hope this will help to inspire others with their own projects, just as I have been by the many other simple arduino projects others have posted on the web. If anyone asks I will be happy to post the code too.


Last edited by dave on Thu Nov 03, 2011 10:24 am, edited 3 times in total.

Posts: 22
Joined: Wed Nov 02, 2011 10:38 am
Location: Hoppers Crossing

Re: Ultrasonic water tank gauge

Post by dave » Wed Nov 02, 2011 9:09 pm

Hi ,
yes I was going to build the silicon chip project but found it didn't really suit my needs - they had designed it to be more of a permanent install and I wanted a portable device that could be used on both of my water tanks. Making it portable also meant I didn't need to put everything in a weatherproof enclosure, and using a servo as the output means I don't have to worry about which LEDs to turn on or off.

I have put lots of documentation in my code to help me troubleshoot down the track, so anyone looking at it should be able to adapt it to their own needs. I was trying to figure out how to upload an attachment last night so I could add a photo or two and the code but ran out of time. I will have another go tonight.



Posts: 22
Joined: Wed Nov 02, 2011 10:38 am
Location: Hoppers Crossing

Re: Ultrasonic water tank gauge

Post by dave » Thu Nov 03, 2011 5:54 am

Code with explanation for anyone interested....

Code: Select all

/* Ping))) Sensor Tank Gauge
   This sketch uses a PING))) ultrasonic rangefinder to return the
    distance to the surface of the water in a rain tank. To do this, 
    it sends a pulse to the sensor to initiate a reading, then 
    listens for a pulse to return.  The length of the returning 
    pulse is proportional to the distance of the water from the sensor.
    This is then converted into a distance in centimeters which is in
    turn converted into a value between 0 - 180 to drive the arm on a
    servo to the correct angle.
    The entire circuit is powered via a 9v transitor battery and is 
    switched via a momentary pushbutton. You just put the unit in 
    position and hold the button down. As soon as the servo arm is in
    position the buzzer beeps and you can release the button, freezing
    the servo in position so you can read the water level in the tank.
       Layout of Tank
     _________________*_   Location Of Sensor at top of tank
    |                 : |  :    
    |  Measured Depth : |  :
    |                 : |  :
    |-----------------:-|  :
    |                   |  :
    |      Usable       |  : Maximum Distance
    |      Volume       |  :
    |                   |  :
    |-------------------===== Water Outlet
    |___________________|  : Unusable Water
   There is always a fixed distance from measuring point to
   the base of the tank. Subtracting the measured distance from
   this will give us the depth of the water. Actually better to
   use the distance from measuring point to water outlet as most
   tanks have a 'dead zone' at the bottom to collect debris etc.
   This way we will get the Usable volume of water from our 
   calculation. We will use the variable "Depth" for this value 
   in centimetres.
   Then multiplying the calculated depth of usable water by the
   tanks footprint or area we quickly calculate the volume of
   water in the tank. There are 1000 cubic cm of water to 1 litre.
   There are also 10,000 square cms in a square metre, so for each
   square metre of surface area there are 10 litres of water per cm.
   Thus if we record the area of the tank in tenths of a square metre
   we get two advantages - a. Store it as an integer value, b. direct 
   multiplication of area by depth gives us volume in litres.
   Thus to perform our volume calculation we will need to know the
   following values;
  Fixed values
   1. Distance from measuring point to water outlet (MaxDepth)in cm
   2. Area of tank (Area) in tenths of a sq metre
  Variable Values
   1. Measured depth (depth)in cm - (cm) calculated through the ping))) tutorial
    The circuit:
     * +V connection of the PING))) attached to +5V
     * GND connection of the PING))) attached to ground
     * SIG connection of the PING))) attached to digital pin 2
     * Brown lead of 9g servo attached to ground
     * Red lead of 9g servo attached to +5V
     * Orange lead of 9g servo attached to pin 9 
     * +ve lead of buzzer to pin 3
     * 9v battery via through a momentary pushbutton switch for power
    WaterTank v1.8
    created 31st Oct 2011
    by David Blake
    This code is in the public domain.
 //Begin Program
 #include <Servo.h>  
 const int pingPin = 2;//  It's the pin number of the sensor's input/output:
 const int buzzerPin = 3; // Pin number for the buzzer
 const int MaxDepth = 190 ;// It's the distance from top to outlet of the tank:
 const int Area = 22;// Area of the tank in tenths of a square metre - see notes:
 int count = 0;
 int litres = 0;
 int angle = 0;
 Servo gauge;  // create servo object to control a servo
 void setup() {
  gauge.attach(9); // attache the servo to pin 9
  pinMode(buzzerPin, OUTPUT);
  digitalWrite(buzzerPin, LOW);
 void loop()
  // establish variables for duration of the ping, 
  // the distance result in  centimeters and
  // the calculated volume of water in the tank:
  // Actually calculating volume is not required to drive a servo gauge but
  //  is useful if you want to switch to a lcd readout or similar.
   long duration, cm, depth, lt;
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
   // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
   pinMode(pingPin, OUTPUT);
   digitalWrite(pingPin, LOW);
   digitalWrite(pingPin, HIGH);
   digitalWrite(pingPin, LOW);
  // The same pin is used to read the signal from the PING))): a HIGH
   // pulse whose duration is the time (in microseconds) from the sending
   // of the ping to the reception of its echo off of an object.
   pinMode(pingPin, INPUT);
   duration = pulseIn(pingPin, HIGH);
  // convert the time into a distance
   cm = microsecondsToCentimeters(duration);
      depth = MaxDepth - cm; 
      litres = depth*Area; 
      /* convert litres to an angle between 0 and 180 degrees
      4180 is the calculated maximum volume from tap to ping sensor
      this is likely larger than the actual volume of the tank
      as the sensor should be located above any overflow pipes etc. */
      angle = map(litres, 0, 4180, 0, 180); 
      gauge.write(angle); //use "gauge.write(180-angle);" to reverse gauge direction
   // sound buzzer
   for (count = 0; count <= 10; count++) 
    digitalWrite(buzzerPin, HIGH);
    delay (15);
    digitalWrite(buzzerPin, LOW);
    delay (10);
   delay (10000);

long microsecondsToCentimeters(long microseconds)
   // The speed of sound is 340 m/s or 29 microseconds per centimeter.
   // The ping travels out and back, so to find the distance of the
   // object we take half of the distance travelled.
   return microseconds / 29 / 2;

Post Reply