Calculation not right

Hey,

in this project I want to read out the distance from an ultrasonic sensor and calculate the distance in percentage, but somehow the result is always 0. Do you know why this could happen or do you find any other mistakes? Please let me know.

Thank you

/***************************************************************************************************************************************************/

const byte cal_lowPin = 7, cal_highPin = 8;
const byte buzzPin = 6, trigPin = 9, ledPin = 13;
const byte echoPin = 10 , gasPin = A0;

const byte ButtonPin[] {cal_lowPin, cal_highPin};
const byte OutputPin[] {buzzPin, trigPin, ledPin};
const byte InputPin[] {echoPin, gasPin};

/***************************************************************************************************************************************************/

void setup() {
  Serial.begin(9600);
  for (byte pin : ButtonPin)
    pinMode(pin, INPUT_PULLUP);
  for (byte pin : OutputPin)
    pinMode(pin, OUTPUT);
  for (byte pin : InputPin)
    pinMode(pin, INPUT);
}

/***************************************************************************************************************************************************/

float calibrateSensor_low() {
  if (digitalRead(cal_lowPin) == true) {
    float calibrate_low = measureDistance();
    return calibrate_low;
  }
}

/***************************************************************************************************************************************************/

int calibrateSensor_high() {
  if (digitalRead(cal_highPin) == true) {
    int calibrate_high = calculateDistance();
    return calibrate_high;
  }
}

/***************************************************************************************************************************************************/

int measureDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  int distance = (duration * 0.034 / 2) ;
  return distance;
}

/***************************************************************************************************************************************************/

int calculateDistance() {
  int s = measureDistance() - calibrateSensor_low();
  int calDistance = t * (-1);
  return calDistance;
}

/***************************************************************************************************************************************************/

int mapDistance() {
  int  percentage = calculateDistance() / calibrateSensor_high() ;
  return percentage;
}

/***************************************************************************************************************************************************/

void loop() {
  Serial.println(mapDistance());
}

int calculateDistance() {
  int s = measureDistance() - calibrateSensor_low();
  int calDistance = t * (-1);
  return calDistance;
}

Does this actually compile without errors? What is "t"?

1 Like

Ah yes. I wanted to change it before posting this question because t is mostly used for time. I forgot to change in the code but before it worked.

You are doing integer division here. so if the numerator is less than the calibration value, you will always get 0. Maybe cast to a float? or calculate a number from 0-100 rather than 0.0-1.0

Hi,
Your function;

int mapDistance() {
  int  percentage = calculateDistance() / calibrateSensor_high() ;
  return percentage;
}

You declare "percentage" inside the function.
Then;

void loop() {
  Serial.println(mapDistance());
}

You try to print it outside the function.

It would be easier for you to declare ALL the return values from your functions as GLOBAL, don't worry about returning the values.
Then use those variables as the print variable.

You would at this stage be worth calling ALL your functions in the void loop(), and serial print their values, to check your functionality.

Tom... :smiley: :+1: :coffee: :australia:

/***************************************************************************************************************************************************/

const byte cal_lowPin = 7, cal_highPin = 8;
const byte buzzPin = 6, trigPin = 9, ledPin = 13;
const byte echoPin = 10 , gasPin = A0;

const byte ButtonPin[] {cal_lowPin, cal_highPin};
const byte OutputPin[] {buzzPin, trigPin, ledPin};
const byte InputPin[] {echoPin, gasPin};

unsigned Calibrate_high = 20;  // cm  Highest distance
unsigned Calibrate_low = 10; // cm  Lowest distance

/***************************************************************************************************************************************************/

void setup()
{
  Serial.begin(9600);

  for (byte pin : ButtonPin)
    pinMode(pin, INPUT_PULLUP);
  for (byte pin : OutputPin)
    pinMode(pin, OUTPUT);
  for (byte pin : InputPin)
    pinMode(pin, INPUT);
}

/**************************************************/
unsigned MeasureDistance()
{
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH, 30000ul);
  return duration * 0.034 / 2;
}

void loop()
{
  unsigned distance = MeasureDistance();

  if (distance != 0)  // Zero means 'no echo'
  {
    if (digitalRead(cal_highPin) == HIGH)
    {
      Calibrate_high = distance;
    }
    
    if (digitalRead(cal_lowPin) == HIGH)
    {
      Calibrate_low = distance;
    }

    unsigned calibratedRange = Calibrate_high - Calibrate_low;

    float percentage = (distance - Calibrate_low) / (float) calibratedRange;

    Serial.println(percentage * 100.0);
  }
}

That is not accurate. The println() function just prints the return value of mapDistance() which is perfectly fine. The variable percentage does go out of scope when the function exits, but its value is correctly used as the return value which then gets passed to println().

No problem here.

1 Like

Thank you for your help, but somehow I don´t get exact results. It´s the same as before, because I don´t receive values between 100 and 0.

These are the only values I receive:

23:10:50.032 -> 0.00
23:10:50.032 -> 0.00
23:10:50.032 -> 0.00
23:10:50.068 -> 0.00
23:10:50.068 -> 0.00
23:10:50.068 -> 0.00
23:10:50.068 -> 100.04
23:10:50.068 -> 100.04
23:10:50.068 -> 100.04
23:10:50.103 -> 100.04
23:10:50.103 -> 100.04
23:10:50.103 -> 100.04
23:10:50.103 -> 100.04

I think I should specify what my project is. I´m using the ultrasonic sensor in a trash can. There the bottom should be calibrated to 0 with this function:

float calibrateSensor_low() {
  if (digitalRead(cal_lowPin) == true) {
    float calibrate_low = measureDistance();
    return calibrate_low;
  }
}

And the maximum level which the trash is allowed to arrive is this function:

int calibrateSensor_high() {
  if (digitalRead(cal_highPin) == true) {
    int calibrate_high = calculateDistance();
    return calibrate_high;
  }
}

Between these two values I want to read out the trash level and serial print it in percentage where the bottom is 0 and the top is 100. Do you understand my idea?

Thank you very much for your kind help!

I suspect your 'calibrate' inputs are reading HIGH all of the time so min and max are getting reset to 'distance' each time. How do you have them wired? How do you use them to 'calibrate' the two distances?

This is the way I have connected them:


The way I use them is that I install the sensor and don´t move it anymore. Then I calibrate the way to the ground with "calibrateSensor_low()". After that I hold my hand two centimeters below the sensor and calibrate it with "calibrateSensor_high()". Is this enough information or do you need any other?

That's what I feared. Calibrate_low is the highest distance value and Calibrate_high is the lowest distance value. Let's try again, calling them Full and Empty instead of High and Low:

/***************************************************************************************************************************************************/

const byte buzzPin = 6;
const byte calEmptyPin = 7;
const byte calFullPin = 8;
const byte trigPin = 9;
const byte echoPin = 10;

unsigned CalibrateFull = 2;  // cm
unsigned CalibrateEmpty = 60; // cm

/***************************************************************************************************************************************************/

void setup()
{
  Serial.begin(9600);

  pinMode(buzzPin, OUTPUT);
  pinMode(calEmptyPin, INPUT);
  pinMode(calFullPin, INPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}


/**************************************************/
unsigned MeasureDistance()
{
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH, 30000ul);
  return duration * 0.034 / 2;
}

void loop()
{
  unsigned distance = MeasureDistance();

  if (distance != 0)  // Zero means 'no echo'
  {
    if (digitalRead(calFullPin) == HIGH)
    {
      CalibrateFull = distance;
      Serial.print("Calibrating FULL to: ");
      Serial.println(CalibrateFull);
    }

    if (digitalRead(calEmptyPin) == HIGH)
    {
      CalibrateEmpty = distance;
      Serial.print("Calibrating EMPTY to: ");
      Serial.println(CalibrateEmpty);
    }

    unsigned calibratedRange = CalibrateEmpty - CalibrateFull;

    float percentage = (distance - CalibrateFull) / (float) calibratedRange;

    Serial.println(percentage * 100.0);
  }
}

Wow! Thank you John for your help.
Now everything is working fine. But can you explain me why you gave "CalibrateFull" and "CalibrateEmpty" a value? Is it possible to declare it with zero?

unsigned CalibrateFull = 2;  // cm
unsigned CalibrateEmpty = 60; // cm

You can, but then the sketch won't work right on power-up until you go through both calibration steps. If you change the '2' and '60' to your calibration values then the sketch will work as soon as you turn on power.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.