Ultrasonic Water Tank Level Monitor

So Im having fun with my Raspberry PI… Trying to build a monitor of a water tank level at a country property - I think I am almost there…

So first time I am using ultrasonic sensors - and umm consistency is not really there… Little disappointed I guess. Its not that I need accuracy - but I would like some consistency…

My Code is as follows - and I am doing multiple readings and averaging them out… But even doing that - each time I run the complete code, the average can change by more than a cm…

Is there anything else I can do, to try and get more accurate / consistent reading ?

I am using the Weatherproof Ultrasonic Sensor with Separate Probe - maybe that was my mistake… I really should not need a waterproof item - if I mount it securely at the top of the tank inside - water should not splash on it…

Advice ?

Code as follows

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
TRIG = 23
ECHO = 24

howmany = 20
soundspeed = 17150

total = 0

print (“Distance Measurement In Progress”)
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
GPIO.output(TRIG, False)

for n in range(1,howmany+1):
print ("Waiting For Sensor To Settle - Reading ",n)
time.sleep(2)
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
while GPIO.input(ECHO)==0:
pulse_start = time.time()

while GPIO.input(ECHO)==1:
 pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * soundspeed
total = total + distance
distance = round(distance, 2)
print ("Distance 1:",distance,"cm")

average = total / howmany
average = round(average, 2)
print ("Average Distance: ",average,“cm”)

GPIO.cleanup()

I have tried different measurements - but really confused over the variance returned by the sensor…
Eg. placed sensor pointing at a wall - at 112.5 cm away and I got results of;
Distance 1 : 112.0 cm
Distance 2 : 112.55 cm
Distance 3 : 216.85 cm
Distance 4 : 112.39 cm
Distance 5 : 112.02 cm
Distance 6 : 49.56 cm
Distance 7 : 112.6 cm
Distance 8 : 112.16 cm
Distance 9 : 112.62 cm
Distance 10 : 112.39 cm

While I expect some variance - I was not expecting to see scan 3 at double the distance, and scan 6 at half the distance…
Its not a critical app - but I am going to be un trustworthy in determining if I captured any rain this week in the water tank, or I just lost half of the water by these readings…

Is it because I am trying to do this on a Raspberry Pi Zero W - and its just underpowered to do any accurate clock measurements ? How can I improve my accuracy on this so I can get better consistency ?

So if anyone is interested… I have spent all morning on this - remember this is my first python program too !

I found such inconsistancies in reading - most likely the second read would be well out there - sometimes twice as big as it should be - once 10 times! Other times, it could be a lot lot smaller than it should be…

So it made me think - how to remove the outliers… If I could ignore the items that occurred at each extreme, and then looked at the average of ‘good’ data - would I then have some kind of consistency…

So here is my revised code - it works out the standard deviations, and removes things at both ends of the extreme - returning an array of potentially good data !!!

import RPi.GPIO as GPIO
import time
import numpy as np

GPIO.setmode(GPIO.BCM)
TRIG = 23
ECHO = 24

howmany = 50
soundspeed = 17550

a = np.zeros(shape=[howmany])

def outliers(data, m = 2.):
d = np.abs(data - np.median(data))
mdev = np.median(d)
s = d/(mdev if mdev else 1.)
return data[s<m]

print (“Distance Measurement In Progress”)
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
GPIO.output(TRIG, False)

for n in range(1,howmany+1):
time.sleep(1)
GPIO.output(TRIG, True)
time.sleep(0.00003)
GPIO.output(TRIG, False)
while GPIO.input(ECHO)==0:
pulse_start = time.time()
while GPIO.input(ECHO)==1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
a[n-1] = pulse_duration * soundspeed

print (“array -original”)
print(a)

print(“array - removed outliers”)
print(outliers(a))

print("Average - removed outliers: ",round(np.average(outliers(a)),1))

GPIO.cleanup()

Running this - it does not seem to matter if I do 20 Reads, 50 Reads, or even a 100 Reads - I end up with something that is now consistent… Each time I execute the code, I end up with .1cm consistency on each read… I have run at 20 times - and each time I got the same answer - so I am happy !!! Very happy !

Maybe this helps someone else ?

Hi Keith,

Great solution!

I was going to suggest taking 10 measurements in sequence, sort the results, and taking the median value rather than the average (grab the middle value in the array, or instead of sorting just go straight for the median value). What you are experiencing is pretty common for an ultrasonic sensor, and is just one of the limitations of the device. There are often stray readings.

Glad you got it sorted out though!