Super Ping for Due

[code]/* Super Ping))) Sensor

This sketch reads a PING))) ultrasonic rangefinder and returns the
distance to the closest object in range to a hundreth of an inch using a Due or Chipkit board.
Most stable at short distances.

The circuit:
* +V connection of the PING))) attached to +5V
* GND connection of the PING))) attached to ground
* SIG connection of the PING))) attached to digital pin 7

http://www.arduino.cc/en/Tutorial/Ping

created 3 Nov 2008
by David A. Mellis
modified 30 Aug 2011
by Tom Igoe

modified to run on the Due at increased resolution
13 Feb 2013
Rick Dumouchelle

This example code is in the public domain.

*/

// this constant won’t change. It’s the pin number
// of the sensor’s output:
const int pingPin = 7;

void setup() {
// initialize serial communication:
Serial.begin(9600);
}

void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
float duration, inches, cm;

// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
//conversions
inches = duration / 74 / 2;
cm = duration / 29 / 2;

Serial.print(inches);
Serial.print("in, ");
Serial.print(cm);
Serial.print(“cm”);
Serial.println();
delay(100);
}[/code]

Don’t know if any one will find this useful, but what the heck. The change is primarily using float’s instead of Long’s for the variables. If you try and use this on a slower Arduino or clone it is just too unstable. The extra processing power of the Due gives good results. Get out your Verniers and check the accuracy for yourself :smiley:

Ooops found and squashed a few bugs.[code]

#include <stdlib.h>

/* Super Ping))) Sensor

This sketch reads a PING))) ultrasonic rangefinder and returns the
distance to the closest object in range to a hundreth of an inch using a Due or Chipkit board.
Most stable at short distances.

The circuit:

  • +V connection of the PING))) attached to +5V
  • GND connection of the PING))) attached to ground
  • SIG connection of the PING))) attached to digital pin 7

http://www.arduino.cc/en/Tutorial/Ping

created 3 Nov 2008
by David A. Mellis
modified 30 Aug 2011
by Tom Igoe

modified to run on the Due at increased resolution
13 Feb 2013
Rick Dumouchelle

This example code is in the public domain.

*/

// this constant won’t change. It’s the pin number
// of the sensor’s output:
const int pingPin = 7;

void setup() {
// initialize serial communication:
Serial.begin(115200);
}

void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
float duration, inches, cm;

// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(5);
digitalWrite(pingPin, HIGH);
delayMicroseconds(10);
digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
//conversions
inches = duration / 74 / 2;
cm = duration / 29 / 2;
if (inches <255 && inches >0 ){
Serial.print(inches);
Serial.print("in, ");
Serial.print(cm);
Serial.print(“cm”);
Serial.println();
delay(10);
}
}
[/code]

It sounds interesting , i will have a try.

It’s fun to switch to floats for the computations, I tried it, but it didn’t increase accuracy too much. Consider how C++ evaluates expressions. As I understand it, C++ groups equivalent operators associatively from right to left: For example, the expression a / b / c is parsed as a/ (b / c), and not as (a / b) / c.

So, the calculation “inches = duration / 74 / 2” becomes “inches = duration / 37”. Then, “duration / 37” rounds the result down to the nearest integer, the remainder is discarded. So you lose at most an inch accuracy.

The inexpensive 2-transducer sensors don’t seem to be that accurate, and will give fairly erratic readings if they are on a moving platform. (No problem, there are $50 ultrasonic sensors you can buy.) What I did was take a weighted exponential moving average of the sensor output:

    int range, rangeavg, duration;
....
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    delayMicroseconds(50);
    digitalWrite(pin, HIGH);
    delayMicroseconds(5);
    digitalWrite(pin,LOW);
    pinMode(pin,INPUT);
    duration = pulseIn(pin,HIGH);
    delay(60);                          // it's important to wait at least 50 msec between pings
    range = duration/74/2;
    if (range > 0) {                  // sometimes the sensor returns 0, discard reading
        rangeavg = (rangeavg + range + range + range) / 4;
    } 

This weights the most recent reading by 3X, you could use 2X or 10X or whatever works best for your project. This filters out the effect of glitches in the ping, since the ping doesn’t always return the distance to the “desired target”. I have a floor-wandering robot that uses these sensors to decide whether to turn L, R, or go straight; the smoothed values make the robot go on a smoother path.