AJ-SR04M Ultrasonic Distance Sensor

AJ-SR04M Ultrasonic Distance Sensor

Applications

The ultrasonic distance measuring sensor is currently used to monitor effluent level in an aerated wastewater treatment system (AWTS). I chose this sensor, rather than the pressure sensor generally used in my water tanks, because, over time, the latter have shown a tendency to be impacted by the impurities, those present in bore water for example, and the AWTS is not exactly a 'clean' environment.

AWTSUltrasonic Sensor Controller
Biological Aquatics System AWTS Ultrasonic Sensor Controller Installation
NodeSensor (Inside Tank)
AWTS Node Installation AWTS Ultrasonic Sensor Installation
AWTS Ultrasonic Sensor Installation

As with most of the things I am doing, I have built on the efforts of others, starting with the AJ‑SR04M project described in Probots Blog. This sensor, or the interface card at least, seems to be generally referenced as being the same as the JSN-SR04T (V2?), although the board layout seems to be slightly different. In any case, I have never used anything other than the AJ‑SR04M module, so I can't comment on any differences that may exist.

I noted various discussions (like this one) about problems with these sensors and the need for special housings etc. to avoid spurious echoes and the like. In the present application, I found the best results when the sensor was installed entirely unimpeded, close to the top of my tank. The internals of my tank are a little complicated in that there are various plumbing elements descending into the tank. Nonetheless, provided the ultrasonic sensor was not in the immediate vicinity of any of this plumbing, and had an unobstructed 'view' of the water surface below, readings were consistent and reliable.

For reference, the sensor in the photo above (bottom right) is ~25cm from the wall of the tank, an Everhard Industries Model 87001 3000L Septic Tank (although my application is not as a traditional septic tank), which tapers in slightly towards the bottom but is otherwise a relatively flat surface, and ~150cm from the normal water surface. The plumbing to the right of the photo connects to a pump and the aeration system in the base of the tank and the sensor is sited so that its 'view' is not impacted by this hardware.

More recently, I have also started using a similar configuration to measure water levels in our rainwater tanks, primarily because it is much more economical (A$4 vs A$40+) than the pressure sensor that has been used to date. Unfortunately, mounting the ultrasonic sensor inside a tank is somewhat more fiddly than just dropping in a pressure sensor. The packaging for the electronics in this application is, however, more straightforward than for the AWTS application, with all but the sensor itself fitting neatly into a single enclosure.

Sensor (Inside Tank)Sensor Bracket MountNode Installation
Tank Node Ultrasonic Sensor Installation Tank Node Sensor Mount Tank Node Installation
Water Tank Ultrasonic Sensor Installation

Configuration

Hardware

This device comprises a sensor that connects, via a 2.5 m, 2-wire cable and XH2.54 plug, to an interface board, which in turn presents a 4-pin header for connection to a microprocessor. While the interface board labels the power input pin as 5V, this sensor will operate on the 3.3V supplied by all of the processors that I use.

Controller Board

The configuration of the connectors on the sensor controller board, as supplied, is not particularly convenient for either of the present applications, with the XH2.54 sensor cable socket protruding vertically from the bottom of the board and, in the case of the AWTS application, the processor interface header horizontally from one edge.

To simplify the packaging of the interface board in the AWTS application, which needed to be relatively close to the sensor itself but then also needed to connect to a microcontroller that could be several metres further away, both of the existing connectors were replaced by right angle XH2.54 connectors. With this configuration, both cables effectively exit in the same direction from the interface board, simplifying their subsequent external connection.

For the water tank application, only the 2P XH2.54 sensor connector needs to be modified.

Note: The pins on the 4P connector need to be trimmed flush with the board to avoid fouling with the sensor connector, and the 2P [sensor] connector needs to be mounted slightly proud of the PCB to accommodate the shrouded plug on the sensor cable.

Original
AJ-SR04M Original Connectors
AWTS Node ModifiedWater Tank Node Modified
AJ-SR04M AWTS Modified Connectors AJ-SR04M Water Tank Modified Connectors
AJ-SR04M Interface Board Connectors

In order to mount the interface board neatly within one of my 'standard' enclosures, 85 × 58 cm for the AWTS application or 100 × 68 cm for the water tank application, I also created mounting boards that could be fixed into the enclosure to provide the necessary mounting points. Cut-outs on the boards are to accommodate external connectors that protrude into the enclosure and, in the case of the water tank application, the components of the controller board itself—see photos below.

TopBottom
8558-SC PCB Top 8558-SC PCB Bottom
8558-SC PCB
ZIP 8558-SC Eagle CAD Files [25 KB]
ZIP 8558-SC CAM Files [54 KB]
TopBottom
10068-SR04 PCB Top 10068-SR04 PCB Bottom
10068-SR04 PCB
ZIP 10068-SR04 Eagle CAD Files [69 KB]
ZIP 10068-SR04 CAM Files [64 KB]

Unused space on the boards is also populated with my standard array of pads to provide flexibility for any possible additional use.

For the AWTS application, the controller board is mounted on the 8558-SC support board using ?mm F-F M2 stand-offs within an 85 × 58 enclosure and the 10068-SP solar panel board is mounted on the 10068-BHCP processor board using ?mm F-F M2 stand-offs within a 100 × 68 enclosure.

AWTS Node Components

AWTS Node Components

For the water tank application, the controller board is mounted on the 10068-SR04 support board using 5mm F-F M2 stand-offs. The 10068-BHCP processor board is also mounted on the 10068-SR04 support board, but using taller, 15mm M-F M2 stand-offs and the 10068-SP solar panel board is mounted on top of that, using 16mm F-F M2 stand-offs. The entire 'sandwich' thus [just] fits neatly into a single 100 × 68 × 50 enclosure.

Tank Node Components

Tank Node Components
Sensor

To provide the sensor connection, I cut the [coaxial] sensor cable and inserted one of the [SP11] Weipu waterproof connectors I use to connect to the enclosure internals. The 85×58 enclosure also had to be modified slightly by removal of one of the external mounting flanges and the 'bottom' [in the photo below] internal mounting post to accommodate the two connectors. The packaging is tight but the smaller the packaging the more flexibility I have in how and where a node can ultimately be mounted.

Remove External FlangeRemove Internal Mounting Post
REmove the bottom enclosure mounting lug Remove the bottom internal mounting post
AWTS Controller Enclosure Modifications

The AWTS sensor bracket was fabricated from a piece of COLORBOND® steel. The sensor mounting hole was a little larger than I would have liked for a snug fit, but that was the size I could cut with the step drill that I had so that was it. To hold it more firmly in place, I just used a snug-fitting O-ring around the back of the sensor.

ComponentsAssembly
AWTS Ultrasonic Sensor Bracket Components AWTS Ultrasonic Sensor Bracket Assembly
AWTS Ultrasonic Sensor Mounting Bracket

The Water Tank sensor mounting bracket is similar, with folds required to hold the sensor horizontally inside the tank (see illustration above).

It doesn't really matter which pins are connected to which wires on the external connectors, but they obviously need to be configured the same way at each end and, if several similar Nodes are being configured, having them all the same keeps everything interchangeable.

PolarityAssembly
Ultrasonic Sensor Cable Configuration Ultrasonic Sensor Cable Assembly
Sensor Cable
Processor

Once again, the CubeCell Dev-Board Plus provided a convenient platform for this application, given that it has the capacity to concurrently support a wide range of sensors, including both the line air pressure and the present ultrasonic distance measuring sensors used in my AWTS application.

The current CubeCell Dev-Board Plus configuration is as illustrated below.

Ultrasonic Sensor Configuration

CubeCell Dev-Board Plus–JA-SR04M Electrical Circuit
Pin Configuration
CubeCell Plus AJ-SR04M
GND GND
Ve 5V
RX2 Echo
TX2 Trig

Some people also recommend configuring a pull-up resistor (4k7–10kΩ) between the Echo pin and Vcc (5V/3.3V), but I've not experienced any problems to date without this.

The actual physical configuration of both applications, as currently implemented, is based on the 10068-BHCP base board and uses the physical GPS interface provided on that board, although the connection is provided through a 4P XH2.54 JST connector, on the top of the board for the AWTS application or the bottom for the water tank application, rather than the conventional header used by the GPS module (which would be located on the bottom of the board). The interface provided for a GPS module conveniently includes connections to the second set of CubeCell Plus UART (TX/RX) pins, which are used in the present configuration to communicate with the ultrasonic sensor interface board.

AWTS Node Assembly

AWTS Node Assembly
StackAssembly
Tank Node Stack Tank Node
Water Tank Node

Software

While some people use the NewPing library, no special software library is actually required to use this sensor. As others have before me, my sketch simply raises the processor's 'trigger pin' for 10 microseconds and measures the delay before receiving a signal on the 'echo pin'.

It should also be noted that the sensor can be configured to work in several different modes (refer to the Probots Blog post for a detailed explanation of the different modes), generally through the addition of an appropriate resistor at location R19 on the interface board. In particular, some of these modes are low power modes, designed specifically for battery-powered applications. Since my processor boards, or the processors themselves, include the ability to power down peripherals in a low power operating mode, I have not bothered to investigate any of these options—I simply use the interface board in its default configuration.

Testing the Configuration

The following sketch, which runs on the CubeCell Dev-Board Plus in the configuration illustrated above, is based on that offered in several other posts. To assist with testing when a Serial Monitor is not available, the present version also generates output on the built-in display on the CubeCell Dev-Board Plus.

As with most of my sketches, processor pin definitions are included in the relevant <processor>Pins.h file, in the present case CubeCellPlusPins.h.

The distance travelled by the ultrasonic wave is calculated from the speed of sound and the elapsed time, using the following formula:

Distance=Speed of Sound × Elapsed Time

2

taking 343 m/s (0.0343 cm/µs) as the speed of sound in air at 20 °C and noting that the distance to the 'measured surface' is half the round trip distance.


Ultrasonic Distance Measuring Test Sketch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <HT_SH1107Wire.h>// CubeCell Plus display library
#include "CubeCellPlusPins.h"// CubeCell Plus pin definitions

// Define the pins to be used
#define echoPin ultraEcho// Refer to processor pin definition .h file
#define trigPin ultraTrig// Refer to processor pin definition .h file

// A couple more variables
long elapsedTime;// Sound wave travel time
int distance;// Distance measurement

// The CubeCell Plus Display object
SH1107Wire display(0x3c, 500000, SDA, SCL, GEOMETRY_128_64, GPIO10);// addr, freq, sda, scl, resolution, rst

void setup () {
pinMode(trigPin, OUTPUT);// Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT);// Sets the echoPin as an INPUT

pinMode(Vext,OUTPUT);
digitalWrite(Vext,LOW);// Turn on power to connected devices

Serial.begin(115200);
delay(100);
Serial.println("[setup] AJ-SR04M Ultrasonic Sensor Test");

display.init();
display.setFont(ArialMT_Plain_10);
display.screenRotate(ANGLE_180_DEGREE);
display.clear();
}

void loop() {

// Clear the trigPin condition
digitalWrite(trigPin, LOW);
delayMicroseconds(2);

// Set the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Read the echoPin, returns the sound wave travel time in microseconds
elapsedTime = pulseIn(echoPin, HIGH);

// Calculate the distance
distance = elapsedTime * 0.0343 / 2;// Speed of sound wave divided by 2 (out and back)

// Give a bit of feedback
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");

display.clear();
display.setFont(ArialMT_Plain_10);
display.drawString(10, 5, "Distance:");
display.setFont(ArialMT_Plain_16);
String distanceString = String(distance);
distanceString.concat(" cm");
display.drawString(10, 20, distanceString);
display.display();

delay(500);
}

In practice, I have noticed a degree of variation in the measurement of elapsed time. This was not a real problem when simply monitoring the water level in a tank, but when it came to using the level to trigger events, it was more important to have a stable, and thus more predictable result. To this end, the present implementation takes 21 samples, at 100ms intervals, and selects the median value. This provided a more workable solution than simply using an average, as the average still varied noticeably with smaller sample sets. Taking only 11 samples was a little less stable—10-15% of samples are outliers, no matter how many are taken, but the median is more consistent in larger samples—and increasing the sample interval didn't improve the consistency of measurements.

Further, while the present arrangement, whereby all calculations are performed by the Node, and just the ultimate result reported, was fine in the original [AWTS] application, when it came to managing water storage tank details, it became apparent that it was better for the Node to simply report its 'observations', the relevant time delay, and let the ultimate recipient of this data do what was necessary to derive a useful result. I am yet to implement this change in the AWTS application (I will remove this note when the task is complete).

The Problem with Ultrasonic Sensors

There is one significant problem with ultrasonic sensors in this type of environment—condensation (water droplets) on the sensor surface. Unfortunately, when this occurs, the water droplets can reflect the ultrasonic signal yielding false readings and unreliable results.

This has never been a real problem in the case of the AWTS application. This may be because the tank is essentially buried and the temperature inside the tank does not vary greatly or it may be related to the fact that the tank never gets very full under normal conditions.

Condensation has shown to be more of a problem in the case of the rainwater tank, which is above ground and often over half full. In this case, the problem manifests itself as frequent, what amount to 100% full readings.

This is less of a problem when monitoring the level graphically, over an extended time period, as correct measurements seem to be made on a regular basis regardless. Fortunately, the sensor seems to make only two types of measurement—the correct one, and a 100% reading (when the signal reflects off a droplet on the surface of the sensor). As a result, the readings are not entirely useless, as a graph over time effectively fluctuates between these two values, the lower 'correct' reading and the upper erroneous 100% reading.

This does nonetheless make using these readings for critical applications, like pumping water between rainwater tanks based on water levels, a little impractical, seriously compromising one of my primary goals in this particular application.

Application Sketches

The application sketches and support files can be downloaded by following the links below. I'll provide a complete description of what's going on at some point, but for the time being you'll need to look at the descriptions under each of the relevant sensors to see what's happening in each case.

Place the EepromHandler and PacketHandler libraries in the Arduino/libraries folder.

Place the Langlo folder, containing the Langlo header files, in the Arduino/libraries folder. The Langlo folder, and the files it contains, can be renamed anything you like. These header files contain the required WiFi and MQTT configuration details and the pin configurations for the relevant processor dev-board.

Place the relevant Node sketch folder in the Arduino IDE root folder (Arduino). If running on a Heltec CubeCell Plus module, as is currently configured, this sketch also requires the latest version of the Heltec [CubeCell] hardware support libraries.

ZIP AWTS Node [v2.1.0] 03-Apr-2024 [7 KB]
ZIP Water Tank Node [v1.2.0] 03-Apr-2024 [6 KB]
5-11-2024