11 November 2012

HC-SR04 Ultrasonic Sensor


Introduction:

The HC-SR04 Ultrasonic Sensor is a very affordable proximity/distance sensor that has been used mainly for object avoidance in various robotics projects . It essentially gives your Arduino eyes / spacial awareness and can prevent your robot from crashing or falling off a table. It has also been used in turret applications, water level sensing, and even as a parking sensor. This simple project will use the HC-SR04 sensor with an Arduino and a Processing sketch to provide a neat little interactive display on your computer screen.



Parts Required:
Freetronics Eleven or any compatible Arduino.
HC-SR04 Ultrasonic Sensor
Mini Breadboard 4.5cm x 3.5cm
Protoshield and female header pins (not essential - but makes it more tidy)
Wires to connect it all together




The Video:




The Arduino Sketch:



     The above sketch was created using Fritzing.





Arduino Code:
You can download the Arduino IDE from this site.

 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
/*
 HC-SR04 Ping distance sensor:
 VCC to arduino 5v 
 GND to arduino GND
 Echo to Arduino pin 7 
 Trig to Arduino pin 8
 
 This sketch originates from Virtualmix: http://goo.gl/kJ8Gl
 Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html
 And modified further by ScottC here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html
 on 10 Nov 2012.
 */


#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED

int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup() {
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}

void loop() {
/* The following trigPin/echoPin cycle is used to determine the
 distance of the nearest object by bouncing soundwaves off of it. */ 
 digitalWrite(trigPin, LOW); 
 delayMicroseconds(2); 

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);
 
 //Calculate the distance (in cm) based on the speed of sound.
 distance = duration/58.2;
 
 if (distance >= maximumRange || distance <= minimumRange){
 /* Send a negative number to computer and Turn LED ON 
 to indicate "out of range" */
 Serial.println("-1");
 digitalWrite(LEDPin, HIGH); 
 }
 else {
 /* Send the distance to the computer using Serial protocol, and
 turn LED OFF to indicate successful reading. */
 Serial.println(distance);
 digitalWrite(LEDPin, LOW); 
 }
 
 //Delay 50ms before next reading.
 delay(50);
}

The code above was formatted using hilite.me





Processing Code:
You can download the Processing IDE from this site.

 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
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* The following Processing Sketch was created by ScottC on
 the 10 Nov 2012 : http://arduinobasics.blogspot.com/
 
 Inspired by this Processing sketch by Daniel Shiffman:
 http://processing.org/learning/basics/sinewave.html
 
*/
import processing.serial.*;


int numOfShapes = 60; // Number of squares to display on screen 
int shapeSpeed = 2; // Speed at which the shapes move to new position
 // 2 = Fastest, Larger numbers are slower

//Global Variables 
Square[] mySquares = new Square[numOfShapes];
int shapeSize, distance;
String comPortString;
Serial myPort;

/* -----------------------Setup ---------------------------*/
void setup(){
 size(displayWidth,displayHeight); //Use entire screen size.
 smooth(); // draws all shapes with smooth edges.
 
 /* Calculate the size of the squares and initialise the Squares array */
 shapeSize = (width/numOfShapes); 
 for(int i = 0; i<numOfShapes; i++){
 mySquares[i]=new Square(int(shapeSize*i),height-40);
 }
 
 /*Open the serial port for communication with the Arduino
 Make sure the COM port is correct - I am using COM port 8 */
 myPort = new Serial(this, "COM8", 9600);
 myPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
}

/* ------------------------Draw -----------------------------*/
void draw(){
 background(0); //Make the background BLACK
 delay(50); //Delay used to refresh screen
 drawSquares(); //Draw the pattern of squares
}


/* ---------------------serialEvent ---------------------------*/
void serialEvent(Serial cPort){
 comPortString = cPort.readStringUntil('\n');
 if(comPortString != null) {
 comPortString=trim(comPortString);
 
 /* Use the distance received by the Arduino to modify the y position
 of the first square (others will follow). Should match the
 code settings on the Arduino. In this case 200 is the maximum
 distance expected. The distance is then mapped to a value
 between 1 and the height of your screen */
 distance = int(map(Integer.parseInt(comPortString),1,200,1,height));
 if(distance<0){
 /*If computer receives a negative number (-1), then the
 sensor is reporting an "out of range" error. Convert all
 of these to a distance of 0. */
 distance = 0;
 }
 }
}


/* ---------------------drawSquares ---------------------------*/
void drawSquares(){
 int oldY, newY, targetY, redVal, blueVal;
 
 /* Set the Y position of the 1st square based on 
 sensor value received */
 mySquares[0].setY((height-shapeSize)-distance);
 
 /* Update the position and colour of each of the squares */
 for(int i = numOfShapes-1; i>0; i--){
 /* Use the previous square's position as a target */
 targetY=mySquares[i-1].getY();
 oldY=mySquares[i].getY();
 
 if(abs(oldY-targetY)<2){
 newY=targetY; //This helps to line them up
 }else{
 //calculate the new position of the square
 newY=oldY-((oldY-targetY)/shapeSpeed);
 }
 //Set the new position of the square
 mySquares[i].setY(newY);
 
 /*Calculate the colour of the square based on its
 position on the screen */
 blueVal = int(map(newY,0,height,0,255));
 redVal = 255-blueVal;
 fill(redVal,0,blueVal);
 
 /* Draw the square on the screen */
 rect(mySquares[i].getX(), mySquares[i].getY(),shapeSize,shapeSize);
 }
}

/* ---------------------sketchFullScreen---------------------------*/
// This puts processing into Full Screen Mode
boolean sketchFullScreen() {
 return true;
}

/* ---------------------CLASS: Square ---------------------------*/
class Square{
 int xPosition, yPosition;
 
 Square(int xPos, int yPos){
 xPosition = xPos;
 yPosition = yPos;
 }
 
 int getX(){
 return xPosition;
 }
 
 int getY(){
 return yPosition;
 }
 
 void setY(int yPos){
 yPosition = yPos;
 }
}

The code above was formatted using hilite.me

 
 



If you like this page, please do me a favour and show your appreciation :

 

 
Have a look at my patreon page.
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
Have a look at my videos on my YouTube channel.


 
 

 
 
 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

55 comments:

  1. Cool. I got it working and it's pretty neat. Gonna toss around some ideas in my head of what I can do with it.

    Thanks.

    ReplyDelete
    Replies
    1. I would be interested to know what you come up with :)

      Delete
  2. My processing screen is all black, i get distance readings in the arduino IDE. why is this?

    ReplyDelete
    Replies
    1. Make sure that you close the Serial Monitor on the Arduino IDE before running the processing sketch.

      Delete
  3. Cool project!
    Where have you downloaded the fritzing part for the ultrasonic sensor?

    ReplyDelete
    Replies
    1. I am pretty sure from the Fritzing website. From memory I think they had a forum where people could contribute Fritzing parts. Have not been to that site for a while but I am pretty sure that's where I got it from. However Fritzing has been through some major changes since then.

      Delete
    2. Here is the download link as of the 21st May 2013:
      DOWNLOAD HERE

      Or alternatively visit the page yourself and search for HC-SR04:
      Fritzing custom parts Webpage

      Delete
  4. Beginner here, I have a 64 bit system therefore I downloaded the 64 bit version of Processing, but when I try to run this example appears "serial is only compatible with the 32-bit download of Processing"

    Any help? Thanks

    ReplyDelete
    Replies
    1. Hi Dan zl,

      I think I fell for the same trap. I had to resort to downloading the 32-bit version instead, because the 64 bit version does not support Serial.

      Scott

      Delete
    2. Thank you very much for taking the time to help me, ...and I´m sorry for taking so long in answer back. At the moment I was hurry trying to finishing a little project, and I have another Chromebook with Ubuntu 12.04 installed, I check there if was working and it does so I just finish it and forget it for about a week. Now in vacation I´m checking some other project to learn something else from your page. Thanks again for all your amazing work.

      Delete
  5. echopin will be high once it receives back the signal. therefore pulsein(echopin, HIGH) will give the duration for which the echopin receives the signal..it will not give the total time for the signal.. but only the time for which the echo sensor receives it..

    ReplyDelete
    Replies
    1. I am not sure what you mean. Can you please explain further. Thanks Scott

      Delete
    2. I am also confused about the same thing. pulseIn reads the length of time where echoPin receives the signal, but shouldn't it read the time between sending the pulse and receiving it with echoPin? In other words woudn't it make more sense to set duration = pulseIn(echoPin, LOW);?

      Delete
    3. Hey Scott,
      I think I'm confused about the same thing here (I'm a beginner so I'm confused a lot).

      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);

      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);

      digitalWrite(trigPin, LOW);
      duration = pulseIn(echoPin, HIGH);

      //Calculate the distance (in cm) based on the speed of sound.
      distance = duration/58.2;

      From what I see, you send a pulse that is 10 microseconds long and then use PulseIn to read the length of that pulse again? Shouldn't it be using LOW instead of HIGH to read the time it takes before receiving the pulse? Maybe I don't understand the PulseIn function well enough or I don't understand the sensor (haven't received mine yet).

      Thanks, Steve

      Delete
    4. HI Steve,

      All examples that I have seen on the net seem to have it set this way.
      I am pretty sure the digitalWrites are there to initialise the sensor, and then the pulseIn measures the pulse. I have read that by setting pulseIn to High, that the sensor will pulse:
      LOW_HIGH_LOW...
      You can try setting it to LOW and see what happens... but I have not seen it setup that way.
      If you do decide to do it that way - then please let me know how you go.

      Regards
      Scott

      Delete
    5. Thanks Scott, I will test this when my sensor arrives.

      Delete
  6. Hello Scott. I would like to ask something. I am new to arduino. I wanna do a project that is a power line detection. So, can this HC-SR04 sensor detect the distance of tight surface like a finger? Have you try to distance measure of tight surface? Thank you.
    Md

    ReplyDelete
    Replies
    1. if it can bounce sound waves, then it will work.

      Delete
  7. New to Arduino IDE. I couldn't get any communication from Arduino Mega 2560 to Processing PDE on my Mac. I couldn't figure out which serial com port to use, so I changed this piece of code;

    /*Open the serial port for communication with the Arduino
    Make sure the COM port is correct - I am using COM port 8 */
    myPort = new Serial(this, "COM8", 9600);
    myPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
    }

    to this;

    /*Open the serial port for communication with the Arduino
    Make sure the COM port is correct - I am using COM port 8 */
    myPort = new Serial(this, Serial.list()[0], 9600);
    myPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
    }

    Now it works fine. I used Daniel Schiffman's sketch Example 19-8: Reading From Serial Port as a basis for making this change. On my Mac /dev/tty.usbmodemfaXXX is the port used for communication with Arduino and Processing. However obvious, I did not realize it was [0].

    How can I determine the actual port number?

    Thanks for the sketch!

    ReplyDelete
    Replies
    1. I know nothing about macs - but I would say you could have a look at the port being used by the Arduino IDE (normally displayed at the bottom of the Arduino IDE)

      Delete
  8. Thats Awesome men, thank for share this !

    ReplyDelete
  9. snowwite and the 7 monkeys11 November 2013 00:15

    perrrrrrrrrrrrrrrrrrrrrrrrrfecto! well as i do say so myself this really helped except i just had to make a weensy change from the diagram with tons of research :)

    ReplyDelete
  10. If found an error ..
    Change : comPortString = cPort.readStringUntil('\n');
    To comPortString = (new String(cPort.readBytesUntil('\n')));

    ReplyDelete
    Replies
    1. thank you now it is working.

      Delete
  11. Hey thank you so much for the diagram and code. The code helped me a lot, since I'm a beginner and I can't write codes yet, although I have started to copy and paste from different codes into one code for my own robot (and it worked:D). Since I have the kind of breadboard that has negatives and positives, I had to bring the wires from the 5V and GND into the - and +. But the sensor is awesome, thank you so much!

    ReplyDelete
    Replies
    1. yea, hashbrown's right. thnx a lot scott!

      Delete
    2. That's great hashbrown, and you are welcome anonymous.
      Feel free to post a link to your project or share a video of your robot in action.

      Delete
  12. When I try to run the processing sketch, an error comes up saying; the function readStringUntil(char) does not exist. When that happens, this line of code is highlighted; comPortString = cPort.readStringUntil('\n');
    I'm a beginner, and would appreciate the help

    ReplyDelete
    Replies
    1. This is a problem with the new version of Processing:
      Change : comPortString = cPort.readStringUntil('\n');
      To: comPortString = (new String(cPort.readBytesUntil('\n')));

      Delete
  13. i did what you explainned in the picturte should i copy the code on the arduino program by the word or i'm going to takeoff some things

    ReplyDelete
    Replies
    1. If you plan to run this complete project. You can copy and paste the arduino sketch and upload it to the arduino. And then copy and paste the processing sketch to the processing IDE, and run it. However you may need to modify the com port based on you specific setup and operating system.

      Delete
  14. One question about the cubes Scott, which part needs to be changed so when the application starts cubes are up and with going far from sensor they come down?

    Thanks...you are the best

    ReplyDelete
    Replies
    1. I cannot remember if this works or not - but feel free to try
      change this:
      distance = int(map(Integer.parseInt(comPortString),1,200,1,height));
      to
      distance = int(map(Integer.parseInt(comPortString),1,200,height,1));

      Delete
  15. hi can anyone help me? i got a problem running the code its say that >processing.app.SerialNotFoundException: Serial port 'COM1' not found. Did you select the right one from the Tools > Serial Port menu?

    please help me, thanks!

    ReplyDelete
    Replies
    1. Make sure to connect and upload the Arduino Sketch to the Arduino before running the Processing sketch. Make note of which com port you are using for your Arduino. Look at the bottom right hand side of the Arduino IDE (after upload).
      Also make sure to close the Arduino IDE Serial Monitor before running the Processing sketch.

      Delete
    2. thanks Scott i solve the problem, but i have another problem here > avrdude: stk500_getsync(): not in sync: resp=0x00

      can u help me again? thanks in advance!

      Delete
    3. What Arduino board are you using? Have you selected this board in the Arduino IDE?
      And have you confirmed you are using the correct COM port?

      Delete
  16. Is there any codings for crack detection in a plain surface using Ulrasonic sensor??..

    ReplyDelete
    Replies
    1. not on this blog - but someone surely has done this somewhere on the internet

      Delete
  17. Hiii
    Please if I have parallax ping ultrasonic sensor how I connected it with arduino and how programming it to send data through xbee sheild and module? .
    I hope to help me....

    ReplyDelete
    Replies
    1. I don't have a parallax ping ultrasonic sensor - but this site may help.
      As for XBee communication - I have an partially completed tutorial which may help you to get started, but there are many tutorials out there on the internet that show you how to do this.
      Try to do each of these separately before trying to join or combine them.

      Delete
  18. the second block of code throws so many errors. the first one is ok. how do i know if it worked???

    ReplyDelete
    Replies
    1. Dunno !
      Vague question, vague response. Need to be a bit more specific.

      Delete
    2. Actually I had white screen and it was at com8 and i use com3. I am noob... um, now it has black screen with blue boxes at the bottom but nothing moves...when i hover my hand. :/ what may i do wrong? :/ thankss

      Delete
    3. Actually,

      I think that my sensor is broken. The above is not working...it keeps returning -1 at my serial monitor.

      Delete
    4. Ok seems like you worked through most of your problems.
      Just make sure that you use the 32 bit version of Processing IDE because 64bit version does not support Serial.
      Your sensor keeps returning -1 because it is calculating a distance that exceeds the maximum or minimum ranges. Try to extend these ranges if possible to see the raw values coming through, or just print the raw value instead.
      Using the serial monitor is a good way to check the functionality of the sensor. Once you find values coming through, then use the Processing IDE, but you cannot have the Serial monitor open when you run the Processing sketch because it will create errors.

      Delete
  19. Do i need any extra lib? :/ I read somewhere that i need to download some more lib to work...

    ReplyDelete
  20. This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
    1. Hi Prasad,
      You will need to ask that question in a forum.
      Sorry.

      Scott

      Delete
  21. Hi Scott, great guide. I just wanted to know where you got the value 58.2 from in the line:
    //Calculate the distance (in cm) based on the speed of sound.
    distance = duration/58.2;

    Do you mind explaining the derivation as well please?

    ReplyDelete
    Replies
    1. duration = pulseIn(echoPin, HIGH);

      duration is the amount of time taken for the sound to travel from the module to the object and back in microseconds.
      Sound travels at 340 m/sec.
      or 34000 cm/sec
      or 340 cm/millisecond
      or 0.034 cm / microsecond
      So you can multiply duration (in microseconds) by 0.034 and then halve it to get distance,
      or divide duration by 29.4 and then halve it to get distance.

      (duration/29.4) / 2 = duration/ 58.8

      So how did I get 58.2?
      I used someone else's calculation for the speed of sound, and assumed that the number of 29.1 was correct and multiplied it by 2 to get 58.2. So there you go - you can change that number to 58.8.

      Did that help??

      Delete
    2. What if you wanted inches, ft, or meters? Would you just have to change that "58.2" to something else? Because, as I look at it right now, that "58.2" will give you cm, so can you input another number to give you another unit of distance?

      Delete
  22. Dear Anonymous:
    Thanks for your question. I have deleted your query because I think you would have better success in a forum.
    Arduino Forum
    Processing Forum

    While I would love to work through the problems in your particular project, I just don't have the time.
    I hardly have the time to work through the problems in my own :)


    ReplyDelete

Feel free to leave a comment :