Ultrasonic Rangefinder (SRF05) Expected Results?

Hi all,

I've wired up an SRF05 ultrasonic range finder to my Arduino, and used the sketch from here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1179936636

My results vary from around 220,000 downwards. Is this to be expected? The SRF05 tech page at robot electronics states that if you divide by 58, you get a result in cm. Evidently this is not the case.

Any ideas why? Is it usual to get such high readings from the sensor? It seems that the readings are accurate (around 20cm away, I get 200000, 10cm away I get approx 100000), and I've tried with two sensors so I don't think it's a hardware problem. It's just that the results don't match with what others seem to be getting. Possibly something to do with the serial communication and the omission of a decimal point somewhere?

Any ideas?

The SRF05 works in two modes:

  1. The "SRF04 Compatibility mode"
  2. and the SRF05 which is the default.

There's not much difference operationally between these two modes, but they require different connections.

Check the Devantech site to find out how you can connect it.

I have an SRF05 on my Arduino Diecimila and works great.

teoxan

Hi teoxan, thanks for the reply.

I'm aware there are two operating modes for the SRF05. I'm using the single pin mode. However, dividing by 58 does not give results in cm.

Anything below 10cm, I get a 6 digit number. So for 5cm, I get a result of 500000. Above that (i.e. above 10cm), I get a 7 digit number. E.g., 20cm gives 2000000. Up until 100cm, if I removed the last 5 digits, I would get an approximate answer in cm. Above 100cm I still get a 7 digit number, and removing the last 4 digits would give me an approximate result in cm. It seems the result is truncated after 7 digits...

I'm not sure if the result is getting truncated or what (it's an unsigned long... so it shouldn't, I don't think). But I can't just cut off a constant number of digits, as >10cm and >100cm both give a 7 digit number.

Any ideas why this is? At the moment I'm using an unsigned long for the pulse duration, and for the distance. When displaying this result to the LCD, I'm using ltoa(), which presumably could be the cause of errors except for the fact that even outputting the raw values to serial gives the same results...

I'm a bit stumped here. I'm sure it's something obvious that I'm missing. But there is no way that dividing by 58 gives a cm result.

Suggestions?

Regards,

Thom

Check this site to get an idea of the code being used:

http://letsmakerobots.com/node/1669

Also, another good site for Arduino and sensor examples:

There's an example for SRF05 there.

teoxan

Yeah I've read both of those - my code does appear to be correct, and I'm getting consistent results; just not what I expected.

I've done as much research as I can into this before posting here.

Could you send me the code you use and some examples of results please? I think that might be helpful. I've tried both modes and get the same results. I've also tried it on two different Arduinos, with two different SRF05 sensors, so I really don't know what's going on!

Cheers,

Thom

Here's the code I use:

//Code for using SRF05 with Arduino and Wiring
//SRF05 works in default mode-using same pin for pulse
// and echo
// The Mode pin of SRF05 is connected to Ground

int SRF05pin = 8; //connect to digital pin 8
unsigned long ultrasoundDuration;

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

void loop() 
{
 pinMode(SRF05pin, OUTPUT); //pin is output
 digitalWrite(SRF05pin, LOW);
 delayMicroseconds(2);
 digitalWrite(SRF05pin, HIGH);
 delayMicroseconds(10);
 digitalWrite(SRF05pin, LOW);
  
  pinMode(SRF05pin, INPUT); // pin is now input
  // wait for a high pulse
  ultrasoundDuration = pulseIn(SRF05pin, HIGH);
  // get results
  Serial.print(ultrasoundDuration);
  Serial.print(ultrasoundDuration/148, DEC); //divide with 58 and you get cm
  Serial.print(" inches");
  Serial.println();
  delay(100);
}

I hope this works for you.

teoxan

Hmmm yeah that's pretty much the code I've been using. If I try it with (ultrasoundDuration/58) I get this sort of result:

2032433 cm
2031355 cm
2030278 cm
2028122 cm
1988252 cm
2024890 cm
2031355 cm
2032433 cm
2022735 cm
812500 cm
813577 cm
2031355 cm
2031355 cm
2019502 cm
2020579 cm
2029200 cm
2030278 cm
845905 cm

Strange... I'm not sure what else to try here!

Here's the full code just in case there's something I'm missing...

int ultraSoundpin = 6;
unsigned long ultrasoundDuration = 0;

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

void loop() {

  // switch pin to output
  pinMode(ultraSoundpin, OUTPUT);

  // send a low, wait 2 microseconds, send a high then wait 10 microseconds
  digitalWrite(ultraSoundpin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultraSoundpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(ultraSoundpin, LOW);

   // switch pin to input
  pinMode(ultraSoundpin, INPUT);

  // wait for a pulse to come in as high
  ultrasoundDuration = pulseIn(ultraSoundpin, HIGH);


  // output
  Serial.print(ultrasoundDuration/58, DEC);
  Serial.print(" cm");
  Serial.println();
  delay(2000);
}

I think I found what maybe your problem.

Change the unsigned long to int.
Create another variable, for example "ultrasound2" and put there the
result from the division "ultrasoundDuration/2".

Divide it by 58 or 148 and you get correct results.

I don't know how to explain this yet, but another friend of mine had the same problem with you with his Arduino.
So, i tried the way I tell you and it worked...

teoxan

Gah tried that, and I get even more erratic results! Hehe, I'm not sure what's going on here at all. I'll check this method on my other Arduino and the other SRF05 unit later on, for now here's the (new) complete code, after halving the ultrasound duration before dividing by 58.

int ultraSoundpin = 6;
char disp_string[80];
unsigned int ultrasoundDuration = 0;
unsigned int ultra_dist = 0;

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

void loop() {

  // switch pin to output
  pinMode(ultraSoundpin, OUTPUT);

  // send a low, wait 2 microseconds, send a high then wait 10 microseconds
  digitalWrite(ultraSoundpin, LOW);
  delayMicroseconds(2);
  digitalWrite(ultraSoundpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(ultraSoundpin, LOW);

   // switch pin to input
  pinMode(ultraSoundpin, INPUT);

  // wait for a pulse to come in as high
  ultrasoundDuration = pulseIn(ultraSoundpin, HIGH);
  ultra_dist = (ultrasoundDuration/2);
  // output
  Serial.print(ultra_dist/58, DEC);
  Serial.print(" cm");
  //Serial.print(dist);
  //Serial.print(" cm");
  Serial.println();
  delay(2000);
}

I've tried this with unsigned ints and longs, and with a long for the duration and an int for the distance... just gives me random results from 7-500 odd....!

Thom

A long shot.

Maybe it's because yourdelay is too short ?

Quote from the delayMicroseconds() description in the reference:

This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

To ensure more accurate delays, this functions disables interrupts during its operation, meaning that some things (like receiving serial data, or incrementing the value returned by millis()) will not happen during the delay. Thus, you should only use this function for short delays, and use delay() for longer ones.

Thanks for that - I tried changing the value for the delay, but sadly it didn't help. This seems to be an unusual problem - I've tried this new code with two Arduinos and two SRF05 units, and the same results are obtained.

I'm sure I've read pretty much everything I can find about this range finder on the net, and there don't seem to be any other suggestions to try.

Could it be something to do with my arduino software set up? I have only tried compiling and running this on my laptop, with arduino0011 and arduino0012 IDE, running on Ubuntu.

Cheers for the help so far guys, but are there any more (however long) shots?

I'm pretty sure the timing readings from the SRF05 are accurate - they're consistent when an object is placed at a fixed distance away.

The problem is the conversion. If I do (pulsetime/10000)/58 I get correct results for dist > 100cm but inaccurate below.

So, for (actual dist) = 200cm, the result will be 200cm, but the result for (actual dist) = 20cm will also be 200cm. Could it be something to do with the pulseIn method returning a value in mS rather than uS? I could hack something together that divides by 10000 for some range of pulse times, and by 100000 some other ranges, to make the numbers fit. But this seems like I'm just putting a plaster on things; curing rather than preventing.

Am I missing something obvious here? It feels like it...

I have the SRF05 right next to me , running the code I posted here, and it works fine..

The example with the distances you gave, means that the SRF05 doesn't actually work.

Now, I can only assume three obvious things:

  1. The SRF05 is damaged
  2. Your cables and your connections are bad
  3. Software problem

Solutions I may think of, providing the SRF05 is not damaged:

  1. Check your cables; also check the connections again.Use only one Mode ( either SRF04 Compatibility or SFR05) and make sure you have all connected properly

Can you tell us what mode you use and the pin connections of your SRF05 and Arduino?

  1. I don't think you have a software problem, but to elliminate that possibilty, you can try all this on a Windows running computer.

teoxan

Dang...

Well, assuming the software is OK it's most likely a cable/USB problem then, as it seems unlikely that I would have bought two faulty Arduinos and/or two faulty SRF05 units, doesn't it? I think I have only one USB cable of this type, I'll see if I can find another and try the combinations of board/sensor/cable on my desktop Linux machine, and my XP machine, and see what happens.

I found some code on a university site somewhere that seems to work... but I'm not sure why.

/* Ultrasound Sensor SRF05 v1
 *---------------------------
 *
 * Reads values (00014-01199) from an ultrasound sensor (3m sensor)
 * and writes the values to the serialport.
 *
 * http://www.xlab.se | http://www.0j0.org
 * copyleft 2005 Mackie for XLAB | DojoDave for DojoCorp
 *
 */

int ultraSoundSignalOut = 7; // Ultrasound signal pin
int ultraSoundSignalIn = 8; // Ultrasound signal pin
int val = 0;
int ultrasoundValue = 0;
int timecount = 0; // Echo counter
int ledPin = 13; // LED connected to digital pin 13

void setup() {
  beginSerial(9600);                  // Sets the baud rate to 9600
  pinMode(ledPin, OUTPUT);            // Sets the digital pin as output
  pinMode(ultraSoundSignalOut, OUTPUT);            // Sets the digital pin as output
  pinMode(ultraSoundSignalIn, INPUT);            // Sets the digital pin as output
}

void loop() {
 timecount = 0;
 val = 0;

/* Send low-high-low pulse to activate the trigger pulse of the sensor
 * -------------------------------------------------------------------
 */

digitalWrite(ultraSoundSignalOut, LOW); // Send low pulse
delayMicroseconds(2); // Wait for 2 microseconds
digitalWrite(ultraSoundSignalOut, HIGH); // Send high pulse
delayMicroseconds(5); // Wait for 5 microseconds
digitalWrite(ultraSoundSignalOut, LOW); // Holdoff

/* Listening for echo pulse
 * -------------------------------------------------------------------
 */

val = digitalRead(ultraSoundSignalIn); // Append signal value to val
while(val == LOW) { // Loop until pin reads a high value
  val = digitalRead(ultraSoundSignalIn);
}

while(val == HIGH) { // Loop until pin reads a high value
  val = digitalRead(ultraSoundSignalIn);
  timecount = timecount +1;            // Count echo pulse time
}

/* Writing out values to the serial port
 * -------------------------------------------------------------------
 */

ultrasoundValue = timecount; // Append echo pulse time to ultrasoundValue

serialWrite('A'); // Example identifier for the sensor
printInteger(ultrasoundValue);
serialWrite(10);
serialWrite(13);

/* Lite up LED if any value is passed by the echo pulse
 * -------------------------------------------------------------------
 */

if(timecount > 0){
  digitalWrite(ledPin, HIGH);
}

/* Delay of program
 * -------------------------------------------------------------------
 */

delay(100);
}

This seems to increment the timecount for every iteration of the while loop where the pin is high - but how does this compute the distance? Does the while loop read the pin at a set interval, and then calculate the distance? This gives me seemingly accurate results but is different to any other way of using the SRF05 that I've seen.

Cheers,
Thom

Well,

by looking at this code, I assume that this is a generic ultrasound code, and using this means you must have your SRF05 connected in "SRF04 Compatibility mode" that uses separate pins for pulse and echo.

The Code I have uses one pin for pulse and echo.

Did you try to use the SRF05 Code with a single pin, but at the same time you had your SRF05 physically connected as "SRF04 Compatibility mode" ?

I will also connect the sensor in SRF04 Mode and try this code.

by the way, by telling you about cables and connections, I also meant the connections of your sensor.
If the USB cable was not good, it wouldn't work at all..Try to install your Linux drivers once again, since Linux has known problems with USB-based controllers and devices.

teoxan

hmmm.

by using this code, I get same problem like you...

but, I used the old again, I replaced delayMicroseconds with delay(), I
used a variable to store the ultrasoundduration/29 ( I got this from an
example with Basic Stamp2), and I get accurate results.

I don't know...I have a Maxbotix Sonar too, and everything runs simpler...just an analog value and there you are.. ;D

teoxan

Where did you use delay() instead of delayMicroseconds()? In the original code that you provided, or one of the ones I've put up since?

As for connections, I've disconnected and reconnected the components several time, and looked at the wiring diagram for the SRF05 every time I've reconnected, so I think I've got it right.

Will have another tinker now and report back if anything interesting happens.

Thanks.