measuring within a range ultrasonic sensors

Hi all this is my first post on here but I have been following posts for a while.
my question is how do I make my ultrasonic sensors measure within a range I.e my sketch measures in percentage and i would like it to measure from 100% to 0% on tank1 and from 0% to 100% on the other
and only measure within that range. How can i achieve this please.

//Distance measure in cm converts to persentage

#include <NewPing.h>
const int trigPin1 = 6; //Trigger pin for sensor 1.
const int echoPin1 = 7; //Echo pin for sensor 1
const int trigPin2 = 8; //Trigger pin for sensor 2
const int echoPin2 = 9; //Echo pin for sensor 2
int pause1 = 5; //5 millsecond delay
int pause2 = 10; //10 millisecond delay
int Distance, Distance2, Duration, Duration2, percentage, percentage2;
int TankDepth1 = 26; // put your tank 1 depth here.
int TankDepth2 = 20; // put your tamkk 2 depth here.
const int MAX_DISTANCE = 30;

NewPing Sonar1 (trigPin1, echoPin1, MAX_DISTANCE);
NewPing Sonar2 (trigPin2, echoPin2, MAX_DISTANCE);

void setup() {
pinMode (trigPin1, OUTPUT); //Trigger pin 1 output
pinMode (echoPin1, INPUT); //Echo pin 1 input
pinMode (trigPin2, OUTPUT); //Trigger pin 2 output
pinMode (echoPin2, INPUT); //Echo pin 2 input
Serial.begin(9600);

}

void loop() {
digitalWrite (trigPin1, LOW); //Trigger pin 1 low
delay(pause1);
digitalWrite (trigPin1, HIGH); //Trigger pin 1 high
delay(pause2);
digitalWrite (trigPin1, LOW); //Trigger pin 1 low
Duration = pulseIn(echoPin1, HIGH);
Distance = Duration * 0.034/2; //convert duration to distance in cm
percentage = (100*Distance/TankDepth1); //convert distance to percent
percentage = 100 - percentage; // makes the percentage 100-0

digitalWrite (trigPin2, LOW); //
delay(pause1);
digitalWrite (trigPin2, HIGH);
delay(pause2);
digitalWrite (trigPin2, LOW);
Duration2 = pulseIn(echoPin2, HIGH);
Distance2 = Duration2 * 0.034/2;
percentage2 = (100*Distance/TankDepth2);

Serial.print ("TANK1 ");
Serial.print (percentage);
Serial.println ( "%");
delay(1000);
Serial.println();
Serial.print ("TANK2 ");
Serial.print (percentage2);
Serial.println ( "%");
Serial.println();
delay(1000);

}

firstly, please use [code ] tags to make your most more readable.

secondly, be very careful when performing math and mixing integers and floats. For example these lines:

  Distance = Duration * 0.034/2;      //convert duration to distance in cm
  percentage = (100*Distance/TankDepth1); //convert distance to percent

might not give you the results you expect due to intermediate truncation errors.

thirdly, I don't really get your problem? You want to prevent values >100 and <0?

percentage = constrain(percentage, 0, 100);

Why create NewPing objects for your sensors and then not use them?

To constrain your values to a range you could use the 'constrain()' function.

 percentage = constrain(percentage, 0, 100);

@TimMJN

Hi thanks for the reply what should i do to prevent this problem?. Would i make distance and duration floats?

secondly, be very careful when performing math and mixing integers and floats. For example these lines:

Distance = Duration * 0.034/2; //convert duration to distance in cm
percentage = (100*Distance/TankDepth1); //convert distance to percent

thirdly, I don't really get your problem? You want to prevent values >100 and <0?

Hi no what I want is it to measure from 100% to 0% not go over 100%. Hope that explains a little better.

The standard Arduino library includes a "map()" function that translates numbers in some range to numbers in some other range: map() - Arduino Reference

MrMark:
The standard Arduino library includes a "map()" function that translates numbers in some range to numbers in some other range: map() - Arduino Reference

Be warned that inputs that are outside the input range will result in outputs that are outside the output range.

tooter:
@TimMJN

Hi thanks for the reply what should i do to prevent this problem?. Would i make distance and duration floats?

For accuracy, yes I would recommend making distance a float. Duration is returned as an int, so you want to keep that.

  Distance = (float) Duration * 0.034/2.;      //convert duration to distance in cm
  percentage = (100*Distance/TankDepth1); //convert distance to percent

You see I changed "2" into "2.". I keep it as a best practice to only use floats in float expressions, to prevent hard-to-debug truncation errors.

Depending on your measurement resolution requirements, you could also consider making percentage and TankDepth floats.

int TankDepth1 = 26;       // put your tank 1 depth here.
int TankDepth2 = 20;       // put your tamkk 2 depth here.

The ultrasonic distance sensor won't measure down to a distance of zero. The sensor should be at least a few cm above the maximum tank level. That means that you need a distance for both full and empty.

percentFull = map(distance, TANK1_EMPTY_DISTANCE, TANK1_FULL_DISTANCE, 0, 100);
percentFull = constrain(percentFull, 0, 100);

Wow thanks for alllthe useful replys. I will try them out and report back latter thanks.

Note: Since you are converting to "percent full" there is no need to convert from Duration to Distance. It will be more accurate to use the duration values directly:

   Duration2 = pulseIn(echoPin2, HIGH);
  percentage2 = map(Duration2, TANK2_EMPTY_DURATION, TANK2_FULL_DURATION, 0, 100);
  percentage2 = constrain(percentage2, 0, 100);

Hi thanks for all the help so far i'm struggling to get it to work. For some reason the serial monitor only displays 100% no matter how far or close sensors are. this is what i changed.

I added tank full int.

int TankFull = 2;
int TankFull2 = 2;

Added map commands.

Duration = pulseIn(echoPin1, HIGH);  
  percentage = map(Duration, TankDepth1, TankFull, 0,100);
  percentage = constrain(percentage,0,100);

and removed old calculations.

 //Distance = Duration * 0.034/2;      //convert duration to distance in cm
  //percentage = (100*Distance/TankDepth1); //convert distance to percent
  //percentage = 100 - percentage;          // makes the percentage 100-0

Did i miss anything?.

tooter:
Added map commands.

Duration = pulseIn(echoPin1, HIGH);  

percentage = map(Duration, TankDepth1, TankFull, 0,100);
 percentage = constrain(percentage,0,100);




and removed old calculations.


//Distance = Duration * 0.034/2;      //convert duration to distance in cm
 //percentage = (100*Distance/TankDepth1); //convert distance to percent
 //percentage = 100 - percentage;          // makes the percentage 100-0




Did i miss anything?.

If you listed only the changes you made then what you missed was converting "TankDepth" from Distance (cm) to Duration (microseconds). If you forgot to list anything then you missed listing that thing you forgot to list. It's really hard to tell without seeing the resulting sketch. :slight_smile: Does it at least compile without warnings or error?

As others have pointed out you create NewPing sonar objects but never use them!

If you did then the whole exercise becomes fairly trivial

#include <NewPing.h>     // Use the NewPing library

// Wiring
const int trigPin1 = 6;     // HC-SR04 trigger connected to pin 6
const int echoPin1 = 7;     // HC-SR04 echo connected to pin 7

// Constants to define the tank
const int tank1Full = 3;      // depth measured when tank 1 is full
const int tank1Empty = 26;   // depth measured when tank 1 is empty
const int maxDistance = 28;  // Sets a maximum distance for the sensor object N.B. must be greater than the empty value

NewPing sonar1(trigPin1, echoPin1, maxDistance);  // Create a NewPing sonar object

int measuredDistance = 0;      // Stores the measured distance to liquid surface
int percentage = 0;             // Stores the calculated percentage of tank volume


void setup() {
  Serial.begin(9600);      // Start the serial port
}

void loop() {
  measuredDistance = sonar1.ping_cm();                                             // Request the distance to liquid surface from the sonar object (in cm)
  if ((measuredDistance > tank1Empty) || (measuredDistance < tank1Full)) {  // Sanity check the distance
    Serial.print("Measurement Error - Sonar reads ");                          // If it's outside bounds print an error message
    Serial.println(measuredDistance);
  }
  else
  {
    percentage = map(measuredDistance, tank1Empty, tank1Full, 0, 100);      // Convert the measured distance to a percentage of the tank depth
    Serial.print("Contents of tank 1 ");                                                  // Print it out.
    Serial.print(percentage);
    Serial.println("% Full");
  }
  delay(1000);
  
}

A couple of things to note:-

The distance from the sonar unit to the surface of the liquid when the tank is full must be at least 2cm (a bit more is better, say 3 to 4cm) or you will have problems with faulty readings.

The percentage is only a true reading of the volume in the tank if the cross-sectional area of the tank remains constant through the range.

Adding code for a second tank is left as an exercise for the reader.

Hope this helps

Ian

johnwasser:
If you listed only the changes you made then what you missed was converting "TankDepth" from Distance (cm) to Duration (microseconds). If you forgot to list anything then you missed listing that thing you forgot to list. It's really hard to tell without seeing the resulting sketch. :slight_smile: Does it at least compile without warnings or error?

Hi it dose compile but the readings are out i will try what you suggested thanks.

IanCrowe:
As others have pointed out you create NewPing sonar objects but never use them!

If you did then the whole exercise becomes fairly trivial

#include <NewPing.h>     // Use the NewPing library

// Wiring
const int trigPin1 = 6;    // HC-SR04 trigger connected to pin 6
const int echoPin1 = 7;    // HC-SR04 echo connected to pin 7

// Constants to define the tank
const int tank1Full = 3;      // depth measured when tank 1 is full
const int tank1Empty = 26;  // depth measured when tank 1 is empty
const int maxDistance = 28;  // Sets a maximum distance for the sensor object N.B. must be greater than the empty value

NewPing sonar1(trigPin1, echoPin1, maxDistance);  // Create a NewPing sonar object

int measuredDistance = 0;      // Stores the measured distance to liquid surface
int percentage = 0;            // Stores the calculated percentage of tank volume

void setup() {
  Serial.begin(9600);      // Start the serial port
}

void loop() {
  measuredDistance = sonar1.ping_cm();                                            // Request the distance to liquid surface from the sonar object (in cm)
  if ((measuredDistance > tank1Empty) || (measuredDistance < tank1Full)) {  // Sanity check the distance
    Serial.print("Measurement Error - Sonar reads ");                          // If it's outside bounds print an error message
    Serial.println(measuredDistance);
  }
  else
  {
    percentage = map(measuredDistance, tank1Empty, tank1Full, 0, 100);      // Convert the measured distance to a percentage of the tank depth
    Serial.print("Contents of tank 1 ");                                                  // Print it out.
    Serial.print(percentage);
    Serial.println("% Full");
  }
  delay(1000);
 
}




A couple of things to note:-

The distance from the sonar unit to the surface of the liquid when the tank is full must be at least 2cm (a bit more is better, say 3 to 4cm) or you will have problems with faulty readings.

The percentage is only a true reading of the volume in the tank if the cross-sectional area of the tank remains constant through the range.

Adding code for a second tank is left as an exercise for the reader.

Hope this helps

Ian

Wow Ian thanks a lot for doing that rely appreciate it. What i'm going to do in the interest of learning in re write the code so I can understand it better and try to add tank 2. Thanks again.

tooter:
Wow Ian thanks a lot for doing that rely appreciate it. What i'm going to do in the interest of learning in re write the code so I can understand it better and try to add tank 2. Thanks again.

No problem, have at it old bean. It's worth exploring the NewPing library as it takes all the pain out of using the HC-SR04 transducers.

Ian

IanCrowe:
No problem, have at it old bean. It's worth exploring the NewPing library as it takes all the pain out of using the HC-SR04 transducers.

Ian

Yer I see that now. I just didn't understand it (but learning all the time). I managed to add the second sensor last might. After a very late night I also added some lcd output that works. I just need to add a percentage bar that gets bigger as the percent is higher if that makes sense so overall very happy. Thnaks again.

Ok so just a quick update for anyone interested. The project seems to be coming on leaps and bounds the last few days. I've hooked up the lcd and got it to print the percentage of water left in the tank and a scaling bar that goes up and down with the water levels on tank one. All I need to do now is add a switch to turn on the back light for 5 seconds and some how (If anyone has any ides on how to achieve this) is to add a second press of the button to scroll from tank 1 levels to tank 2 levels. that would be great thanks.

The backlight code is easy. Every time you detect a button press, you record millis() and turn on the backlight. Separately in loop(), you always check the saved value minus millis(). Any time the difference is more than 5000, you turn off the backlight. This procedure is logically independent from any menu code so there's nothing to think about there.

Hi I'm still struggling with the back light button press and the screen cycle. Tried of command but it just kept flashing from one screen to another after initial button press.