Hello again Instructables community!

This instructable will teach you how to improve the accuracy of an ultrasonic range sensor. It is based on the principal that sound will move through air at different speeds depending on the temperature. Since ultrasonic range sensors use the time it takes for the triggered sound to echo off an object and return to the sensor, the ambient temperature can play a role in the calculated distance.

Potential Applications:

• Improving the accuracy of any ultrasonic range sensor
• Adaptation for similar sensors placed in liquids or gases other than air
• Education

Required Materials:

• Ultrasonic Range Sensor (I use the 4 pin versions, however this will work with a 3 pin version as well)
• Arduino UNO (or other programmable microcontroller)
• TMP36 Temperature sensor (or similar)
• Jumper Cables
• Breadboard

Required Tools:

• Computer with Arduino IDE
• Your Brilliant Self

Step 1: Wire the Components

I have provided a Fritzing diagram to show how to hook up the temperature sensor. Be sure that you look at the datasheet for your particular temperature sensor since some sensors have flipped positive and negative ends. If you plug in your project and the temperature sensor gets really hot really fast, be sure to switch the polarity.

For the temperature sensor, connect the positive and negative wires to the correct terminals on the temperature sensor. Then connect the data terminal to analog pin A0 on the arduino.

I am using a four pin Ultrasonic Range Sensor because I believe it is easier to use than a three pin sensor because with a three pin sensor you have to code the data pin to be both an input and an output. The three pin sensors still work just fine though.

Connect the positive and negative wires to the correct terminals of the range sensor. Connect the trig data pin to digital pin 10 on the Arduino and the echo data pin to digital pin 9 on the Arduino.

Step 2: Code It!

In order to improve the range sensor's accuracy, the code will calculate what the speed of sound is according to the ambient temperature. The formula for the speed of sound through air at a certain temperature is: Vair = (331.3 + 0.606 * Tc) m/s where Vair is the speed of sound and Tc is the temperature in Celsius according to http://en.wikipedia.org/wiki/Speed_of_sound. Once the speed of sound has been calculated, the distance is measured the same way it is in other ultrasonic range sensor codes. The time is multiplied by the speed and then halved leaving you with units of distance to the object.

If you plan on using this in extreme temperatures, be sure to check the temperature sensor's datasheet as they will give a recommended temperature range. Sometimes the temperature sensors will work just fine in a large range but you might need to change the code a little bit to make up for variations of the temperature sensor's output.

Finally, as with all of my code, I am using a simple debug trick my friend taught me. Using a boolean and if statements, you can easily turn serial communication on or off by changing debug to true or false.

I attached the original code file, otherwise the code can be copied directly from here:


Improved Ultrasonic Range Sensing Created by Calvin Kielas-Jensen

Using an Arduino UNO, connect a TMP36 temperature sensor data pin to A0 and a 4 pin ultrasonic range sensor with trig pin on digital pin 8 and echo pin on digital pin 9.

This script improves the accuracy of an ultrasonic range sensor by measuring the ambient temperature. Sound moves through air at a speed dependant on the ambient temperature according to the following equation: Vair = (331.3 + 0.606 * Tc) m/s where Vair is the speed of sound and Tc is the temperature in celcius.

Anyone is welcome to use and modify this code as long as I am given credit. Thank you for respecting the open source movement!

******************************************************************************************************** *******************************************************************************************************/

//The majority of this code is taken and modified from the ARDX temperature sensor code and the PING

//sensor code.

int temperaturePin = A0; //Set the temperature pin input float temperature; //Set temperature variable

boolean debug = true; //For serial communication set debug to true, for faster code set debug to false

long duration, cm; //Set time and cm for distance sensing

int trig = 10, echo = 9; //Set pins for trig and echo

void setup() { if (debug) { Serial.begin(9600); } }

void loop() { temperature = (getVoltage(temperaturePin) - 0.5) * 100;

if (debug) { Serial.println(temperature); }

// Give a short LOW pulse beforehand to ensure a clean HIGH pulse: pinMode(trig, OUTPUT); digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(5); digitalWrite(trig, LOW); duration = pulseIn(echo, HIGH);

cm = microsecondsToCentimeters(duration, temperature); if (debug) { Serial.println(cm); Serial.println("cm"); } }

float getVoltage(int pin) { return (analogRead(pin) * .004882814); //Converting from 0 to 1024 to 0 to 5v }

long microsecondsToCentimeters(long microseconds, long temp) { return (microseconds * (331.3 + 0.606 * temp)) / 2; //Multiplying the speed of sound through a certain temperature of air by the //length of time it takes to reach the object and back, divided by two }

Step 3: Conclusion

In conclusion this instructable improved the accuracy of an ultrasonic range sensor. I uploaded a graph of a my tests to prove that it does indeed increase the accuracy in different temperatures. As you can see, the control varied quite a bit depending on the temperature. Using the temperature sensor, the greatest variation from 30cm was 0.03cm.


  • If you aren't getting any serial readings, make sure that debug is set to true and that all your hardware connections are good.
  • If the temperature sensor is getting really hot, unplug the Arduino right away and switch the positive and negative connections.
  • If you are getting absurd distances, be sure to test the temperature sensor. A faulty temperature sensor can greatly change the distance output.

Future Plans:

  • Integrate this system with more projects
  • Create an underwater ultrasonic range sensor
  • Improve other sensors using similar techniques

My aim of this instructable is to not only teach you how to improve the accuracy of an ultrasonic range sensor, but to open your mind to more possibilities. Even though an ultrasonic range sensor is a simple and well understood sensor, it can still be modified to work even better. When creating projects you should always think about the outside variables. In this case I thought about the temperature, but why not think about exposure to the elements, human interaction, or even extreme conditions out in space. A lot of times people like to create projects that have been designed in a vacuum, but that is not the way the real world works. I hope that you enjoyed my instructable and perhaps learned something too!

If you enjoyed this instructable, please be sure to favorite it and vote for it. Feel free to leave constructive comments!

<p>Hey everyone, my name is Hunter Burns. I saw this tutorial and thought it was great to help improve my project. I am new to Arduino so I am still learning and would love some help. I copied this tutorial to my code, but it says that there is something wrong, no matter what I do. I will post some screenshots for you guys to look at. If anyone can help, I would much appreciate it. Thanks!</p>
Could you post the full code that you are using? From looking at it though, it appears that your functions were not declared correctly. I think you're missing braces for the get voltage function.
<p>#define trigPin 13</p><p>#define echoPin 12</p><p>#define tempAir 24</p><p>#define max_distance 91</p><p>int Buzzer = 9;</p><p>int temperaturePin = A0;</p><p>long unsigned soundSpeed;</p><p>boolean debug = true;</p><p>float temperature = 30;</p><p>void setup() {</p><p> if (debug){</p><p> Serial.begin (9600);</p><p> }</p><p> soundSpeed = 331300+606*tempAir;</p><p> pinMode(trigPin, OUTPUT);</p><p> pinMode(echoPin, INPUT);</p><p> pinMode(Buzzer, OUTPUT);</p><p>}</p><p>void loop() {</p><p> temperature = (getVoltage(temperaturePin) - 0.5) * 100;</p><p> if (debug){</p><p> Serial.println(temperature);</p><p> }</p><p> long duration, distance;</p><p> digitalWrite(trigPin, LOW); </p><p> delayMicroseconds(2); </p><p> digitalWrite(trigPin, HIGH);</p><p> delayMicroseconds(5); </p><p> digitalWrite(trigPin, LOW);</p><p> duration = pulseIn(echoPin, HIGH);</p><p> distance = (duration/2) / 29.1;</p><p> cm = microsecondsToCentimeters(duration, temperature);</p><p> if (debug){</p><p> Serial.println(cm);</p><p> Serial.println(&quot; cm&quot;);</p><p> }</p><p> float getVoltage(int pin) {</p><p> return (analogRead(pin) * .004882814);</p><p> long microsecondsToCentimeters(long microseconds, long temp) {</p><p> return (microseconds * (331.3 + 0.606 * temp)) / 2</p><p> }</p><p> }</p><p> if (distance &gt;= 91 || distance &lt;= 61){</p><p> Serial.println(&quot;Out of range&quot;);</p><p> digitalWrite(Buzzer, LOW);</p><p> } </p><p> else {</p><p> Serial.print(distance);</p><p> Serial.println(&quot; cm&quot;);</p><p> tone(Buzzer, 100);</p><p> delay(300);</p><p> noTone(Buzzer);</p><p> }</p><p> if (distance &gt;= 61 || distance &lt;= 30){</p><p> Serial.println(&quot;Out of range&quot;);</p><p> digitalWrite(Buzzer, LOW);</p><p> }</p><p> else {</p><p> Serial.print(distance);</p><p> Serial.println(&quot; cm&quot;);</p><p> tone(Buzzer, 200);</p><p> delay(300);</p><p> noTone(Buzzer);</p><p> }</p><p> if (distance &gt;= 30 || distance &lt;= 0){</p><p> Serial.println(&quot;Out of range&quot;);</p><p> digitalWrite(Buzzer, LOW);</p><p> }</p><p> else {</p><p> Serial.print(distance);</p><p> Serial.println(&quot; cm&quot;);</p><p> tone(Buzzer, 300);</p><p> delay(300);</p><p> noTone(Buzzer);</p><p> }</p><p> delay(500);</p><p>}</p>
<p>So I took a look at your code and tweaked it a little bit so that it didn't have a compile error. I am in a rush unfortunately so I didn't have the time to look at the logic of it. Hopefully it will work as expected! Here you go:<br><br>#define trigPin 13</p><p>#define echoPin 12</p><p>#define tempAir 24</p><p>#define max_distance 91</p><p>int Buzzer = 9;</p><p>int temperaturePin = A0;</p><p>long unsigned soundSpeed;</p><p>boolean debug = true;</p><p>float temperature = 30;</p><p>long cm;</p><p>float getVoltage( int pin );</p><p>long microsecondsToCentimeters(long microseconds, long temp);</p><p>void setup() {</p><p>if (debug){</p><p>Serial.begin (9600);</p><p>}</p><p>soundSpeed = 331300+606*tempAir;</p><p>pinMode(trigPin, OUTPUT);</p><p>pinMode(echoPin, INPUT);</p><p>pinMode(Buzzer, OUTPUT);</p><p>}</p><p>void loop() {</p><p>temperature = (getVoltage(temperaturePin) - 0.5) * 100;</p><p>if (debug){</p><p>Serial.println(temperature);</p><p>}</p><p>long duration, distance;</p><p>digitalWrite(trigPin, LOW);</p><p>delayMicroseconds(2);</p><p>digitalWrite(trigPin, HIGH);</p><p>delayMicroseconds(5);</p><p>digitalWrite(trigPin, LOW);</p><p>duration = pulseIn(echoPin, HIGH);</p><p>distance = (duration/2) / 29.1;</p><p>cm = microsecondsToCentimeters(duration, temperature);</p><p>if (debug){</p><p>Serial.println(cm);</p><p>Serial.println(&quot; cm&quot;);</p><p>}</p><p>if (distance &gt;= 91 || distance &lt;= 61){</p><p>Serial.println(&quot;Out of range&quot;);</p><p>digitalWrite(Buzzer, LOW);</p><p>}</p><p>else {</p><p>Serial.print(distance);</p><p>Serial.println(&quot; cm&quot;);</p><p>tone(Buzzer, 100);</p><p>delay(300);</p><p>noTone(Buzzer);</p><p>}</p><p>if (distance &gt;= 61 || distance &lt;= 30){</p><p>Serial.println(&quot;Out of range&quot;);</p><p>digitalWrite(Buzzer, LOW);</p><p>}</p><p>else {</p><p>Serial.print(distance);</p><p>Serial.println(&quot; cm&quot;);</p><p>tone(Buzzer, 200);</p><p>delay(300);</p><p>noTone(Buzzer);</p><p>}</p><p>if (distance &gt;= 30 || distance &lt;= 0){</p><p>Serial.println(&quot;Out of range&quot;);</p><p>digitalWrite(Buzzer, LOW);</p><p>}</p><p>else {</p><p>Serial.print(distance);</p><p>Serial.println(&quot; cm&quot;);</p><p>tone(Buzzer, 300);</p><p>delay(300);</p><p>noTone(Buzzer);</p><p>}</p><p>delay(500);</p><p>}</p><p>float getVoltage(int pin) {</p><p>return (analogRead(pin) * .004882814);</p><p>}</p><p>long microsecondsToCentimeters(long microseconds, long temp) {</p><p>return (microseconds * (331.3 + 0.606 * temp)) / 2;</p><p>}</p>
<p>I am happy to hear you are interested in my project! At first glance, I think that the code is missing the function prototype. This code was written in an older IDE which most likely did not require function prototypes. If this is the issue, you can solve the problem by writing the following line above void startup():</p><p>float getVoltage(int pin);</p><p>Let me know if that solves your problem!</p>
<p>same problem as huntbb</p>
I think that the 0.606 constant in the equation is for measuring at sea level, am I correct ? If so, a barometric pressure sensor to compensate would make it even better.
You are very correct! That constant is for sea level. This could be changed if you know the general pressure in your local area, or as you suggested, add a barometric pressure sensor. thanks for your input!
<p>Ultrasonic range sensors can accurately measure distances from about 2 cm to about 3 m. So unfortunately it won't reach the 300 m that are required. I would recommend using a different measurement method. My best guess would be a laser measuring device, but after a very short google search it looks like you'll have to pay about $150 for a device that will measure about 30 m. I'd recommend attempting to make the distance shorter. If you do choose a laser measurement device, you could take into account the atmospheric changes which may bend the light a bit (I don't think that they would make much of a difference for these distances though). </p>
<p>So how accurate does this get? I mean What's the maximum you can measure and does it loose accuracy measuring long distances? Could it measure smth like 300 m? I need it for my project :)</p>
Wow thanks for shearing this and good job finding out an way to improve it! Now my lcd ruler can be even better :D
Happy I can help! It's always fun finding new ways to improve sensors. There are many professional fields that are based entirely on improving sensors by writing code to make up for environmental changes.
<p>Outstanding work! I am seeking such a sensor for measuring distance (non-contact) for measuring an object. The works I have found record the distances in CM's. Is there an Instructable, or modification of your work that can give me measurements in MM's?</p>
In the function microsecondstoCentimeters, instead of dividing by 2, divide by 0.2. This essentially multiplies your final number by 10 which converts CM to MM. If you need more help just let me know!
<p>An excellent piece of work, plus the Boolean debug is a nice touch. Well done.</p>
<p>Brilliant, thanks for sharing this!</p>
<p>Judging by this instructable you have a good head on your shoulders. Thanks for sharing your intelligence with us!</p>
Thanks! I'll be sure to keep sharing my projects as they happen!
I like the Boolean debug. I think I'll start using it. I can even put most of that in a module so I don't have to keep typing &quot; if boolean&quot;
<p>My good friend who works in software suggested that and I regularly use it now. It is such a simple piece of code, but incredibly useful and powerful.</p>
<p>Indeed, since the speed of sound varies approximately as the square root of the absolute temperature, a temperature variation of 20 C results in approximately a 5% change in the speed, thus measured distance. Nicely done.</p>
Thank you! The code would also apply to an ultrasonic range sensor that is submerged in a liquid or in a different gas by using the speed of sound through said medium.

About This Instructable




Bio: I am currently a student in South Dakota. All my life I have been interested in tinkering with electronic amd mechanical gizmos, however after working ... More »
More by MagicByCalvin:Improve Ultrasonic Range Sensor Accuracy  Motion Following Robot 
Add instructable to: