Ultrasonic 4 Directions Distance Meter

Hi,

I made a distance meter to use simultaneously in four directions at the same time. It uses an Arduino Mega, LCD 16x2 and 4 sr04 ultrasonic sensors. The idea is to make it usefull to mark the wall to hang a picture and stuff like that. I’d like it to have 4 functions like to change with only one button “Prog”

  1. Measure the distance from the center hole to the four walls
  2. Reset it to 0 in and measure from that point.
  3. Measure the total distance, so you can put it in the ground and know the height of the roof.
  4. Measure the area so it will calculate the area using the distance to the roof and the distance to the wall, etc.
    Also I have a button to change the units to cm or inches

I think I have the 1, 3 and 4 solved but I don’t know how to solve the 2 and the unit conversion.
Besides, I am getting wrong measures using the library newping. I get 1 or 2cm more in a meter, 5cm more in 2 meters and 12 or 13 cm more in 4 meters.

I am kind of a noob with the code, this is what I have until now:

#include <LiquidCrystal.h>
#include <NewPing.h>
#define SONAR_NUM     4 // Number or sensors.
#define MAX_DISTANCE 500 // Max distance in cm.
#define PING_INTERVAL 200 // Milliseconds between pings

LiquidCrystal lcd( 12, 10, 6, 5, 4, 3 );

unsigned long pingTimer[SONAR_NUM]; // When each pings.
unsigned int cm[SONAR_NUM]; // Store ping distances.
uint8_t currentSensor = 0; // Which sensor is active.
const int buttonPin = 40;
const int button2Pin = 44;
int buttonState = 0;

NewPing sonar[SONAR_NUM] = { // Sensor object array.
  NewPing(22, 24, MAX_DISTANCE),
  NewPing(26, 28, MAX_DISTANCE),
  NewPing(30, 32, MAX_DISTANCE),
  NewPing(34, 36, MAX_DISTANCE),
  };

void setup() {
   lcd.begin(16, 2);
   pinMode(buttonPin, INPUT);
   pingTimer[0] = millis() + 75; // First ping start in ms.
   for (uint8_t i = 1; i < SONAR_NUM; i++)
   pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {

    if(digitalRead(buttonPin) ) {
      // increment count
      buttonState++;
      // debounce
      delay(300);
      
      }

    if (buttonState > 3){
       buttonState = 0;
       }
 
   for (uint8_t i = 0; i < SONAR_NUM; i++) {
     if (millis() >= pingTimer[i]) {
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;
      if (i == 0 && currentSensor == SONAR_NUM - 1)
      oneSensorCycle(); 
      sonar[currentSensor].timer_stop();
      currentSensor = i;
      cm[currentSensor] = 0;
      sonar[currentSensor].ping_timer(echoCheck);
     }
   }


}

void echoCheck() { // If ping echo, set distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { 

switch (buttonState) {
    case 0:
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print(cm[0]+7);
      lcd.setCursor(7,1);
      lcd.print(cm[1]+8);
      lcd.setCursor(0,0);
      lcd.print(cm[2]+6);
      lcd.setCursor(13,0);
      lcd.print(cm[3]+6);   
      lcd.setCursor(0,1);
      lcd.print("Hole");
      break;
    case 1:
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print("0");
      lcd.setCursor(7,1);
      lcd.print("0");
      lcd.setCursor(0,0);
      lcd.print("0");
      lcd.setCursor(13,0);
      lcd.print("0");
      lcd.setCursor(0,1);
      lcd.print("Rel.");
      break;
    case 2:
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print(cm[0]+15);
      lcd.setCursor(7,1);
      lcd.print(cm[1]+15);
      lcd.setCursor(0,0);
      lcd.print(cm[2]+13);
      lcd.setCursor(13,0);
      lcd.print(cm[3]+13);
      lcd.setCursor(0,1);
      lcd.print("Total");
      lcd.setCursor(14 ,1);
      lcd.print("cm"); 
      break;  
     case 3:
//area up/right up/left
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print((cm[0]-15)*(cm[2]-13));
      lcd.setCursor(13,0);
      lcd.print((cm[0]-15)*(cm[3]-13));  
// Area down/left down/right
//      lcd.setCursor(0,1);
//      lcd.print(cm[1]*cm[2]);  
//      lcd.setCursor(13,1);
//      lcd.print(cm[1]*cm[3]);  
      lcd.setCursor(6,1);
      lcd.print("Area");    
     break;
  }
 }

Besides, I am getting wrong measures using the library newping.

The values are probably as accurate as the sensor allows.

      // debounce
      delay(300);

That's about 30 times as long as is needed for debouncing.

Thanks for answering PaulS,

I am having accurate values without the newping library, so it is not the problem with the sensors.

The original code uses a delay of 33ms, I changed it because it was so fast It was complicated to read.

I don’t understand why it works perfectly when I use the pulseIn() function but it does not with the newping library using the example code, can it be my arduino mega is not working properly or maybe I’m using the last version of Arduino?

I am trying this code, the second one works the first doesn’t:

// ---------------------------------------------------------------------------
// Example NewPing library sketch that does a ping about 20 times per second.
// ---------------------------------------------------------------------------

#include <NewPing.h>
#include <LiquidCrystal.h>

#define TRIGGER_PIN  22  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     24  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 500 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
LiquidCrystal lcd( 12, 10, 6, 5, 4, 3 );
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  lcd.begin(16, 2);
}

void loop() {
  delay(50);                      // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
  unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
  lcd.setCursor(0,0);
  lcd.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance and print result (0 = outside set distance range, no ping echo)

}
#include <Wire.h>
#include <LiquidCrystal.h>
#define trigPinU 22
#define echoPinU 24

LiquidCrystal lcd( 12, 10, 6, 5, 4, 3 );

int maximumRange = 500; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long durationU, distanceU; // duracion distancia arriba

void setup()
{
  lcd.begin(16, 2);
  //asigna pins sensores
  pinMode(trigPinU, OUTPUT);
  pinMode(echoPinU, INPUT);
}

void loop()
{
  lcd.setCursor(0,0);
   //sensor Up
  digitalWrite(trigPinU, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPinU, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPinU,LOW);
  durationU= pulseIn(echoPinU, HIGH);
  distanceU = durationU/58.2;
 if (distanceU >= maximumRange || distanceU <= minimumRange){
   /* Enviar un número negativo para ordenador y LED enciende
para indicar "fuera de rango" */ 
  
  lcd.print("OUT");

 }
 else {


  lcd.print(distanceU);


 }

Cool project !
You should post it in the Exhibition/Gallery.

Speed of sound is 343.5 meters/second, which translates to about 29.11us/cm.

Roundtrip would be 58.22us/cm, but newping library defines US_ROUNDTRIP_CM as 57us/cm and pulsein defines it more correctly as 58.2us/cm. That's where the inaccuracy comes from.

Speed of sound is 343.5 meters/second, which translates to about 29.11us/cm.

The speed of sound depends on a number of factors - to say it is a particular value is nonsensical.

Well, I should have specified at sea level at 20 degrees Centigrade. I guess you can find a table of different altitudes/temperatures and calculate the value relevant to your location.

There's an interesting page on the subject here:-
Calculation of the Speed of Sound in Air and the effective Temperature

Interesting read. I always thought altitude mattered as the speed of sound is most often listed at sea level.

In that case, the difference in the speed of sound should be very minimal for this project, as one can assume that it will be used indoors at relatively constant temperatures.

Semidigital:
Interesting read. I always thought altitude mattered as the speed of sound is most often listed at sea level.

In that case, the difference in the speed of sound should be very minimal for this project, as one can assume that it will be used indoors at relatively constant temperatures.

Depends on how you define "relatively constant temperatures".
Here it varies between about 15C and 40C indoors. That's 340.3m/s to 354.7m/s.
Thankfully, it's not often at 15 or 40 though.

Still, it's not a big deal to integrate temperature sensing and alter the calculation accordingly.

Thank you so much! I’ll try to modify the US_ROUNDTRIP_CM and see what happens

Hi again,

I'm kind of stuck with the prog 2. I'd like to reset to 0 all the measurements when I go to that program saving them in variables and then calculate the relative distances from that point subtracting them to the total distance. The thing is... well as I said I am kind of new in Arduino and I don't have a clue about how to do that :frowning: because those measurements are constantly updating and are continuously overwriting the variables.

Anyone have an idea about how to solve this before I delete that program?

I don't have a clue about how to do that

Nor do you seem to be able to describe precisely what you want to do.

I'd like to reset to 0 all the measurements when I go to that program

What program? It seems to me that "that program" should return some measurements. Setting "the measurements" to 0 is something that "that program" should do, if it is not able to make the measurements.

saving them in variables

Saving what, in what variables?

and then calculate the relative distances from that point subtracting them to the total distance.

Relative to what? "Subtracting to"? Is that like reading to a book or writing from some paper?

because those measurements are constantly updating and are continuously overwriting the variables.

Isn't that what should happen?

It sounds vaguely like what you want to do is to, when some event happens (such as a switch becoming pressed), you want to save the current measurements as baseline measurements, and then calculate stuff relative to the baseline measurements. But, you need to clarify exactly what you are talking about.

Thank you for your time PaulS. You're right I'll try to explain it better.

As I said in the first post, I want it to have 4 different functions. The first one "Hole" will show in the display the measurements from the walls, roof and floor to the center hole like this:

10cm 50cm 40cm
80cm

Now if I press the "Prog" button, I'll go to the Rel. program and all these numbers will go 0cm like this:

0cm 0cm 0cm
0cm

And if I move it now 10cm to the right, for example, it'd show:

0cm 0cm 10cm
0cm

And if I move it now 10cm to the right, for example, it’d show:

I would expect that if you moved the thing 10cm to the right that the left number would show +10 and the right number would show -10. Why do you see it differently?

If the object of the device is to display dimensions and you move it 10 cm closer to the wall on the right then I would expect the initial reading "X" to change to (X-10) to the right wall and (X+10) to the LEFT wall.( upper and lower dimensions remain the same)

Oh shit I think you're right.

Let me explain myself again. Imagine what I want is to hang 2 pictures on the wall and the first one goes at 47cm from the beginning of the left wall, and the display shows the measures like this:

left up right
down

so I move the device until I get this:

47cm 100cm 200cm
60cm

Ok, I put a mark there and now I want to mark the 2nd one at 76cm from the first one, so I press that button and all the measures goes to 0:

0cm 0cm 0cm
0cm

and then move to the right until I get 76 in the left and the up and down remains 0 so I can be sure I keep the same distance to the floor and ceiling

76cm 0cm -76cm
0cm

So now the I am getting 76cm in the left to the first mark where the first picture goes and the total distance to the beginning of the wall would be 122. And I get 122-47=76 in the left, in the right would be 124-200= -76

And the code would be something like this:

if(digitalRead(buttonPin) ) {
// increment count
buttonState++;
if (buttonState == 1){
diffU = cm[0];
diffD = cm[1];
diffL = cm[2];
diffR = cm[3];
}
switch (buttonState) {
...
case 1:
lcd.clear();
lcd.setCursor(7,0);
lcd.print(cm[0] - diffU);
lcd.setCursor(7,1);
lcd.print(cm[1] - diffD);
lcd.setCursor(0,0);
lcd.print(cm[2] - diffL);
lcd.setCursor(13,0);
lcd.print(cm[3] - diffR);
lcd.setCursor(0,1);
lcd.print("Rel.");
break;
...
}

If you read the forum rules and knew where the CODETAGS button [</>] was
THEN

the code would

LOOK

something like this:

 if(digitalRead(buttonPin) ) {
      // increment count
      buttonState++;
      if (buttonState == 1){
        diffU = cm[0];
        diffD = cm[1];
        diffL = cm[2];
        diffR = cm[3];
      }
switch (buttonState) {
...
    case 1:
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print(cm[0] - diffU);
      lcd.setCursor(7,1);
      lcd.print(cm[1] - diffD);
      lcd.setCursor(0,0);
      lcd.print(cm[2] - diffL);
      lcd.setCursor(13,0);
      lcd.print(cm[3] - diffR);
      lcd.setCursor(0,1);
      lcd.print("Rel.");
      break;
...
}

Sorry, I forgot