I needed some ultrasonic range finders for my project. But most of the commercial sensors like Parallax’s PING sensor and other similar products are quite expensive, especially if multiple units are needed. So I thought why not building it myself?

The theory behind ultrasonic ranging is quite simple. Typically a short ultrasonic burst is transmitted from the transmitter. When there is an object in the path of the ultrasonic pulse, some portion of the transmitted ultrasonic wave is reflected and the ultrasonic receiver can detect such echo. By measuring the elapsed time between the sending and the receiving of the signal along with the knowledge of the speed of sound in the medium, the distance between the receiver and the object can be calculated. The picture below (source: Wikipedia) illustrates this basic principal:

Ultrasonic Ranging (Courtesy of Wikipedia)
Ultrasonic Ranging (Courtesy of Wikipedia)

In my design, I used separate transducers for transmitter and receiver. It is possible to multiplex the transmission and receiving with a single transducer (e.g. Maxbotix range finders), but the design would be significantly more complex.

Ultrasonic Transducer

There are quite a few ultrasonic transducers to choose from, and the main criteria are the resonant frequency, radiation pattern and sensitivity. Generally speaking, these parameters affect the measurement in the following ways: a higher resonant frequency can provide finer details of the surroundings due to the shorter wavelength. A more directional radiation pattern can also enhance the resolution of the measurement. Sensitivity affects the efficiency of the transducer and also attributes to the SNR (signal to noise ratio).

I bought these 24 kHz transducers on sale (see picture below). These transducers are very inexpensive (around a dollar each, and even cheaper when on sale) but effective. With properly designed circuits these sensors can easily achieve a range of more than 20 feet. Of course, using the higher priced 40 kHz sensors should achieve even better performance.

24 kHz Ultrasonic Transducers
24 kHz Ultrasonic Transducers

But for these DIY ultrasonic range finders, the choice of the transducers are really not that critical and this transducer really hits the performance to price sweet spot.


The Transmitter

The ultrasonic transmitter is powered from ATmega328’s counter 1 PWM output (chip pin 16 and Arduino digital pin 10). In order to achieve the maximum output power of the transducer for a given supply voltage, I used the bridged output design as shown in the following schematics:

Ultrasonic Transmitter
Ultrasonic Transmitter

This bridged circuit produces an output voltage roughly twice the Vcc. I used +5V for Vcc and the result is already quite good (more than 20 feet of range). For even longer range measurement, you can safely increase this driving voltage to around 12 Volts as most ultrasonic transducers can be driven with voltage as high as 20 to 30 volts. If you increase the voltage significantly above 5V however, you will have to change the transistors to allow more power dissipation. With 2N3904 and 2N3906 the transistors get warm during normal operation and would heat up drastically with voltage above 6V.

Here is the output of the ultrasonic burst measured at the output transducer’s terminals:

Output Waveform
Output Waveform

The small “ladders” at the half-way voltage point in the output waveform is due to the slight added delay of the inverted signal stage due to the use of an extra NPN transistor. To obtain purer rectangular wave form and reduce switching loss, a PNP transistor with similar timing parameters can be used on the side that is directly connected to the driving signal. For this application though, the waveform is more than adequate and the added switching loss is negligible.

The transmitter and receiver transducers can be mounted on a circuit board with approximately one inch of spacing (see below).

Ultrasonic Range Sensor
Ultrasonic Range Sensor

In order to reduce possible interference from the reflected ultrasonic waves, the components are mounted on the reverse side of the board (below is the H-bridge circuit that drives the ultrasonic transducer, a few decoupling capacitors are used to reduce noise and they are not shown in the schematics above):

H Bridge
H Bridge

The code to drive the transducer is similar to that I used previously, except that I changed the pre-scalar to 1 so that the output frequency can be controlled more precisely in the kHz range.

void startTransducer(float freq, float dutyCycle)
  if (dutyCycle > 0.5) dutyCycle = 0.5;
  else if (dutyCycle < 0) dutyCycle = 0;

  TCCR1B = _BV(WGM13) | _BV(CS10) | _BV(ICNC1);
  //f0 = fclk / (2 * N * Top)
  long topv = (long) ((float) F_CPU /(freq * 2.0 * 1.0));
  ICR1 = topv;

  OCR1A = (int) ((float) topv * dutyCycle);
  OCR1B = (int) ((float) topv * (1 - dutyCycle)); 
  DDRB |= _BV(PORTB1) | _BV(PORTB2);
  TCCR1A = _BV(COM1A1) | _BV(COM1B1); 

void stopTransducer()
  TCCR1B = 0;


The Receiver

The performance of the range sensor is largely determined by the sensitivity of the receiver for a given transmitter power level. Because the received signal is usually very weak (less than 1 mV), a high gain low noise amplifier is needed to ensure optimal performance.

I used a two stage inverted band-pass amplifier design (see below). Each stage has a gain of around 67 (36.5 dB) and the circuit has a combined voltage gain of 73 dB. The operational amplifier I used is National’s LPC662. In general, any operational amplifier with a sufficient gain bandwidth product should work just as well.

Each stage has a band-pass filter that is centered around the operation frequency (24 kHz). Because the amplifier has a very high gain, we must pay special attention to the circuit layout in order to prevent parasitic oscillation. The connection between the receiver transducer and the circuit input (6.8n capacitor) needs to be shielded to reduce noise and unwanted coupling.

Ultrasonic Receiver
Ultrasonic Receiver

Because we are using a single power supply the output voltage of the opamp is centered at around Vcc/2 (2.5V). In order to make it easier to process the echo, a diode (IN4148), capacitor (0.1uF) and resistor (10k) are used to demodulate the signal and a coupling capacitor (1uF) is used to rid the demodulated signal of the DC component.

You can see the demodulated envelope waveform from the following oscilloscope screenshots (you can ignore the frequency measurement as these signals are none-periodical the frequency readings are meaningless). The higher amplitude waveforms in both images are the results of the ultrasonic burst, the lower amplitude waveforms are from the echo. In the first screenshot on the left, two echoes can be seen.

Echo and the demodulated waveform 1
Echo and the demodulated waveform 1
Echo and the demodulated waveform 2
Echo and the demodulated waveform 2

The following screenshot shows the relationship between the ultrasonic pulses (measured from ATmega328 pin 16) from the transmitter and the demodulated echo output. One key observation is that the received signal takes much longer time to fade then the original pulse duration and thus we must add in some delay after the transmission of the ultrasonic pulses. A delay of 1 to 2 millisecond is typical. With a 1 millisecond delay, the shortest measurable distance is around 30 centimeters or one foot.

Demodulated Echo
Demodulated Echo

And here is a picture of the finished project.

Ultrasonic Range Finder
Ultrasonic Range Finder

Range Calculation

Since the measured distance is a function of the time interval between the time at which the pulse is transmitted and the time at which the echo is received, we need to reliability detect the echo.

Empirically, we can measure the peak of the received echo and use the time displacement to calculate the distance. We assume that the strongest echo comes from the closest object (this may not always be true as the reflectivity of different objects are different, but generally achieves very good results in real-world situations) and thus the peak measurement corresponds to the closest object’s position.

The code snippet below assumes that we are interested in measuring objects with a range of up to about 20 feet. After the pulses are transmitted from the transmitter, we wait for a millisecond for the initial receiver signal to fade. Then we search the peak value in the next 20 milliseconds or so (the loop limit 256 is set empirically, in the code below this setting corresponds to a 20 milliseconds interval between transmitted pulses which is suitable for distance measurement up to approximately 20 feet. To measure longer distance, the upper limit for the loop needs to be increased correspondingly) and assume that the peak comes from the first echo.

byte a = 0;
unsigned long t_start = 0;
unsigned long t_peak = 0;
unsigned long t = 0;
byte v_peak = 0;
const float SPEED_OF_SOUND_20C = 0.0003432; //meters per micro-second
float d = 0;

void loop()
  startTransducer(24000.0, 0.5);

  v_peak = 0;
  t_start =micros();
  t_peak = t_start;

  for (int i = 0; i < 256; i++) {
    a = analogRead(0);
    t = micros();

    if (a > v_peak) {
      t_peak = t;
      v_peak = a;

  t = t_peak - t_start;
  d = (float) t * SPEED_OF_SOUND_20C / 2.0;
  Serial.println(d , 2);

Here’s the full code listing for this project:

The bill of material for this ultrasonic range finder is less than 5 dollars (excluding the MCU since it can be incorporated into your projects).


I would like to thank Thomas for pointing out the mistakes in my H-Bridge schematic. The PNP transistor’s collector and emitter are swapped by mistake (I should have double checked the schematics. Anyway, the photo shows the correct orientation) and I have updated the image.

Also on the receiver side, the first OP’s output was missing connection to the 0.1uF capacitor, I have updated it as well.

Be Sociable, Share!

286 Thoughts on “A Sensitive DIY Ultrasonic Range Sensor”

  • kerry so far so good. my progress has been minimal
    i effected the change in the source code for developing a 40KHZ frequency to run the transmitter. but unfortunately sir. my measurement on a frequency metter is 1.86KHZ. . pls what can be done sir

    sir i was likewise getting 0.19 on my serial board without any variation in the value. weather the object goes further or closer. the value on d serial board remains constant. i also reduced the transducer decay value. which was immediately after the statement T-peak〓 T-start. but any change made there would increase or reduce d serrial value to another constant value without any variation.

    sir my changes to ur circuit was dat am using an LM324 op amp.
    ® i also edited the resonant circuit and filter capacitor used at the negative input of each op amp stage.
    ® finally i dnt use the capacitor that ran through vcc and ground in th H-bridge circuit. what effect can dis have sir.

    am really sorry for bothering. i am running out of time to the completion of the project sir. i would appreciate a personal contact to u sir. u can email me personnaly sir on engrtor151@gmail.com.

  • The bridge transmitter doesn’t look right. The waveform should be +(5v – 1.2v) to -(5v – 1.2v) peak-to-peak. The 1.2v drops would be due to 0.6v base-emitter drops on the PNP and NPN transistor on either side of the transducer.

    With nothing connected to “Pin 10” driver, there is a sneak circuit through the PNP Base-Emitter junction, through first 1.5K, through second 1.5K, through both NPN transistors. The Arduino Pin 10 driver source would have to source a lot of current to overcome the sneak circuit and it only seems to be sinking current.

    Anyway, you are not getting +3.8v to -3.8v peak-to-peak across the transducer and would be better off with a single P-Channel MOSFET highside switch or a single N-channel lowside switch. If you want a higher signal output, use a 1:10 transformer to raise the transducer voltage and match the higher transducer impedance. The transformer would put about 50v peak-to-peak across the transducer when using +5v Vcc.

    Very interesting and thanks for posting.

    • Brilliant, Randy! I spent a day struggling with this trying to figure out where my stray current was going. With the original setup, during the 1-2 second Arduino startup when pin 10 is still an INPUT (default), there was about 100mA of current flowing to the circuit. Then when pin 10 was set to an output, there was still stray current: 13mA when pin 10 was HIGH and 35mA when pin 10 was LOW. If I didn’t configure pin 10 to be an OUTPUT at all, the 100mA would remain and start to cook my transistors, literally.

      Anyway, I did as you said and it worked perfectly. When pin 10 is set to LOW or as an input, it consumes < 2mA including during startup. Presumably this is solely due to the resistor.

      And regarding the resistor… it reduces ringing quite a bit it seems.


  • Pingback: google
  • love your write up on this, very well done indeed. i remember doing similar work on this when i was younger for a micromouse competition, where i was told it was impossible to use ultrasonics in such small places, and that was by the so called head of robotics for the UK. anyhow it worked, lol.
    just wondering if you mind if we used a couple of your photos and a bit of text for a review blog on our site of this, with your name and site mentioned and linked to?

  • Hi Randy,

    Am i able to use other chip instead of lpc662? in addition, do u mind if i have a clearer picture of the circuit you have done? Thanks!

  • Respected sir. Which op amp can i use instead of lpc662. Expecting ur reply at the earliest. THANKS 1 in advance.

  • Hi Kerry,
    First of all, great tutorial, it has been a great help in my project. I have a small question regarding the receiving of the signal. I understand you are using the single-ended ADC conversion of the microcontroler. What is the threshold voltage you are accepting as an echo? Should it be anything higher than 2.5V- the “ground” of the receiver output or something more precise?
    Thanks for any help!

    • Thanks!

      For this simple example, I used the “peak” in the returned signal. But to make it more robust, you could use the peak along with a threshold (so when the object is too far away and there is no echo, the reading does not jump around). The threshold should be referenced to ground instead of 2.5V (Vcc/2) though since the cap at the ADC pin removed the DC offset already.

      • Well, I forgot about the capacitor at the end. Anyway, I have another question. The amplification of each stage is 67. That makes 67*67=4489. Assuming we have echo peak at around 20mV, that would give us almost 90V output. How come the output signal doesn’t exceed 2.5V? Sorry for the stupid question, but I’m a begginer if it comes to electronics.

        • In practice, the actual gain will be much smaller (as some pointed out, the first stage was probably not quite ideal as it was configured as none-inverting, which means the input impedance is quite low, never the less, the circuit does work quite well over all), the best way to determine whether the gain is adequate is to use a scope to measure the output.

  • hi. i have two Ultrasonic Transducer RC40K5 and OC40K5. Can someone please tell me which one is Transmitter & Receiver. how to get to know about it. and at what frequency it operates…thanks

  • Hi,
    I have an ultrasonic transducer of frequency 1 MHz. what part of the circuits(both Tx and Rx ) should I edit for getting an echo in digital oscilloscope.
    Now, I am trying to give signal using agilent waveform generator, pulse of 1 MHz,15 Vpp etc. but i am not getting proper distance measurement. Please help me.

    • Hi Rajeev, I am trying to do something similar. Could you share if you found an amplification solution? Maybe we can work together to determine a solution.

      Kind regards,

      • Any progress on the 1 MHz ultrasonic transducer/receiver project? I would like to know what you have learned. Trying to do the same.

        • Looks like 1MHz is quite high for range finders.. why this choice of 1MHz?
          We’re working with 5-7Mhz transducers, but our medium is “water”, not air.

  • hello sir , well i work on project that’s much similar to yours and i was very impressed when i saw your project and i wanted to associated to my robot but i am working w uth pic 18f6620 can you help me with some directions please

  • sir,
    I am a new bee into this. I have chosen my final year project regarding acceleration measurement using ultrasound. i have a 40 kHz transceiver. i would like to have range of 20 meters. I am using a pic16f877 controller, but my sensor is detecting just 1 meter, i am using 5v supply. what could be done to solve this please help me guys. what would be the maximum range measurable using 40 kHz sensor.

  • Hi Kerry,
    First of all, I higly appreciate your valuable article. I am attempting to build a proximity sensor device for the first time.
    Can you suggest me an appropriate ultrasonic transducer part number for a higher range (25-30 meters)?
    Also, can you tell me whether the same ultrasonic tranducer part number can be used as both transmitter as well as receiver? Or, is it that the transmitter and receiver is given different part numbers by the manufacturers?

  • Hello,

    I have a question about the bandpass filter. According to the datasheet of LPC662 (http://www.ti.com/lit/ds/symlink/lpc662.pdf), its gain bandwidth product is 0.35 MHz. So the gain of the filter centered around 24 KHz is less than 0.35/0.024 = 14.6, which is in conflict with your statement “Each stage has a gain of around 67”. Am I missing something here?

    Thank you in advance.

    • Looking for thoughts, ideas, and information on sending data using sound. This will be from transducer to transducer in a direct line of sight, not looking at a reflected signal off a target. What are some maximum distances that can be expected, using reasonably low cost transducers? I am requiring about 200 feet. Is this even remotely possible? What are some suggested transducers to work with, and sources for same? — Thanks for any and all comments, good or bad.

  • Hi Kerry,

    This is a great tutorial and very helpful. I am curious though… would it be possible to track the position of an independent moving transmitter with 4 fixed receivers – given a fixed starting position to allow for calibration? I am working with an arduino, however it seems as though I will need to create my own transmitter and receiver. http://forum.arduino.cc/index.php?topic=317927.0

    Thanks for your help!

  • Congratulations. Interesting intiguing project. I would like to use similar to record how close cars come to an object. Have you noted the response time. A car might pass a point in a tenth of a second. Is this circuit fast enough to respond to that? I am having difficulty finding this sort of information.

  • hi, i use a hc-sr04 ultrasonic sensor for the use of detect obstacles.
    but they cover only the 200cm. but i need some extended coverage.
    how to amplify the soundwaves. is there any possibility to extend the distance coverages?

  • Hi look you must use 40khz transducers and drive with an op amp simple as that. I feel that U.S. R not the best way to go too many things interfere u need to go laser to get 100% accuracy n no interference

  • Hello Kerry,

    Thanks for your help. I have a few question.
    1. In the schematic for the transmitter there is no polarity shown for the ultrasonic sensor connection. So does it not matter which terminal is connected?
    2. In one of the earlier post it is mentioned that the Transmitter bridge circuit is upside down. Is this post incorrect?
    3. My ultrasonic sensor has a resonant frequency of around 1 MHz and internal impedance of around 200 ohm. Does this mean I need to change the design?

    Thanks in advance

    • 1. The transducer I used does not have polarity. Most ultrasonic sensors do not have polarity. For the receiver, if one lead of the sensor is connected to the sensor casing, you should use that one as ground as it will pick up less noise.
      2. The bridge drawing had been corrected here.
      3. For 1MHz transmitter you will most certainly need to redesign the transmitter/receiver circuitry as the Opamp does not have enough bandwidth to provide meaningful gains at your desired operating frequency.

  • Hi,
    I want to build ultrasonic sensor with following requirements
    1. Single transmitter and receiver – i.e. transceiver – both transmission and reception with same transducer
    2. transducer needs to be water proof
    3. Max distance to measure 2 feet
    4. the entire circuit needs to be powered by 3V button battery

    Can you please let me know how do I achieve these requirements? I read on top of this article , to achieve first requirement we need to multiplex.

    Can you please give me detailed instructions to achieve these requirements?


  • I have a question about the bandpass filter. when i used numerical values in this picture , i get value of bandwidths from about 120khz to 370khz
    it is more ten times than bandwidths that you said. so i know if that is precise enough.

  • I don’t quite get how your code works for the startTransducer. I’ve built your circuit and ran the code, but my results are terribly inaccurate and the number floats like crazy. It doesn’t help that your code is poorly documented and has almost no comments. Why do you write both pins 9 and 10 low, yet don’t reference hooking up to pin 9 in the document? I don’t quite follow how you transmit, or how he program receives the signal. Perhaps if you elaborate I could figure out where my issues lie. Thank you!

    • Hi Frankoman,

      pin 9 and 10 work together in PWM mode, that was why they were both initialized. But I only used pin 10 to drive the sensors. I think the first step in isolating the problem is to make sure that the PWM signal output looks correct and then you can see the waveform across the ultrasonic sensors.

      • I wasn’t getting the correct waveform, but added another switching diode in parallel facing the opposite direction which worked. This allowed biasing in both directions. However my numbers are still way off. How would you change the circuit for 40kHz sensors? Thanks again!

  • I have some doubts about pin9. Where should it be connected?

    I have read in some comments that pin 9 and 10 work together in PWM mode, but I don’t get were should be the pin 9 connected.

    Some people say that pin 9 is not necessary. So, can I use the same code (without highing and lowing pin9) and it should be the same?

    Thank you!

  • Hi. I’m doing something similar to this but the problem is that am using a pic16f690 and the codes I’ve tried are not working.
    Can you help me with a code to try and see if it works. Thanks

  • Hi Kwong,
    Could you please suggest the transistors to be used when we use the Vcc=12V in the transmitter circuit?
    Thanks in advance.

      • Hi,
        Is this correct? You said earlier that you can’t put more than 6V through these transistors. I tried hooking the transmitter circuit to 12V and transistors heated very hot very fast. Could you suggest transistors for 12V usage?

  • A few questions about your driver design.

    First what is the load resistance / impedance of the transmitter device?

    I looked at a data sheet for a device (transmitter) and it appears to be around 1,000 ohms.

    Second, since the bridge circuit has no capacitors or inductors and the transistors at best have zero resistance how do you multiply the voltage beyond the VCC-GND differential.

    A capacitor which stores the voltage would allow doubling of the voltage when reversing the push-pull direction but your circuit doesn’t have one.

    You mentioned the transistors getting warm.

    Is it possible that the heating of the transistors has nothing to do with the load (transducer) and the transistors are “on” simultaneously in the same leg of the push-pull circuit during transitions. The transistor stays on until the base voltage is about a diode drop to the rail. I realize this is a current gain device.

    A search of the internet shows the transducer can be driven by a CD4013 flip-flop which is a low current device or a 555 with a single transistor so your push-pull circuit is pretty much a poor solution.

    I’m just starting my research for an eventual ultrasonic scanner project.

    I thought the Arduino board such as the Uno could source and sink 50ma, not sure about any protection resistors which may lower the current rating.

    I’m not likely to find my way back to this website so I would appreciate an email.

    Thanks for the information.

    Joe Berardi

  • Hi Mr. Kwong! First, I would like to thank you for the very detailed instructions. A helpful site, indeed.
    Now I would like to ask what portion of the circuit is to be changed since I plan on using a 40 Khz trasnmitting and receiving transducer. Thank you in advance Sir for your answer!

  • Mr. Wong, I build your circuit, but to no luck, it doesn’t work. The measurements are inaccurate. Could you help me? I’m really in need of a person who cold help.

  • Kerry Wong
    – Hi Sir! Thank you very much for this work of yours. Now, I want to ask,
    1. You said above that after transmitting the waves of 24khz frequency, a ‘millisecond’ delay would be done since ‘the received signal takes much longer time to fade’. However, a 300us delay is what is indicated in your code. Why is it Sir?
    2. The upper limit for you loop is 256. I’m working on a 40khz transmitter Sir. How could I set up such upper limit? And lastly,
    3. What does the line delayMilliseconds(1) represent after t_peak = t_start? Because I tried varying the value like delayMilliseconds(500) etc.. However, the only change I got is that it either starts with higher or lower distance value, but is still inaccurate.

    Thank you in advance for your answer Sir.

  • Mr. Wong what modifications should I do in the receiver side if I am to use a 40khz transducer?What happens to the code and the circuit?

  • My oscilloscope is showing only the negative component of the transmitter. The probe’s ground lead is connected to the other side of the transducer and the probe itself to the other. The signal looks good but it’s only -5.5V to 0V, so the peak to peak is not double the VCC, it’s the same (but inverted).
    Any help is greatly appreciated.

  • Hello, I build the reciever circuit with opamp LM358, and tested it with another transmitter (TR). When the TR is off Arduino nano V2 clon gives (taking the hightest value from each second) 350( max 1024) and when TR is on Arduino says 650. I think because there is only one diode to rectify half wave signal it only get half power. But my question is :
    When i power the US reciever with 9V or 5 batteries the above happens, but when I power it with Ardu nano 5 volt out it always says 650, being or not connected the US TR. Did u know why this is happening?

  • Hi, are piña 9 and 10 un phase?. And is there a way to chante it forma pwm, so forma example pin 9 is 180 degrees from pin 10, so when 10 is up 9 is down?

  • would you please please please upload another tutorial on how to make 40khz version of this?? I’ve tried everything from changing the code to using other RC values but I can’t get my circuit to work. and no else in the comments seems to have got to work either.

  • Hi, i want to design under water sound velocity meter with tx frequency 1Mhz 10vpp . i have arduino uno kit and waterproof 1Mhz sensors. hc-sr04 module working with 40Khz. i want replace with 1Mhz Tx & Rx so please help me how to make Tx & Rx circuit.

Leave a Reply

Your email address will not be published.