Ultrasonic distance meter, for measuring water volume

Hello!

I apologize in advance for the spelling mistakes, but my English is poor, so I use a translation program!
I need help!
I'm starting the ARDUINO "project" at the age of 58!

The following would be the case:
I'm building an irrigation system that works with rainwater. When it rains, the water flows into 2 IBC tanks, which means 2000 liters of water.
From these 2 tanks, 1 pump lifts the water into 1 1000 liter IBC tank. From this, the system will work with the help of gravity, on 3 separate branches. I've already solved the control of these circuits! The whole system will be covered, so I need the external display!

I need a program that displays the amount of water on 2 "20x4" LCD displays. One shows the volume of the lower 2 tanks, the other the upper tank! I would like to solve the system with 2 Arduino Unos, One would display the saturation of the upper tank, the other the lower tank.

So the distance measurement in cm is not good for me, because the smaller the distance, the greater the water volume! ( 9 cm = 100 liters )
In the case of the upper tank this is:

  • 99 cm = 0 liters, 9 cm = 1000 liters
    In the case of the lower tanks:
  • 99 cm = 0 liters, 9 cm = 2000 liters

Unfortunately, I was careless and accidentally ordered the :
" PWM DC5V Ultrasonic ranging sensor ultrasonic waterproof distance sensor waterproof probe RS485 ultrasonic sensor module ", but I can't find an adapter program for it!

Now I will order the :
A02YYUW UART sensor, which is easier to write a program for.

So I would like to ask you, if anyone is willing to do this, to write me a program for the UART version!

I will try to upload pictures - which I drew with the "SketchUp" program - to make it more understandable!

  • The two thick pipes are where the rainwater flows into the 2 lower tanks.
  • The pump you can see on the side lifts the water into the top tank
  • The black squares on the top of the tanks are the ultrasonic sensors
  • The 3 pipes coming out of the upper tank are for the irrigation system

Thank you in advance for your help!!!

Best regards: Raptor67

Simple arithmetic can solve this problem

How many feet away from the controller Arduino will this sensor be? TTL communications is rather limited at 9600 bps.
Care to explain how you will be providing power to the devices you have distributed around your irrigation system?

Here you can see a few photos of my idea!:

The sensor will be about 2 meters away from the Arduino

That should be ok with shielded, twisted pair wiring. Be sure to keep all the stuff dry!

ok!

Do you think I can build the system with the PWM ultrasonic sensor?

I think you can build ONE to test with!

Could you write me a program for it? I'm completely stupid for it!

Plenty of getting started tutorials for Arduino and an ultrasonic distance sensor have been posted on line (including sensors that use RS485). Look them up, pick one, have a crack at it, and forum members will be happy to help with specific problems that arise.

Otherwise, ask a moderator to move your post to the Jobs and Paid Collaborations forum section.

Not to dissuade you, however, I would measure pressure at the bottom of each tank. There is also the bubbler method using pressure. This will accurately measure the water depth in each tank. A Google of bubbler method for measuring level in a water tank.

Ron

I don't understand what the problem is.
A few years ago, I made a water level gauge for an espresso machine, and it works fine (though in my case, I just needed to check the level against the "minimum" mark).

Assuming a linear tank (i.e., cylindrical or otherwise non-oddly shaped), it's possible to create a function, also (inversely) linear, that calculates the volume given the measured distance.

You can even simply use the existing "map()" function:

  // Upper tank
  int upperL = map(upDist, 99, 9, 0, 1000);
  // Lower tank
  int lowerL = map(lowDist, 99, 9, 0, 2000);

Am I missing something? Am I wrong?

1 Like

Nice solution,

One points,
in practice there will be noise so the distances must be averaged over e.g. 20 measurements.

@raptor1967
One can add some diagnostics to the system, just 2 ideas

  • The level in the tanks will drop when the pump is running. If it is not the pump is broken.
  • If the level in the two tanks rise simultaneously => it is raining.

Hi, @raptor1967
Welcome to the forum.

Do you actually need to know the level, or just when the tanks are at minimum and maximum levels.

Tom.... :smiley: :+1: :coffee: :australia:

Which Arduino are you using?
A sample program is on the product wiki

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11, 10);  // RX, TX

const uint8_t HEADER_BYTE = 0xFF;
const uint16_t READ_TIMEOUT_MS = 200;
const int ERROR_DISTANCE = -1;  // Error return value

void setup() {
  Serial.begin(115200);
  mySerial.begin(9600);
}

void loop() {
  Serial.print("distance=");
  Serial.print(getDistance());
  Serial.println("mm");
}

uint8_t readN(uint8_t *buf, size_t len) {
  size_t offset = 0, left = len;
  uint8_t *buffer = buf;
  long curr = millis();
  while (left) {
    if (mySerial.available()) {
      buffer[offset] = mySerial.read();
      offset++;
      left--;
    }
    if (millis() - curr > READ_TIMEOUT_MS) {
      break;
    }
  }
  return offset;
}

/**
 * Get distance data from the sensor
 * @return Returns the distance value (non-negative) on success, -1 on failure
 */
int getDistance(void) {
  uint8_t data[4] = { 0 };
  uint8_t receivedByte = 0;
  unsigned long startTime = millis();

  while (millis() - startTime < READ_TIMEOUT_MS) {                      // Check if timeout
    if (readN(&receivedByte, 1) == 1 && receivedByte == HEADER_BYTE) {  // Find the header byte
      data[0] = receivedByte;
      if (readN(&data[1], 3) == 3) {                     // Read the remaining 3 bytes
        uint8_t checksum = data[0] + data[1] + data[2];  // Checksum
        if (checksum == data[3]) {
          uint16_t distance = (data[1] << 8) | data[2];  // Calculate and return the distance
          return distance;
        }
      }
    }
    Serial.println("Error data");
  }
  Serial.println("Error Reading data timeout");
  return ERROR_DISTANCE;
}

I would be happy to write the code for you if you can tell me which arduino you are using i prefer 2 x CH340G Arduino UNO R3 Compatible boards for lower cost

and one more question your display is with I2C or without

Code for the display with I2C AND THE PWM ultrasonic

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Adjust address if LCD doesn’t light up (try 0x3F if 0x27 doesn’t work)
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Ultrasonic sensor pins
const int trigPin = 9;
const int echoPin = 10;

// Tank settings
const float mountOffset = 200.0;  // cm (height above top of tank)
const float tankTopToBottom = 99.0; // cm (tank depth)
const float tankTopFull = 9.0;      // cm (when tank is full)

// === CHANGE THIS LINE for each Arduino ===
// Upper tank = 1000.0
// Lower tanks = 2000.0
const float MAX_LITERS = 1000.0;  

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  lcd.init();
  lcd.backlight();
  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print("Rainwater System");
  lcd.setCursor(0, 1);
  lcd.print("Level Display Init");
  delay(2000);
  lcd.clear();
}

void loop() {
  float distance = getDistance();  // Total from sensor to water
  float distanceInsideTank = distance - mountOffset;  // Adjust for sensor height

  // Keep within valid range (avoid nonsense readings)
  distanceInsideTank = constrain(distanceInsideTank, tankTopFull, tankTopToBottom);

  // Volume calculation (linear)
  float volume = (tankTopToBottom - distanceInsideTank) * (MAX_LITERS / (tankTopToBottom - tankTopFull));
  int percent = map(distanceInsideTank, tankTopToBottom, tankTopFull, 0, 100);

  // ===== LCD DISPLAY =====
  lcd.setCursor(0, 0);
  lcd.print("Tank Capacity: ");
  lcd.print((int)MAX_LITERS);
  lcd.print("L ");

  lcd.setCursor(0, 1);
  lcd.print("Distance: ");
  lcd.print(distanceInsideTank, 1);
  lcd.print("cm   ");

  lcd.setCursor(0, 2);
  lcd.print("Volume: ");
  lcd.print(volume, 0);
  lcd.print("L      ");

  lcd.setCursor(0, 3);
  lcd.print("Fullness: ");
  lcd.print(percent);
  lcd.print("%     ");

  delay(2000);  // Update every 2 seconds
}

float getDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH);
  float distanceCm = duration * 0.0343 / 2; // convert to cm
  return distanceCm;
}

:brain: Project: Dual-Tank Water Level Display System

Hardware used (per Arduino):

  • 1 × Arduino Uno
  • 1 × Ultrasonic sensor (HC-SR04)
  • 1 × 20×4 LCD display (I²C type, with backpack)
  • 4 × Jumper wires (male-to-female for the LCD)
  • 4 × Jumper wires (male-to-female for the HC-SR04)

:gear: Arduino Wiring Table

Component Pin on component Connects to Arduino pin Notes
LCD (I²C 20×4) VCC 5V Power for the display
GND GND Common ground
SDA A4 Data line for I²C
SCL A5 Clock line for I²C
HC-SR04 Ultrasonic Sensor VCC 5V Power for the sensor
GND GND Common ground (must match LCD’s GND)
TRIG D9 Trigger pin in code
ECHO D10 Echo pin in code

:white_check_mark: Both the LCD and the HC-SR04 share the same 5 V and GND lines — make sure you tie all grounds together.


:puzzle_piece: Wiring Notes

  • Use male-to-female jumper wires if your LCD and HC-SR04 have pin headers.
  • Keep the echo wire short (under 30 cm) to avoid noise in readings.
  • Double-check that the LCD backpack really uses I²C (it should have only 4 pins labeled VCC, GND, SDA, SCL).
  • If the display stays blank, try changing the I²C address in the code from 0x27 to 0x3F.
  • You can mount the ultrasonic 2 m above the tank, pointing straight down — make sure it’s steady and dry.

:screwdriver: Powering the System

  • If you’re only testing, connect the Uno to your computer’s USB port.
  • For field use: a 5 V 2 A power adapter or a 12 V adapter into the UNO’s barrel jack works fine.

:receipt: Quick Checklist Before Power-On

  1. All GNDs tied together.
  2. LCD’s SDA→A4 and SCL→A5.
  3. HC-SR04’s Trig→D9 and Echo→D10.
  4. Code uploaded with correct MAX_LITERS value.
  5. Tank sensor height = 200 cm above top of tank (as in your setup).

Yes.

There is exactly identical pressure measuring example in the very old, now, Arduino textbook "Practical Arduino" by Jonathon Oxer, complete with code. From memory, it used a Honeywell pressure sensor.

Ultrasonics are widely used for tank content measurements or flow gauging, but can be subject to environmental hazards. Spiders and the like can cause havoc, so cleanliness and maintenance are essential.