6
\$\begingroup\$

I was not happy with original code for Ultrasonic sensor and decided to write my own implementation.

I managed to do this, but it still looks weird. Could you help me to improve it?

#include <wiringPi.h>
#include <stdio.h>
#include <sys/time.h>

#define Trig    0
#define Echo    1

double raw_ultrasonic_measure(int trig, int echo) {
  digitalWrite(Trig, LOW);
  delayMicroseconds(1);

  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);

  while(!(digitalRead(Echo) == 1));
  int time1 = micros();

  while(!(digitalRead(Echo) == 0));
  int time2 = micros();
  return (double)(time2 - time1) / 100;
}

double ultrasonic_measure(int trig, int echo) {
  double value1 = raw_ultrasonic_measure(trig, echo);
  delay(1);
  double value2 = raw_ultrasonic_measure(trig, echo);
  delay(1);
  double value3 = raw_ultrasonic_measure(trig, echo);
  delay(1);
  double value4 = raw_ultrasonic_measure(trig, echo);
  delay(1);
  double value5 = raw_ultrasonic_measure(trig, echo);
  return (value1 + value2 + value3 + value4 + value5) / 5;
} 

int main(void) {
  wiringPiSetup();
  pinMode(Echo, INPUT);
  pinMode(Trig, OUTPUT);

  while(1){
    double value = raw_ultrasonic_measure(Trig, Echo);
    printf("%0.1f cm\n", value);
    delay(1000);
  }

  return 0;
}
\$\endgroup\$
0

3 Answers 3

6
\$\begingroup\$

raw_ultrasonic_measure measures the duration of an echo staying high. It is not related to the distance in any way, it is just a duration of trig signal.

You need a time elapsed from the beginning of a signal to reception of echo - that is, a duration of echo being low.

In a quick and dirty way,

        signal_start = micros();
        digitalWrite(Trig, HIGH);

        while (digitalRead(Echo) == 0) {
            ;
        }

        echo_received = micros();
        digital_write(Trig, LOW);

        return (echo_received - signal_start) / (2 * speed_of_sound);

In a real world application you would want to debounce echo, provide for a timeout, etc.

You may also want to account for the time taken by a first call to digitalWrite, but I doubt it will make any perceptible difference.


ultrasonic_measure is in fact a loop:

        double value = 0.0;
        for (int i = 0; i < 5; i++) {
            value += raw_ultrasonic_measure(Trig, Echo);
        }
        return value / 5;

One benefit of such approach is an ability to pass a number of samples as a parameter.

\$\endgroup\$
1
  • \$\begingroup\$ I love your implementation of ultrasonic_measure and clarification of raw_ultrasonic_measure, thanks! \$\endgroup\$ Commented Nov 2, 2017 at 16:17
4
\$\begingroup\$

Oops...

#define Trig    0
//      ^                                             !!!
#define Echo    1

double raw_ultrasonic_measure(int trig, int echo) {
  //                              ^                   !!!
  digitalWrite(Trig, LOW);
  //           ^                                      !!!
  delayMicroseconds(1);
  // ...

Look at the capitalization. Your trig (and echo) function parameters are completely unused. That's why you #define constants to be ALL UPCASE normally.

Naming

Functions are usually named for what they do: "erase" something, "sort" some elements, "activate" some timer, ...

ultrasonic_measure (and it's raw variant) don't follow this style. They name what they return, not what they do in order to be able to return that value. How about measure_ultrasonic_distance? (measure used as a verb then.)

\$\endgroup\$
0
4
\$\begingroup\$

Take these comments together with the comments of others, not instead of them. They have already said much that needs saying.

double raw_ultrasonic_measure(int trig, int echo) {
  digitalWrite(Trig, LOW);
  delayMicroseconds(1);

  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);

The 5 lines above are basically a "ping" operation - you are generating a sonar ping and shaping it using the 1 and 10 constants. I'd suggest you write a parameterized ultrasonic_ping(duration) function.

  while(!(digitalRead(Echo) == 1));
  int time1 = micros();

  while(!(digitalRead(Echo) == 0));
  int time2 = micros();
  return (double)(time2 - time1) / 100;
}

I find your while loops difficult to read and comprehend. Please consider changing to something more left-to-right, and more explicit, like:

while (digitalRead(Echo) != 0) 
    EMPTY();

Finally, what does 1 mean? What does 0 mean when returned by digitalRead(Echo)? Could you use HIGH or LOW there? Or some other constant?

Why do you divide your time intervals by 100? Is that the speed of sound in microseconds per centimeter? A nice constant would help...

\$\endgroup\$
3
  • \$\begingroup\$ 100 is experimentally found value, probably I need better idea. \$\endgroup\$ Commented Nov 2, 2017 at 17:23
  • \$\begingroup\$ Your suggestion for the empty while loop makes things more unreadable, now somebody reading the code has to guess that EMPTY() does nothing, rather than seeing an empty loop body. \$\endgroup\$ Commented Nov 2, 2017 at 23:46
  • \$\begingroup\$ You could use /*EMPTY*/ instead. Or {}. Anything to make clear what's happening. \$\endgroup\$
    – aghast
    Commented Nov 3, 2017 at 4:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.