Water Level Monitor using HC-SR04 and LabView

I have been working with ultrasonic range sensor HC-SR04 and got this wild idea to use it as a water level monitor from the internet. Despite having some concerns about using it for water level monitoring in a production environment, I decided to put together a prototype to experiment with it.

The HC-SR04 Ultrasonic Range Sensor

HC-SR04 Sensor
HC-SR04 Sensor

The breakout board has 2 pins apart from the power supply pins. One is called TRIGGER and the other is ECHO. The sensor has two cylindrical shaped objects on one side. Apparently one of these is a ultrasound pulse sender, and the other is a receiver. They are relatively close to each other. But since these are two parts, instead of one combo sender/receiver, I’m not sure how exactly does this device range objects. I think the concept is vaguely discussed in some blog posts on the internet. Lets assume that, it is very similar to SONAR. Electrically, the working is relatively simple as shown below.

HC-SR04 Working
HC-SR04 Working

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 sender, and receives reflections from nearby objects. 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.

Programming Arduino to Handle HC-SR04

So, by this understanding about the sensor module, I have wired up the sensor with Arduino. The convenience here is that, since Arduino board itself acts as a serial port device, using the USB-to-TTL emulation, it becomes useful in the next stage.

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. I have modified it to simplify the serial communication on the LabView side.


/**
 * 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 Windows-7 OS is running as a guest on VirtualBox. In that case, the first step is to install FTDI VCP (Virtual COM Port) drivers, since the Arduino Duemilanove I have, uses FT232RL chip. (I will blog about these chips PL2303, CH340G, CP2102 etc in detail in a future post) Once, this is done I fired up CoolTerm to check the virtual serial port, to make sure data from the sensor is coming correctly at the Windows end. 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 also relatively simple. You will need VISA drivers to let LabView read from the serial devices. You may download it from the NI website. Fundamentally, the serial port is opened first, and the program reads 4 bytes from it at a time. This can be changed at the program level by constant widget, 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). 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 very straight forward. 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.
  2. Only the first 4 bytes of incoming data is read. Ideally, the reading should be fully captured, and appropriate error handling should be done when the received data cannot be converted to a number.
  3. The LabView read loop looks a little slow for some reason. I personally have no idea why this is so. Needs investigation.
  4. In the field, the communication between the monitor and the sensor should be done wirelessly. My plan is to put a ESP8266 into the picture. What is your idea?