Let's Make Robots!

I feel dumb

It all started when I was programming PopPet. I was using the simple way of using the HC-SR04:

  long duration, distance;

  digitalWrite(trigPin, LOW); 

  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH);

  delayMicroseconds(10);

  digitalWrite(trigPin, LOW); 

  duration = pulseIn(echoPin, HIGH);

  distance = (duration/2) / 29.1; 

This was all well and good except for one thing. If there is no echo from the ping, the pulseIn hangs and freezes the code for a whole second.

This wreaked havoc on the simplest obstacle avoidance routine as the bot would just spin in a circle. I wanted to conquer this delay, so I went to google and started looking for ways to be rid of the pulseIn.

My first thought was to run some sort of micro timer and manually calculate the distance by calculating the time it took to go high to low with a micros subtraction.

This didn't work for me. I figure I was too simplistic in my code or was barking up the wrong tree. So I decided to see if I could use a for loop. Using a for loop I could attempt to trigger the trig pin and set a timer, if no echo is heard in that time frame it exits and returns a 0. This also didn't work.

I came to the SB to see if someone could spark my next idea, Basile did not disappoint. He mentioned the NewPing library.

Many of you know that the NewPing library makes the use of such ultrasonic sensors much easier, no tricky timings are needed, you just need to tell it to trigger and it triggers.

One of the big benefits of this library though is the fact that is does not have this one second delay. I did no however want to import the whole library into the sketch as I am using the DAGU Mini Driver, a great board, but small on space.

Basile mentioned looking in the actual library files and seeing how they did it. Let's just say I spent way to long trying to figure it out. Being the first time looking at a library I was confused how it all linked and in the end I resorted to a bag of chips and Dr.Phil.

After my brief session watching stupid people, and making myself feel better, I returned to the conundrum at hand. I thought, hey, why not look up what the Arduino site has to say about pulseIn. This is when I realized I was dumb.

Little did I know that the pulseIn function actually has a timeout feature, and by default, this value is one second. All I had to do was set the timeout value much lower and guess what, the bastard of a thing worked perfectly. Absolutely no lag at all and incredibly quick sensor readings, faster than I can actually physically test.

Moral of the story? RTFM and don't be an dumb dumb head.

duration = pulseIn(echoPin, HIGH, 2000);

 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

thanks for posting this CP!  It's always good to know when others make mistakes and feel frustrated.  Helps keep the rest of us pushing on when we hit those bumps ourselves.  I always find that watching some mindless TV (my guilty pleasure is 80's action movies on Netflix) helps me solve problems.  I think it's because in the background my brain is ruminating on the problem without me focusing on it.

I wouldnt bother with

distance = (duration/2) / 29.1; 

Use this instead:

distance = duration / 58; 

The AVR cannot divide in hardware, it has to software emulate it which is slow. No point dividing twice if it can be done once. Also floating point cannot be done in hardware so again needs software emulating. The space and time wasted might not be significant on PopPet, but why waste it when easily avoided?

If you don't need a constant set of units to compare with other types of sensors, I'd forgo the division totally.

The duration variable is already proportional to the distance, and if you're comparing distance to some constant, you can #define constants for these distances that are already multiplied by 58.

If you need the distance in proper units, then you might be able do right shifts to divide by multiples of 2.

  1. You could check to see if the margin of error is such that dividing by 64 is good enough. That would be something like:

    distance = duration >> 3;

    If you have a good compiler it should translate a division by 64 into a right shift.

  2. If that isn't good enough, then to get an integer division by 58, you can factor 58 into the appropriate exponents of 2 and make multiple shifts to do this. Right now my pain pills have kicked in big time, so I will leave this as an exercise for the reader. Sorry.

I probably wouldn't do this sort of thing on a BBB or RasPi, but the AVR needs all the help it can get. :)

I learned this trick back in the day when I was programming on a 6502.

For the life of me I cannot work out why anyone bothered to write, or search for a library for ping sensors simply to replace a function which only has 3 or 4 lines of code.

Now you have answered the question for me. Because it is much easier to search for a library on the internet, download and install it, then read it's instruction manual instead of the Arduino reference that is already installed on your computer. Silly me.

Personally I have a low opinion of anyone who uses any sort of ping library. Below is my reason why.

//====================================================== Measure distance in cm with ultrasonic range finder ===========
void Ultrasound()
{
  digitalWrite(ustrigpin,1);                          // trigger ultrasonic pulse 
  delayMicroseconds(10);                              // wait 10uS
  digitalWrite(ustrigpin,0);                          // complete pulse trigger
  usdistance=int(pulseIn(usechopin,HIGH,17500)/58);   // measure width of output pulse from range finder in cm up to 3m
}

This is my function for reading a ping sensor (from my OB1 code). To take code as simple as this and make it into some sort of library to make it easier for people is like making 100Kg paperweights, yes it will hold the paper in place but you will need a crane to lift it enough to put the paper underneath.

Dispite the disclaimer in the title, you really went off on CP there.

In my head at least, when a bloke says "I'm stupid" and shows off his mistake, you share a common bond, and some story of when you flubbed. You don't tell him you have a low opinion of him.

We are all at different levels in different areas... I can't see bashing anyone for pointing out their mistakes though.

 

-James

No, I was not having a go at CP. I was just having a rant (it was a hot day with no airconditioning, we are moving to a new factory).

I also make stupid mistakes and I have also created bogs or forums when I do.

There is merit for the library. The included example shows it being able to trigger 15 sensors without freezing the code on delays, in just a few lines. The library also does not just work with the HC-SR04, but many other sensors in which the output is not so simple. In my basic robotics tutorials it is much easier for the newbies to use the library as logically it easier for them to understand. You just tell it to ping and you get a distance. 

And I would believe the 'not picking on you personally' if I didn't see you picking on me in the SB the other day about my livestream. Credit to JerZ for trying to hide it from me by spamming the SB, but I saw it.

It can do more than read a single sensor. Even if you are dead set against loading up NewPing, you would probably do well to make your short batch of code into a lib and save having to retype it all the time.

It's a function, you call it the same way and can be easily modified to read more than 1 sensor.