Comparing distances from HC-SR04 with if statements

Hello all,

I'm looking to control the speed of two linear actuators that I'm going to be using to raise and lower my desk. These actuators need to be travelling close to the same speed as they're going up and down so my desk does not tilt. To keep them in sync, I'm going to put an HC-SR04 sensor on each side of my desk. They're going to measure the distance from the top of the desk where they'll be mounted, to the ground.

I'm looking for a better way to compare the two values I get from these sensors. I want to keep the recorded distance from the sensors within an inch of each other (more than doable because the resolution of the sensors is 1cm). I want to be able to check to see if distance1 is greater than distance2 by >1 inch, and vice versa. Should I just create a separate variable that, for example, would be 'int x = distance2+1' then check that variable against the distance1 variable? Or is there a simpler way to get my desired result?

Thanks!

TehPl0x:
Should I just create a separate variable that, for example, would be ‘int x = distance2+1’ then check that variable against the distance1 variable?

First: are you sure you want to use “int”? for this?

Second: you can use results from arithmetic in comparisons.

if (distance1 > (distance2 + 1)) {
  // do something
}
else if (distance1 < (distance2 - 1)) {
  // do something different
}

with if loops

No such thing. Not every statement is a loop.

odometer:
First: are you sure you want to use “int”? for this?

I’m pretty new to programming, so I’m not sure which way I’d like to create the variable. I was under the impression that if the variable is going to be changing, “int” isn’t a bad way to go, but if the variable is going to be constant, use “define”. I’m more than open to suggestions though as I’m quite new.

odometer:
Second: you can use results from arithmetic in comparisons.

if (distance1 > (distance2 + 1)) {

// do something
}
else if (distance1 < (distance2 - 1)) {
 // do something different
}

That’s perfect! I should’ve known you can do something like that. Much easier than creating separate variables. Thanks!

PaulS:
No such thing. Not every statement is a loop.

So did I mean to say “if statement” instead?

So did I mean to say “if statement” instead?

Yes.

Is it possible to use arithmetic within the map function? I want to vary the speed of the actuators proportional to how far apart the sensors are reading the heights. I figured I could just use the map function to get a PWM frequency that’s proportionate to the difference between the actuators… So maybe something like this.

if (distance1 > (distance2+1)){
    if ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==LOW) &&   (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==LOW)){
      digitalWrite(MOTOR1, LOW);    //disable motor 1 if it was previously running
      digitalWrite(MOTOR2, LOW);    //disable motor 2 if it was previously running
      delay(300);    //let motors slow down
      while ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==LOW) && (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==LOW)){
        digitalWrite(DIR1, LOW);    //revert direction back to normal for motor 1 if it was previously switched
        digitalWrite(DIR2, LOW);    //revert direction back to normal for motor 2 if it was previously switched
        delay(200);  
        map(motor1speed, (distance1-(distance2+1)), 1, 0, 255)
        analogWrite(MOTOR1, motor1speed);  
        analogWrite(MOTOR2, 255);
        Serial.println("ON-FORWARD");
      }
    }

I apologize for the ugly looking code in advance. Lol

Is it possible to use arithmetic within the map function?

It is, but map() is overkill for what you are trying to do. Besides, the speed of one motor is not solely related to the difference in positions. The speed of one motor needs to be relative to the speed of the other motor.

You should be running the motors, and checking relative speed (based on relative distances) as often as possible. Those stupid delay() mean that you are blind for the period of time they are idling. You do not want to be blind at all.

PaulS: It is, but map() is overkill for what you are trying to do. Besides, the speed of one motor is not solely related to the difference in positions. The speed of one motor needs to be relative to the speed of the other motor.

By measuring the difference between the sensor readings, I am essentially measuring the speed of the actuators. If the left side of my desk is higher, that means the left actuator is moving faster, and my code will see that once the left side exceeds an inch above the right side. Then, with the map function, I want to measure that difference, and then based upon the magnitude, I want to slow down the left side while having the right side remain running at full speed. The map function is the only way I know to do this. I'm more than open to any suggestions, however!

PaulS: You should be running the motors, and checking relative speed (based on relative distances) as often as possible. Those stupid delay() mean that you are blind for the period of time they are idling. You do not want to be blind at all.

These actuators run at .98in/sec, so I didn't think that half a second delay would be bad, but you're correct. I just didn't want to have quick switching.. didn't know if that would be bad for the motors over time. I'll make those delays conditions. Thanks!

By measuring the difference between the sensor readings, I am essentially measuring the speed of the actuators.

No. You are measuring the relative speed. You know nothing about the actual speed.

that means the left actuator is moving faster

See? Faster is a relative term.

Then, with the map function, I want to measure that difference, and then based upon the magnitude, I want to slow down the left side while having the right side remain running at full speed.

What if the left side is the lower side? Then, you'd need to make it run faster than the right side.

PaulS: No. You are measuring the relative speed. You know nothing about the actual speed. See? Faster is a relative term.

Lol, relative speed is all that I need to know. Why would I need to know the actual speed? As long as I know that one side is moving faster or slower than the other, I know that I need to either speed up or slow down one of them.

PaulS: What if the left side is the lower side? Then, you'd need to make it run faster than the right side.

I've already accounted for that. Here's the entire bit of code I've written so far.

#define DIR1 4    //direction control for motor 1
#define MOTOR1     //motor 1 pin (must be PWM)
#define DIR2 12    //direction control for motor 2
#define MOTOR2     //motor 2 pin (must be PWM)
#define pos1      //predetermined position 1
#define pos2      //predetermined position 2
#define trigpin1 13    //trigger pin of sensor #1
#define echopin1 12    //receiver pin of sensor #1
#define trigpin2 11    //trigger pin of sensor #2
#define echopin2 10    //receiver pin of sensor #2
int onoffswitch1 = 7;    //switch that controls on/off of motor 1
int dirswitch1 = 8;    //switch that controls the direction of motor 1
int onoffswitch2 = 5;    //switch that controls on/off of motor 2
int dirswitch2 = 3;    //switch that controls the direction of motor 2

long duration1, distance1;
long duration2, distance2;

void setup() {
  pinMode(DIR1, OUTPUT);
  pinMode(MOTOR1, OUTPUT);
  pinMode(DIR2, OUTPUT);
  pinMode(MOTOR2, OUTPUT);
  pinMode(onoffswitch1, INPUT);
  pinMode(dirswitch1, INPUT);
  pinMode(onoffswitch2, INPUT);
  pinMode(dirswitch2, INPUT);
  pinMode(trigpin1, OUTPUT);
  pinMode(echopin1, INPUT);
  pinMode(trigpin2, OUTPUT);
  pinMode(echopin2, INPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(trigpin1, LOW);
  digitalWrite(trigpin2, LOW);
  delayMicroseconds(2);
  digitalWrite(trigpin1, HIGH);
  digitalWrite(trigpin2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin2, LOW);
  digitalWrite(trigpin2, LOW);
  duration1 = pulseIn(echopin1, HIGH);
  distance1 = duration1 / 58;
  duration2 = pulseIn(echopin2, HIGH);
  distance1 = duration2 / 58;
  if ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==LOW) && (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==LOW)){
    digitalWrite(MOTOR1, LOW);    //disable motor 1 if it was previously running
    digitalWrite(MOTOR2, LOW);    //disable motor 2 if it was previously running
    delay(300);    //let motors slow down
    while ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==LOW) && (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==LOW)){
      digitalWrite(DIR1, LOW);    //revert direction back to normal for motor 1 if it was previously switched
      digitalWrite(DIR2, LOW);    //revert direction back to normal for motor 2 if it was previously switched
      delay(200);  
      analogWrite(MOTOR1, 255);  
      analogWrite(MOTOR2, 255);
      if (distance1 > (distance2+1)){    //enter the statement if the left side of the desk is higher than 1in above the right side
        while (distance1 > (distance2+1)){    //do commands while this is true
          map(motor1speed, (distance1-(distance2+1)), 1, 0, 255);    //calculate the difference between height of left sensor and 1in above right sensor, then map to analog output
          analogWrite(MOTOR1, motor1speed);    //reduce speed based upon the magnitude of the difference between the sensors
          analogWrite(MOTOR2, 255);    //keep motor2 running full speed
        }
      }
      if (distance2 > (distance1+1)){
        while (distance2 > (distance1+1)){
          map(motor2speed, (distance2-(distance1+1)), 1, 0, 255);
          analogWrite(MOTOR1, 255);
          analogWrite(MOTOR2, motor2speed);
        }
      }
      Serial.println("ON-UP");
    }
  }
  else if ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==HIGH) && (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==HIGH)){
    digitalWrite(MOTOR1, LOW);
    digitalWrite(MOTOR2, LOW);
    delay(300);
    while ((digitalRead(onoffswitch1)==HIGH) && (digitalRead(dirswitch1)==HIGH) && (digitalRead(onoffswitch2)==HIGH) && (digitalRead(dirswitch2)==HIGH)){
      digitalWrite(DIR1, HIGH);
      digitalWrite(DIR2, HIGH);
      delay(200);
      analogWrite(MOTOR1, 255);
      analogWrite(MOTOR2, motor2speed);
      if (distance1 > (distance2+1)){
        while (distance1 > (distance2+1)){
          map(motor2speed, (distance1-(distance2+1)), 1, 0, 255)
          analogWrite(MOTOR1, 255);
          analogWrite(MOTOR2, motor2speed);
        }
      }
      if (distance2 > (distance1+1)){
        while (distance2 > (distance1+1)){
          map(motor1speed, (distance2-(distance1+1)), 1, 0, 255);
          analogWrite(MOTOR1, motor1speed);
          analogWrite(MOTOR2, 255);
        }
      }
      Serial.println("ON-DOWN");
    }
  }
}
  else if ((digitalRead(onoffswitch1)==LOW) && (digitalRead(dirswitch1)==LOW) && (digitalRead(onoffswitch2)==LOW) && (digitalRead(dirswitch2)==LOW)){
    while ((digitalRead(onoffswitch1)==LOW) && (digitalRead(dirswitch1)==LOW) && (digitalRead(onoffswitch2)==LOW) && (digitalRead(dirswitch2)==LOW)){
      digitalWrite(MOTOR1, 0);
      digitalWrite(MOTOR2, 0);
      digitalWrite(DIR1, LOW);
      digitalWrite(DIR2, LOW);
      Serial.println("OFF");
    }
  }
  if (digitalRead(pos1)==HIGH){
    while (distance1 != 50 && distance2 != 50){
      digitalWrite(DIR1, LOW);
      digitalWrite(DIR2, LOW);
      delay(30);
      analogWrite(MOTOR1, 255);
      analogWrite(MOTOR2, 255); 
    }
    if (distance1 = 50 && distance2 = 50){
      analogWrite(MOTOR1, 0);
      analogWrite(MOTOR2, 0); 
    }
    if (distance1 != 50 && distance2 = 50){
      while (distance1 != 50){
        analogWrite(MOTOR1, 155);
      }
    }
    if (distance1 = 50 && distance2 !=50){
      while (distance2 != 50){
        analogWrite(MOTOR2, 155);
      }
    }
  if (digitalRead(pos2)==HIGH){
    while (distance1 != 32 && distance2 != 32){
      digitalWrite(DIR1, HIGH);
      digitalWrite(DIR2, HIGH);
      delay(30);
      analogWrite(MOTOR1, 255);
      analogWrite(MOTOR2, 255);
    }
    if (distance1 = 32 && distance2 = 32){
      delay(50);
      digitalWrite(DIR1, LOW);
      digitalWrite(DIR2, LOW);
      analogWrite(MOTOR1, 0);
      analogWrite(MOTOR2, 0);
    }
    if (distance1 != 32 && distance2 = 32){
      while (distance1 != 32){
        digitalWrite(DIR1, HIGH);
        analogWrite(MOTOR1, 155);
      }
    }
    if (distance1 = 32 && distance2 != 32){
      while (distance2 != 32){
        digitalWrite(DIR2, HIGH);
        analogWrite(MOTOR2, 155);
      }
    }    
  }    
}

I know that some of the variables don't have a pin designated to them. My UNO was running out of pins slots, so I ordered a MEGA2560. I just received it this morning.

  digitalWrite(trigpin1, LOW);
  digitalWrite(trigpin2, LOW);
  delayMicroseconds(2);
  digitalWrite(trigpin1, HIGH);
  digitalWrite(trigpin2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin2, LOW);
  digitalWrite(trigpin2, LOW);
  duration1 = pulseIn(echopin1, HIGH);
  distance1 = duration1 / 58;
  duration2 = pulseIn(echopin2, HIGH);
  distance1 = duration2 / 58;

Unless you have some very reliable way of keeping a pulse from one sensor being received by the other, this is NOT going to work.

(You certainly don't want to trash distance1 that way.)

delay(300); //let motors slow down

For 3/10ths of a second?

      if (distance1 > (distance2+1)){    //enter the statement if the left side of the desk is higher than 1in above the right side
        while (distance1 > (distance2+1)){    //do commands while this is true
          map(motor1speed, (distance1-(distance2+1)), 1, 0, 255);    //calculate the difference between height of left sensor and 1in above right sensor, then map to analog output
          analogWrite(MOTOR1, motor1speed);    //reduce speed based upon the magnitude of the difference between the sensors
          analogWrite(MOTOR2, 255);    //keep motor2 running full speed
        }
      }

If the two distance vary more than 1", the while loop will never end. Re-reading the sensor now and then is probably a good idea. Nothing that is being done in that while loop needs to be in the body of the while statement, unless you actually read the sensor data again.

    if (distance1 = 50 && distance2 = 50){

The = operator and the == operator do very different things. You probably want the == operator.

PaulS:  digitalWrite(trigpin1, LOW);  digitalWrite(trigpin2, LOW);  delayMicroseconds(2);  digitalWrite(trigpin1, HIGH);  digitalWrite(trigpin2, HIGH);  delayMicroseconds(10);  digitalWrite(trigpin2, LOW);  digitalWrite(trigpin2, LOW);  duration1 = pulseIn(echopin1, HIGH);  distance1 = duration1 / 58;  duration2 = pulseIn(echopin2, HIGH);  distance1 = duration2 / 58;

Unless you have some very reliable way of keeping a pulse from one sensor being received by the other, this is NOT going to work.

(You certainly don't want to trash distance1 that way.)

I'm glad you said something about that. I probably wouldn't have thought to do anything about that!

PaulS: For 3/10ths of a second?

That's not very long. Maybe I should change that..

PaulS:      if (distance1 > (distance2+1)){    //enter the statement if the left side of the desk is higher than 1in above the right side        while (distance1 > (distance2+1)){    //do commands while this is true          map(motor1speed, (distance1-(distance2+1)), 1, 0, 255);    //calculate the difference between height of left sensor and 1in above right sensor, then map to analog output          analogWrite(MOTOR1, motor1speed);    //reduce speed based upon the magnitude of the difference between the sensors          analogWrite(MOTOR2, 255);    //keep motor2 running full speed        }      }

If the two distance vary more than 1", the while loop will never end. Re-reading the sensor now and then is probably a good idea. Nothing that is being done in that while loop needs to be in the body of the while statement, unless you actually read the sensor data again.

I was under the impression that distance1 and distance2 would continue updating. Hmm.. How would you recommend re-reading the sensor's data?

PaulS:    if (distance1 = 50 && distance2 = 50){

The = operator and the == operator do very different things. You probably want the == operator.

I could probably do it either way if I adjusted my code.. but your way seems to make more sense with what I have.

I really appreciate all of these suggestions and comments. Some of the stuff you're saying would've taken me forever to think of, I'm sure. Thank you.

How would you recommend re-reading the sensor's data?

Put the code that is at the start of loop() in a separate function (or, even better, two), and call it/them in the while loop.

PaulS: Put the code that is at the start of loop() in a separate function (or, even better, two), and call it/them in the while loop.

Will do.

Trying to look at the previous switch states to get rid of the delays is starting to make this a little complicated for me. I'm not a very organized programmer. :sweat_smile:

Again, thanks for your help.

I don't think that using while loops to vary the speed is appropriate. In those while loops, you don't check that the desk as reached its upper or lower limit. The loop() function is called over and over. As long as you adjust the speed of the faster motor on each pass through loop(), it should not be necessary to have the while loops.

A couple thoughts:

The HC-SR04 can give lots of false readings, so try to filter/average them before you calculate the next move for the desk.

Can your motors run from a PWM signal?

That seems like a certainty, since that is how OP is driving them now.

PaulS: That seems like a certainty, since that is how OP is driving them now.

...... I'm actually just testing with a small 9V dc motor right now.... Is there any reason why the dc motor within the actuator wouldn't allow for PWM? I just contacted Progressive Automations (the source of my actuators) to see if they're compatible with PWM. It's gonna suck when they turn out to not be compatible.. Lol :roll_eyes:

Edit:

The PA representative got back to me.. these actuators are PWM compatible. PHEW!

PaulS: I don't think that using while loops to vary the speed is appropriate. In those while loops, you don't check that the desk as reached its upper or lower limit. The loop() function is called over and over. As long as you adjust the speed of the faster motor on each pass through loop(), it should not be necessary to have the while loops.

These actuators have limit switches pre-installed. I guess I don't understand what your concern is here.

Edit:

[quote author=jack wp link=msg=2326120 date=1437591868] The HC-SR04 can give lots of false readings, so try to filter/average them before you calculate the next move for the desk. [/quote]

I will definitely be sure to do that. I noticed the variance when I tested the sensors to make sure they weren't DOA. Thanks!

I guess I don't understand what your concern is here.

Well, without looking real closely at the code again, there certainly seemed like a lot of switch reading going on. Reading the "Go UP" switch doesn't require that much code. Reading the "Go DOWN" switch doesn't involve that much code. I don't recall that you used names like that, or used the state change detection example to determine when the state changed, or that you used a state machine to move up, move down, or do nothing, as appropriate.

So, I assumed that the rest of the switch stuff dealt with reading limit switches. I guess not, so don't worry about it.