HC-SR04 based Water Level Monitor with LabView Interface

I have been experimenting with an ultrasonic range sensor (HC-SR04) and thought about this wild idea of using it as a water level monitor. It turned out that the idea was not that wild, I could find some related articles on the internet. Despite having some concerns about field usability, I have decided to put together a prototype to see what happens.

The HC-SR04 Ultrasonic Range Sensor

HC-SR04 Sensor
HC-SR04 Sensor

The breakout board has 2 data/control pins apart from the power supply. One is called TRIGGER and the other is ECHO. The sensor has two cylindrical metal drums on one side. Apparently one of these is a ultrasound pulse generator, and the other is a receptacle. They are placed close to each other. I’m not sure how exactly does this device range objects, but the concept is vaguely discussed in some internet articles. The idea is that, the pulse generated by one drum reflects off of any objects in direct vicinity, and the reflected pulses are picked up by the receptacle. I believe that the system assumes that the object does not interact with the ultrasonic wavelengths. If it does, the reflected wavelengths may be varied. Technically speaking, this is a mini SONAR.

Note:- Strictly speaking, this should have difference in interactions with the surface of water, and objects under water. SONAR is generally designed to detect objects under water, but here I go anyway

HC-SR04 Working
HC-SR04 Working

Lets try to understand the timing features of this configuration. When we give it a HIGH on the TRIGGER pin for at least 10uS, the device gets triggered. It subsequently sends a 40KHz pulse from the generator, and receives reflections from nearby objects. There should a transfer function to convert the time difference in send/receive to distance. Then depending on the measured distance, the board sends us back a HIGH on the ECHO pin. The length of this pulse will be directly proportional to the distance measured by the device.

Interfacing HC-SR04 with Arduino

With this understanding, I have wired up the sensor with Arduino. The convenience here is that, since Arduino itself acts as a serial port device, using the USB-to-TTL emulation, it becomes useful in the next stage when we want to see data directly on a computer.

HC-SR04 Wired up to the Arduino
HC-SR04 Wired up to the Arduino

Corresponding program is a reference program that I happen to find on the internet. The code below is in public domain, and you are free to use it the way you want. I have modified it to simplify the serial communication.


/**
 * HC-SR04 Demo
 * Demonstration of the HC-SR04 Ultrasonic Sensor
 * Date: August 3, 2016
 * 
 * Description:
 *  Connect the ultrasonic sensor to the Arduino as per the
 *  hardware connections below. Run the sketch and open a serial
 *  monitor. The distance read from the sensor will be displayed
 *  in centimeters and inches.
 * 
 * Hardware Connections:
 *  Arduino | HC-SR04 
 *  -------------------
 *    5V    |   VCC     
 *    7     |   Trig     
 *    8     |   Echo     
 *    GND   |   GND
 *  
 * License:
 *  Public Domain
 */

// Pins
const int TRIG_PIN = 7;
const int ECHO_PIN = 8;

// Anything over 400 cm (23200 us pulse) is "out of range"
const unsigned int MAX_DIST = 23200;

void setup() {

  // The Trigger pin will tell the sensor to range find
  pinMode(TRIG_PIN, OUTPUT);
  digitalWrite(TRIG_PIN, LOW);

  // We'll use the serial monitor to view the sensor output
  Serial.begin(9600);
}

void loop() {

  unsigned long t1;
  unsigned long t2;
  unsigned long pulse_width;
  float cm;

  // Hold the trigger pin high for at least 10 us
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  // Wait for pulse on echo pin
  while ( digitalRead(ECHO_PIN) == 0 );

  // Measure how long the echo pin was held high (pulse width)
  // Note: the micros() counter will overflow after ~70 min
  t1 = micros();
  while ( digitalRead(ECHO_PIN) == 1);
  t2 = micros();
  pulse_width = t2 - t1;

  // Calculate distance in centimeters
  // are found in the datasheet, and calculated from the assumed speed 
  //of sound in air at sea level (~340 m/s).
  cm = pulse_width / 58.0;
  
  // Assuming when there is no water in the tank,
  // the distance measured will be at a maxima.
  // In this case, the depth of the tank : 300cm.
  cm = 300 - cm;
  // Print out results
  if ( pulse_width > MAX_DIST ) {
    Serial.println("Out of range");
  } else {
    Serial.print(cm);
    Serial.print("\n");
  }
  
  // Wait at least 60ms before next measurement
  delay(300);
}

Stage-1 Testing

The first stage testing is to make sure that the data send out by the Arduino reaches the target machine correctly. If you are running Arduino IDE on your target machine itself, it is relatively easy since your drivers are in place, as well as your IDE has a serial monitor. In my case, I’m programming the Arduino from my Mac, and my target host is a Windows-7, is running as a guest on VirtualBox. In that case, I should have the FTDI VCP (Virtual COM Port) drivers for Windows in place. Arduino Duemilanove uses FT232RL chip. Your control board may be using a different driver. A serial monitor program such as CoolTerm can be used to make sure the data from the sensor is coming correctly on the target host. You may use any program of your choice to do the same.

LabView Program

Labview Block Diagram for the Water Level Monitor Project
Labview Block Diagram for the Water Level Monitor Project

The LabView program is relatively simple. You will need VISA drivers for LabView to be able to read from serial devices. You may download it from the NI website. What the LabView program does is explained below. The serial port is opened first, and the program reads 4 bytes from it at a time. This can be changed by the constant widget in the diagram, or at the runtime by using a control widget. My assumptions here is that, all the numbers coming from the sensor is less than 300 (Max depth of the tank), which fits well within 4 bytes. The read-buffer from the VISA Reader is at the same time attached to an Indicator (so that we can see what data is being received on the front panel), as well as a String —> Decimal number converter. Note that, I have not added a divider to set the tank input between the tank’s scale which is 0 - 100. It should be pretty straight forward to do. Finally, when the read operation is done, close the serial port. Note that, I have also connected the number output to a waveform chart. This is to monitor historical data.

Front-Panel

Water Level Monitor Running
Water Level Monitor Running

The front panel is also very simple. It contains a tank and a waveform chart. (I’ve a taste for classic controls, you may choose better widgets). The first 4 bytes of every new line printed by the Arduino program is displayed in the read buffer indicator. Once converted to a number, the tank widget is redrawn with appropriate progress. Paralelly, the same data is used to draw the waveform.

Caveats

  1. As this is a prototype project, I have omitted many details. Say for example, the block diagram does a very minimal job in reading data from the serial device. If there is no data coming in from the device for 20 seconds, the program simply crashes. You may add conditional blocks to change the behavior.
  2. Only the first 4 bytes of incoming data is read. Ideally, the reading should be full, and appropriate error handling should be done when the received data cannot be converted to a number. Again, adds more controls to the diagram.
  3. In the field, the communication between the monitor and the sensor shall be done wirelessly, since the water tank is located elsewhere compared to your monitoring computer. This can be achieved by using any wireless com setup.