Tuesday, May 15, 2012

Arduino - HC-SR04 ultrasonic distance sensor

Last Christmas as part of my stocking fillers I got an HC-SR04 ultrasonic distance sensor.
Like most of my electronic bits it's a cheap generic device from ebay.  It's a small sensor that is suppose to do the same thing as the Ping sensor but for less money.


I finally unwrapped it and found a library for Arduino IDE 1.0 at HERE.  There is even some sample code to read the HC-SR04 and display the results on an LCD display.


Wiring is really simple
VCC - 5V
GND - GND

Trig - Trigger Pin you define in the code
Echo - Echo Pin defined in the code

Since I don't have an LCD display (yet) I modified the code to use the Serial Monitor as the output.
Code Below:

    #include "Ultrasonic.h"

      int TriggerP = 13; // Trigger Pin for Sensor
      int EchoP = 12; // Echo Pin for Sensor
     
      Ultrasonic ultrasonic(TriggerP,EchoP);   
   
       void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
      Serial.print("Distance: ");
      Serial.print(ultrasonic.Ranging(CM)); // Get Range in Centimetres
      Serial.println(" Cm.");
      delay(1000);
      Serial.println("..."); // Next lines.
    }

This worked great up to about 16cm.  But beyond that it started to give me some random numbers greater than 4000, so I'd expect not very robust.

I continued my search and found the following code that doesn't use any library, and this code even does the Serial Monitor as the output so no modification needed.


/*
 HC-SR04 Ping distance sensor]
 VCC to arduino 5v GND to arduino GND
 Echo to Arduino pin 13 Trig to Arduino pin 12
 More info at: http://goo.gl/kJ8Gl
 */

#define trigPin 12
#define echoPin 13

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  int duration, distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1000);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  if (distance >= 200 || distance <= 0){
    Serial.println("Out of range");
  }
  else {
    Serial.print(distance);
    Serial.println(" cm");
  }
  delay(500);
}

This code performed better, working out to about 24cm.  
While doing my research on using the HC-SR04 I did find a post (somewhere...) stating that when powering from USB the 5V line can be a little bit off so this might be part of my problem.

But, using either method I have a sensor that is good up to 15cm which could be good enough for a small autonimous robot as if I'm within 15 cms I will need to look around for another direction.

NOTE: If you are using a version of the Arduino IDE before 1.0 then at the following LINK you can get the relevant library.  It looks like it's the same as the 1.0 library and has similar performance.

The hunt is on to see if there is a way of getting a reading beyond 24cm that is reliable.

Loving the tinkering.


UPDATE:
I combined some of the code from the Library with the direct code and now it reliably(ish) without detailed testing will work to 70cm.

The modified code is below.


/*
 HC-SR04 Ping distance sensor]
 VCC to arduino 5v GND to arduino GND
 Echo to Arduino pin 13 Trig to Arduino pin 12
 More info at: http://goo.gl/kJ8Gl
 */

#define trigPin 13
#define echoPin 12

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  long duration, distance;
  digitalWrite(trigPin, LOW);  // Added this line
  delayMicroseconds(2); // Added this line

  digitalWrite(trigPin, HIGH);
//  delayMicroseconds(1000); - Removed this line
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  if (distance >= 200 || distance <= 0){
    Serial.println("Out of range");
  }
  else {
    Serial.print(distance);
    Serial.println(" cm");
  }
  delay(500);
}

Once again, I love this Tinkering.


17 comments:

  1. It returns always 'out of range', perhaps my sonar is broken..

    ReplyDelete
    Replies
    1. I know a mistake I made was getting the wires backwards as I mounted the sensor at the edge of the board I had the pins wired incorrectly.

      Also, check out the 2 links above for other code that might be worth trying.
      I have afeeling with the cheaper sensors things may not always be 100% as they should be.

      Finally, if none of that works try messing with the delays in the code above. It might be that thy need to be adjusted for your specific sensor.

      Delete
    2. Echo to Arduino pin 13 Trig to Arduino pin 12 says the comment in the starting of the code, change the pins and it will work!

      Delete
    3. That worked for me, good job Ayush

      Delete
  2. I think its funny as heck seeing some webstores and ebay sellers quoting this unit as accurate from anywhere from 200cm to 500cm!!!

    The updated code works great with my Uno R3 and the HC-SRO4 I just bought for £6 ($10). Its exact (Tested and confirmed manualy) to about 80cm, pretty good to around 105cm but makes some mistakes ~5-10cm on some softer surfaces (ie a sofa or a cushion) and on solid walls its good to about 120cm with around a +/- 3cm-5cm margin of error from 105cm-120cm, after that it seems to start going down rather then up but wierdly then has an area at about 220cm-250cm where it is accurate again to just a few cm on solid objects (walls etc)...
    Fair Acuarcy to over a meter and near perfect under 60cm is fine by me as its going into a robotics project and I only need it acurate to around 50cm max and in that range this code and the HC-SRO4 is perfect with at most a 5mm(0.5cm) margin of error on any surface.
    Thanks for the code.

    ReplyDelete
    Replies
    1. Yeah works great with my Uno R3 too, got mine on Amazon for $5 US. I have a working display and need to figure out how to get the data to print to the screen & would like serial too. :D

      Delete
  3. I have noticed that if you get a little dust or a hair or anything like that on the 2 protective meshes then that can make it throw up constant out of range errors as well as throw off results it does publish.
    If you are get a problem with out of range errors then run a small paint brush over the mesh and give it a light blow (not with compressed gas/air cans or anything tho)

    ReplyDelete
  4. I bought the same sensor, But mine has only 3 pins. (1) GND (2)5V (3) Sig. Here's the Datasheet: http://www.rhydolabz.com/documents/sensors/Ultrasonic%20Distance%20Sensor%20Serial%20Output-User%20Manual.pdf

    Instead of digital output it gives serial output. Can anyone help me with the code for serial communication with a sensor. There are many tutorials for serial communication but all they do is communicate with the PC, Help me read the serial output of this sensor.

    ReplyDelete
  5. Try this modified code:

    #define trigPin 13
    #define echoPin 12
    #define TIMEOUT 40000 // 40ms timeout (the HC-sr04 has 38 ms timeout)

    void setup()
    {
    Serial.begin (19200);
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    digitalWrite(trigPin, LOW); // Ensure triger is starting with low befre any pulse
    delayMicroseconds(20); // Delay before first pulse
    }

    void loop()
    {
    long duration, distance;

    digitalWrite(trigPin, HIGH); // Start the High Pulse

    delayMicroseconds(10); // Delay 10 micros

    digitalWrite(trigPin, LOW); // End the Pulse
    duration = pulseIn(echoPin, HIGH, TIMEOUT);
    distance = (duration/2) / 29.1;

    if (distance >= 400 || distance <= 0)
    {
    Serial.println("Out of range");
    }
    else
    {
    Serial.print(distance);
    Serial.println(" cm");
    }
    delay(50);
    }

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Hi Vedant,

    For 3-pin version - maybe it comes from Parallax? - check out this example: http://learn.parallax.com/kickstart/28015.

    Arduino code is near bottom of page. Upshot is that Arduino pin connected to "SIG" is set to output to send a ping, and then that same pin is set to input to read the result!

    - Mike

    ReplyDelete
  8. If you can´t get values accurate enought make the sensor wait longer: it´s just about the right timing...or at least it works with me...

    ReplyDelete
    Replies
    1. Also, changing the baudrate to 115200 seems to make it more accurate o.O

      Delete
  9. Try this as well. I basically got rid of the delay() and replaced it with millis(). This lets the Arduino work on other things without pausing it.

    /*
    Modified code to use without delay() functions.
    */

    int trigPin = 2;
    int echoPin = 13;

    unsigned long currentTime;
    unsigned long loopTime;

    unsigned long currentTime2;
    unsigned long loopTime2;

    long duration;
    long distance;

    void setup() {
    Serial.begin (9600);
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    }

    void loop() {

    currentTime = millis();
    if(currentTime >= (loopTime + 200)){
    ping();
    loopTime = currentTime; // Updates loopTime
    }
    }

    void ping(){

    digitalWrite(trigPin, HIGH);
    currentTime2 = millis();
    if(currentTime2 >= (loopTime2 + 1000)){
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);
    distance = (duration/2) / 29.1;
    if (distance >= 200 || distance <= 0){
    Serial.println("Out of range");
    }
    else {
    Serial.print(distance);
    Serial.println(" cm");
    }
    loopTime2 = currentTime2; // Updates loopTime2
    }
    }

    ReplyDelete
  10. how can we send the data from ultrasonic sensor to cosm?

    ReplyDelete