Agree with AWOL's proposal , especially as the original code mixes type (false=bool and ints)

you can even make it a macro:

#define convert_cm(echotime) ((echoTime) / US_ROUNDTRIP_CM)

After learning that false===0 in C++, I've had to rework some things. Basically, I want a ping to return false (zero) if there's no ping echo within the distance allowed. Also, if there is a ping echo, the result needs to be >0. We don't want to confuse a <1 inch ping echo with infinity as this difference would be very important to what you're using the sensor for.

In an case, I've reworked a bunch of the code to accommodate this and to give expected results. Here's the macro that's used for both cm and inch conversion:

echoTime is obviously the microsecond time and conversionFactor is either US_ROUNDTRIP_CM or US_ROUNDTRIP_IN. It may appear that it's overly complex with code reduction possible. But, I need to make sure 0="no ping echo" and we never get a 0 for a really close range (happens with inches). If there's a better way do write this macro, let me know.

I'm not really sure the "volatile" qualifiers are necessary, except for "_echoInput", either.

"pulseInNew" may as well be "inline"

Without the "volatile" it won't compile, which is why I used it. Feel free to correct me if I'm wrong.

You're right, I should have made pulseInNew inline, in a hurry and it was late I guess. I've made it inline now. But, that's a part of the code I need to totally rework as I'd really like to see it totally event driven (or an option to have it event driven at least). I really hate delays or small loops that wait for an event without processing something else.

That makes it ideal to use the negative values as error codes, but those should be in the primary ping function

True, but the logic is not with the ping echo, it's with the conversion to inches and cm. And this is where it can be zero as the sensor can read something closer than an inch, which yields a zero. Technically, it should never happen with cm. But, I'd rather go the safe route.

Making errors negative is basically what I'm doing, but with zero as the error value. Which is why the code is written that way, to accommodate the zero error indicator. Making the error a negative doesn't remove the need for that code.

No-one said you added them on a whim, but you can get rid of the error message with a simple cast.The only reason to have volatile qualifier is for polling loops on registers, and the only register you poll is the one associated with the echo pin.

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.Do not send technical questions via personal messaging - they will be ignored.

No-one said you added them on a whim, but you can get rid of the error message with a simple cast.The only reason to have volatile qualifier is for polling loops on registers, and the only register you poll is the one associated with the echo pin.

Gotcha. I assumed there was some very good reason why it was asking for a volatile qualifier. The only value now with a volatile qualifier is *_echoInput

With that said, it didn't change my code size at all, so I suspect the compiler optimized the code identically both with and without the volatile qualifier. Or, maybe I just got lucky and the compiled code is just coincidentally the same length.

I had the sensors already plugged in on a bread board so, I wiped the code additions together so I could see the results. Thank you for pointing out the ability to time pings using the bit of code you already had in the sketch, in my rush I missed the clear comments that you had in the sketch for timing the pings. I will not use delay on my next usage!

True, but the logic is not with the ping echo, it's with the conversion to inches and cm. And this is where it can be zero as the sensor can read something closer than an inch, which yields a zero. Technically, it should never happen with cm. But, I'd rather go the safe route.

thats why you should include rounding in the conversion functions (or do mililmeters, or 1/16th)

I had a closer look at the conversion functions and you should revisit them:

Speed of sound is 340.29 m/sec => US_ROUNDTRIP_CM = 58.77

that means that US_ROUNDTRIP_CM should be rounded to 59 iso 58 and US_ROUNDTRIP_IN 149 iso 148?

True, but the logic is not with the ping echo, it's with the conversion to inches and cm. And this is where it can be zero as the sensor can read something closer than an inch, which yields a zero. Technically, it should never happen with cm. But, I'd rather go the safe route.

thats why you should include rounding in the conversion functions (or do mililmeters, or 1/16th)

I had a closer look at the conversion functions and you should revisit them:

Speed of sound is 340.29 m/sec => US_ROUNDTRIP_CM = 58.77

that means that US_ROUNDTRIP_CM should be rounded to 59 iso 58 and US_ROUNDTRIP_IN 149 iso 148?

These rounding errors add up !!

I knew this was going to happen...

I originally had a longer comment about the speed of sound in my library, but removed it as it seemed a little too preachy and bordered on a rant. Basically, it talked about how there's actually some debate as to the speed of sound, if you can believe it. We can measure the speed of light and time within the smallest margins to track your location down to 3 meters with cheap GPS technology, but there's a debate on how fast sound travels and what influences that speed.

Google reports the speed of sound as 340.29m/s. The speed Google reports is only true when the temperature is 59 degrees (not a typical temp in most situations). Wikipedia gives the speed as 343.2m/s in "dry air" at 68 degrees, yet the humidity, pressure, altitude, etc. makes no difference in the speed (only the temperature affects the speed). The actual speed of sound at 73 degrees (a fairly typical testing temperature) is 344.838m/s. See this page for details: http://www.sengpielaudio.com/calculator-speedsound.htm

I'm going to use 73 degrees as the standard, as I consider 73 a good average temperature in most situations and works out to a number very close to an integer: 57.998. So, the first problem with converting time to distance is everyone has a different opinion on how fast sound travels, and it really is different for different temperatures. Using 58 for US_ROUNDTRIP_CM is actually almost perfectly accurate at 73 degrees. Your 58.77 value would only be accurate if it was 59 degrees, which I believe is a little cold for real-world situations. If that's your current temperature, by all means, change US_ROUNDTRIP_CM to 58.77.

The next problem is that I believe there's some overhead or delay either before the ping or reading the echo. Some sensors' documentation state this delay, but most do not. Actual measurements confirm this, showing times being way off at close distances but getting more accurate at longer distances. This indicates that there's some processing overhead going on, which makes small readings off, and longer readings more accurate. I've actually already done this testing and calculation and for my sensors I would add 97 microseconds to make the results closer to accurate over the full range of the sensor.

So, a more accurate conversion from microseconds to cm assuming 73 degrees would be cm=(microseconds+97)/57.998. The adding of this 97 microseconds will be addressed at some point in my library, once I have compiled enough sensors to actually confirm this is a fairly fixed value for multiple devices by different manufactures.

Next... There's the issue of the actual pulseIn timing code in Arduino. I'm not 100% confident the technique is "sound" (no pun intended). While I've tried to streamline the pulseIn function, I still don't like it. It's done in a sequential in-line manner with a loop instead of event-driven. How it does the timing is based on the processing cycles for the loop, not time. I intend on looking into this further and hopefully writing an event-driven version of pulseIn that is still (basically) accurate but also doesn't send the program off into a loop rendering the processor useless while it waits for a ping echo.

Next... These sensors really can't get a measurement out to 500cm. It's more like 400cm or less. Some quote 500cm, so I figured I should make that the max, just in case. So, while it's true calculation errors get larger at longer distances, in the real-world it's not quite as drastic.

Finally, there's the issue of using floating point values which require additional libraries to be compiled taking up program space and additional processor cycles at execution time. That's why I used integers instead of fractions. It seems silly to make US_ROUNDTRIP_CM 57.998, when the accuracy of the sensor is +/- 0.3cm, we're guessing at the temperature, we know the sensor has some overhead, and the timing code is in question.

If we could assume that pulseIn was perfectly accurate, the correct full calculation would be as follows (it would also require a temperature sensor):

// ---------------------------------------------------------------------------// Ballpark numbers for US_ROUNDTRIP_CM and US_ROUNDTRIP_IN were used. Feel free to change if more// accurate readings for your testing temperature and situation are needed. The values don't need// to be integers. But, using integers will save program space. And honestly, we're talking// microseconds here. If we're off by a few dozen microseconds one way or another does it really// matter? The HC-SR04 isn't that accurate to begin with to fuss too much with this.// ---------------------------------------------------------------------------

So, if your testing environment is 59 degrees, feel free to change US_ROUNDTRIP_CM to 58.77 and take the performance and program space hit. Or, leave it at 58 and enjoy the fairly close to accurate results.

Hi,Great subject; I really like this kind of detailed discussion about a good subject... Thanks for the work writing the library.

Tim, one of the sensors we were talking about has a built-in temperature sensor: This one: http://goo.gl/Ox2rP

This is the one that has both UART mode and Pulse/echo mode. The temperature measurement only works in UART mode.. The docs I have say:---------------------( COPY )--------------------------Temperature function only in UART mode. TX send 0X50 trigger temperature measurement. When temperature measurement is completed, the module will return a byte temperature ( tDATA ), The actual temperature is tDATA-45 . For example, by TX sending 0X50 , RX received 0x45 , then the temperature at this time is [69 ( 0x45 to 10 decimal value) -45] = 24 degrees C-----------------( END COPY )----------------------

Of course temperature can be measured with a DS18B20, or etc also...

Maybe you can actually do temp compensation?? Maybe only important for OutdoorBots...