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)
The Concrete Pick: For 90% of robust general-purpose proximity builds (car reverse alarms, outdoor tank level monitors, robotic obstacle avoidance), buy the JSN-SR04T V2.0. It uses the exact same trigger/echo timing protocol as the HC-SR04, but the transducer is sealed in a waterproof aluminum housing with a 3-meter shielded cable. It will not short out when condensation forms on the mesh.

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

  1. Disconnect the Arduino Nano from USB power.
  2. Plug the Nano into a breadboard, ensuring pins straddle the center trench.
  3. Connect the JSN-SR04T VCC to the Nano 5V rail, and GND to the Nano GND rail.
  4. Route the Trig wire to Digital Pin 9, and the Echo wire to Digital Pin 10.
  5. Screw the waterproof transducer into your enclosure panel, ensuring the acoustic mesh is flush and unobstructed.
Voltage Warning: If you later port this build to a 3.3V board (like an ESP32), the JSN-SR04T Echo pin will output 5V, which will fry the ESP32 GPIO. You must add a voltage divider (10kΩ and 20kΩ resistors) on the Echo line for 3.3V microcontrollers.

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

  1. 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.
  2. 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.
  3. 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.

Final Recommendation: Start your prototype on the breadboard with the JSN-SR04T and the code provided above. Once the logic is proven, migrate to the A02YYUW UART variant only if you hit GPIO limits or need to eliminate the blocking nature of pulseIn() in a multi-sensor array.