The Direct Answer: Which Ultrasonic Proximity Sensor Should You Pick?
When building an arduino proximity sensor ultrasonic circuit, the default hobbyist choice is the cheap HC-SR04. But if your project leaves the workbench, the HC-SR04 will fail. To save you from tearing apart a finished enclosure to swap a dead sensor, use this decision tree to pick the right transducer on day one.
| Operating Environment | Required Range | Budget | Recommended Sensor |
|---|---|---|---|
| Indoor, clean air, dry | 2 cm - 400 cm | < $2.00 | HC-SR04 (Standard 4-pin) |
| Outdoor, wet, dusty, or high humidity | 20 cm - 450 cm | ~ $6.00 | JSN-SR04T V2.0 |
| Narrow beam needed, liquid level sensing | 10 cm - 500 cm | ~ $12.00 | A02YYUW (UART output) |
Parts List & Spec Sheet for the JSN-SR04T Build
The code and wiring below specifically target the Arduino Nano V3 (ATmega328P, 5V logic) paired with the JSN-SR04T V2.0. We assume an ambient air temperature of 20°C (68°F) for the speed of sound calculations (343 m/s).
Bill of Materials
- Microcontroller: Arduino Nano V3 (ATmega328P, 16MHz, 5V)
- Sensor: JSN-SR04T V2.0 Waterproof Ultrasonic Module
- Wiring: 4-pin JST connector (usually included) to male Dupont jumpers
- Power: 5V USB supply capable of ≥ 500mA (the sensor draws ~30mA peak during ping)
Sensor Specification Sheet
| Parameter | JSN-SR04T V2.0 Value | Notes |
|---|---|---|
| Operating Voltage | 4.8V - 5.5V DC | Will brownout on 3.3V logic boards without a level shifter/boost |
| Quiescent Current | < 5 mA | Idle state between pings |
| Peak Current | ~ 30 mA | During the 40kHz burst transmission |
| Blind Zone | 0 cm - 20 cm | Acoustic ringing prevents accurate reads closer than 20cm |
| Beam Angle | ≤ 70° (at -6dB) | Wider than focused industrial sensors; watch for side-wall reflections |
Wiring the Arduino Nano to the Ultrasonic Transducer
The JSN-SR04T separates the transducer from the driver board. Keep the driver board close to the Arduino, and route the transducer cable away from high-current motor wires to prevent EMI from inducing false echo triggers.
Pin Mapping Table
| JSN-SR04T Pin | Arduino Nano V3 Pin | Wire Color (Typical) | Function |
|---|---|---|---|
| VCC | 5V | Red | Power input (Do NOT use 3.3V) |
| Trig | D9 | Yellow | Trigger pulse input (10μs HIGH) |
| Echo | D10 | White | Echo pulse output (HIGH for duration of flight time) |
| GND | GND | Black | Common ground reference |
Physical Connection Steps
- Disconnect the Arduino Nano from USB power.
- Plug the Nano into a breadboard, ensuring pins straddle the center trench.
- Connect the JSN-SR04T VCC to the Nano 5V rail, and GND to the Nano GND rail.
- Route the Trig wire to Digital Pin 9, and the Echo wire to Digital Pin 10.
- Screw the waterproof transducer into your enclosure panel, ensuring the acoustic mesh is flush and unobstructed.
Compilable C++ Code with Timeout & Error Handling
This code targets the Arduino Nano V3 (ATmega328P). It uses the native pulseIn() function with a strict timeout to prevent the main loop from hanging if the echo pin never goes HIGH. It also includes a 5-sample moving average filter to smooth out acoustic multipath bounce.
/*
* Target Board: Arduino Nano V3 (ATmega328P, 5V)
* Sensor: JSN-SR04T V2.0 Waterproof Ultrasonic
* Author: ElectricalFlux
*/
const int trigPin = 9;
const int echoPin = 10;
// Speed of sound at 20C in cm/uS (343 m/s = 0.0343 cm/uS)
// Divided by 2 for round-trip time
const float SOUND_SPEED_CM_PER_US = 0.01715;
const unsigned long TIMEOUT_US = 30000; // 30ms timeout (~5 meters max)
const int NUM_SAMPLES = 5;
float distanceSamples[NUM_SAMPLES];
int sampleIndex = 0;
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Initialize sample array
for (int i = 0; i < NUM_SAMPLES; i++) {
distanceSamples[i] = 0.0;
}
Serial.println("JSN-SR04T Proximity Sensor Initialized.");
}
void loop() {
// 1. Clear the trigger pin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// 2. Send 10us HIGH pulse to trigger
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 3. Read the echo pin with timeout
unsigned long duration = pulseIn(echoPin, HIGH, TIMEOUT_US);
// 4. Error Handling & Calculation
if (duration == 0) {
Serial.println("Error: Pulse timeout. Check wiring or out of range.");
} else {
float rawDistance = duration * SOUND_SPEED_CM_PER_US;
// Filter out blind spot anomalies
if (rawDistance < 20.0 || rawDistance > 450.0) {
Serial.print("Distance: ");
Serial.print(rawDistance);
Serial.println(" cm (Out of bounds / Blind spot)");
} else {
// Add to moving average buffer
distanceSamples[sampleIndex] = rawDistance;
sampleIndex = (sampleIndex + 1) % NUM_SAMPLES;
// Calculate average
float sum = 0;
for (int i = 0; i < NUM_SAMPLES; i++) {
sum += distanceSamples[i];
}
float avgDistance = sum / NUM_SAMPLES;
Serial.print("Smoothed Distance: ");
Serial.print(avgDistance);
Serial.println(" cm");
}
}
// Wait 60ms between pings to avoid acoustic echo overlap (max 20Hz polling)
delay(60);
}
Debugging: "Distance: 0" and "Timeout" Error Strings
Ultrasonic sensors are notorious for failing silently or throwing garbage data. If your serial monitor is misbehaving, follow this diagnostic path.
First Three Things to Check When It Fails
- Measure VCC at the sensor header: Use a multimeter to probe the VCC and GND pins on the sensor side of the wires. It must read ≥ 4.8V under load. Voltage drop across cheap breadboard wires often causes brownouts.
- Verify the Trigger Pulse: Connect an oscilloscope or logic probe to D9. You must see a clean 5V, 10μs HIGH pulse every 60ms. If it's missing, your Arduino timer interrupts (like Servo.h) are blocking the loop.
- Check the Echo Pull-down: If the Echo line is left floating when the sensor is disconnected,
pulseIn()will instantly time out or hang. Ensure the wire is seated firmly.
Exact Error Strings & Ranked Causes
| Exact Serial Output | Ranked Causes (Most to Least Likely) | Fix |
|---|---|---|
Error: Pulse timeout. Check wiring or out of range. |
1. Echo wire disconnected or broken. 2. VCC sagging below 4.5V during ping. 3. Target is beyond 5 meters (exceeds 30ms timeout). |
Resolder Echo pin. Add a 100μF decoupling capacitor across VCC/GND on the sensor board. |
Distance: X.XX cm (Out of bounds / Blind spot) |
1. Object is inside the 20cm acoustic blind spot. 2. Target material is sound-absorbing (foam, heavy fabric). 3. Sensor is angled > 15° off-axis from a flat wall. |
Move sensor back. Add a hard plastic reflector plate to soft targets. Realign sensor perpendicular to target. |
Smoothed Distance: 0.00 cm (Glitch) |
1. EMI from nearby DC motors inducing false echo triggers. 2. Acoustic cross-talk from a second ultrasonic sensor firing simultaneously. |
Use shielded cable for the transducer. Stagger multiple sensor triggers by ≥ 100ms. |
Extending and Simplifying the Build
Once you have stable proximity readings, you will inevitably need to adapt the code for your specific application constraints. Here is how to pivot.
How to Simplify (For High-Speed Polling)
If your robot needs to poll the sensor at 50Hz instead of 15Hz, the moving average filter and the 60ms delay() will bottleneck your main loop.
The Fix: Drop the manual averaging and install the NewPing library. NewPing uses timer interrupts to fire the trigger and read the echo in the background, freeing your main loop to handle motor PID calculations. It also natively handles the 5-sample median filtering in a single function call: sonar.ping_median(5).
How to Extend (For Multi-Sensor Arrays & Displays)
If you are building a 4-sensor parking assist system, daisy-chaining four JSN-SR04T modules will consume 8 GPIO pins and require complex timing to prevent acoustic cross-talk.
The Fix: Switch to the A02YYUW UART Ultrasonic Sensor. Because it outputs a continuous serial data stream over TX/RX, you can connect up to four of them using a single Arduino via a software serial multiplexer or an I2C UART bridge. To visualize the data locally without a PC, wire an SSD1306 128x64 I2C OLED to pins A4 (SDA) and A5 (SCL) using the Adafruit_SSD1306 library to render a real-time bar graph of the proximity zones.
pulseIn() in a multi-sensor array.






