Ultrasonic sensor Do...While conditions

Hi there,
I would like some help with my programing of an arduino uno, I'm pretty new to this and this project has got me confused ahah.

I'd like the code to read an arcade button's state and check the distance of an ultrasonic sensor. Then If that sensor's distance is less than 100cm I would the arduino to run the motors forward, while checking the distance. Once the distance is greater than 100cm I would like the motors to stop running. If no button state has changed then nothing will happen and if the first distance check results in a reading greater than 100cm then the motors should do nothing.
Unfortunately instead of this the code runs through correctly, starting the motor but doesnt stop it when the distance is greater that 100cm. I'm trying to achieve this with a "do" "while" function shown below.

I'm using a L298n dual motor driver with two 12VDC motors and a Ultrasonic sensor. All components work when run separately I just cant get this code to work correctly :frowning:

Thank you all for your help and contributions

#include <L298N.h>

#define trigPin 5
#define echoPin 6
#define ButtonPin 7 //momentary switch

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

// motor one
const int enA = 11;
const int in1 = 13;
const int in2 = 12; 

//motor two
const int enB = 9;
const int in3 = 10;
const int in4 = 8; 
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration1, distance1, cm; // Duration used to calculate distance


void setup() {
  // put your setup code here, to run once:
      pinMode(trigPin, OUTPUT);
      pinMode(echoPin, INPUT);
      pinMode(ButtonPin,INPUT);
      pinMode(enA, OUTPUT);
      pinMode(in1, OUTPUT);
      pinMode(in2, OUTPUT);
      pinMode(enB, OUTPUT);
      pinMode(in3, OUTPUT);
      pinMode(in4, OUTPUT);
       Serial.begin (9600); 
}

void loop() {
  buttonState = digitalRead(ButtonPin); //read the state of the button
  if(digitalRead(ButtonPin) == HIGH) {
  if (buttonState != lastButtonState) {
     if (buttonState == HIGH) {

      buttonPushCounter++; 
  
  long duration1, distance1; 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);  
  digitalWrite(trigPin, LOW);  
          
  duration1 = pulseIn(echoPin, HIGH);
  distance1 = duration1 / 58; // distance in cm
  
  Serial.print(distance1);
  Serial.print("cm");
  Serial.println();
    
    if (distance1 < 100); {  
      do {
      
              digitalWrite(in1, HIGH);
               digitalWrite(in2, LOW);
              // set speed to 210 out of possible range 0~255
              analogWrite(enA, 200); 
             // turn on motor B
               digitalWrite(in3, HIGH);
               digitalWrite(in4, LOW);
               // set speed to 200 out of possible range 0~255
              analogWrite(enB, 200);

      delay(50);
  long duration1, distance1; 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);  
  digitalWrite(trigPin, LOW);  
          
  duration1 = pulseIn(echoPin, HIGH);
  distance1 = duration1 / 58; // distance in cm
  Serial.print(distance1);
  Serial.print("cm");
  Serial.println();
  }

  while (distance1 < 100);

  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW); 
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  
    }
    } else {
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW); 
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
    }

  }
   
  } 
 

   // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

}
  buttonState = digitalRead(ButtonPin); //read the state of the button
  if(digitalRead(ButtonPin) == HIGH) {
  if (buttonState != lastButtonState) {
     if (buttonState == HIGH) {

The idea behind the state change detection example is to test that two consecutive reads of the state result in different values. However, the expectation is that the switch will be read ONCE per iteration of loop().

Try again.

Put the code for reading the ultrasonic sensor in a function, so you don't need the code in loop(). You only call the function from loop(). Call the function twice. Don't write the code twice.

    if (distance1 < 100); {

If statements rarely have semicolons.

    }
    } else {

WTF? Use Tools + Auto Format before posting code, so it doesn't look like it was typed by a drunken monkey.

A do/while is almost certainly NOT appropriate. A while statement is. Learn the difference to understand why.

PaulS,

I only want the button to be read once... I dont want to have to push the button multiple times, I would like it to just run the code and end until the button it pushed again, I'm using this method because its a momentary button, not latching & this is a method that I understand to work when I use it with other sequences.

I didnt realise if statements couldn't have a semi colon, sorry it didnt seem to impact it.

And thank you for letting me know about auto format :cold_sweat: I didnt know that was a thing aha

Something like this maybe...

#include <L298N.h>

#define trigPin 5
#define echoPin 6
#define ButtonPin 7 //momentary switch

// motor one
const int enA = 11;
const int in1 = 13;
const int in2 = 12;

//motor two
const int enB = 9;
const int in3 = 10;
const int in4 = 8;
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration1, distance1, cm; // Duration used to calculate distance
bool isRunning = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ButtonPin, INPUT);
  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin (9600);
}

void loop() {
  if (digitalRead(ButtonPin) == HIGH)
  {
    isRunning = true;
  }

  checkDistance();
  if (distance1 < 100 && isRunning == true)
  {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    // set speed to 210 out of possible range 0~255
    analogWrite(enA, 200);
    // turn on motor B
    digitalWrite(in3, HIGH);
    digitalWrite(in4, LOW);
    // set speed to 200 out of possible range 0~255
    analogWrite(enB, 200);
    delay(50);
  }

  if (distance1 > 100)
  {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    isRunning = false;
  }
}
void checkDistance()
{
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration1 = pulseIn(echoPin, HIGH);
  distance1 = duration1 / 58; // distance in cm

  Serial.print(distance1);
  Serial.print("cm");
  Serial.println();
}

Gabriel types faster

same idea

#include <L298N.h>

#define trigPin 5
#define echoPin 6
#define ButtonPin 7 //momentary switch

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

// motor one
const int enA = 11;
const int in1 = 13;
const int in2 = 12;

//motor two
const int enB = 9;
const int in3 = 10;
const int in4 = 8;
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration1, distance1, cm; // Duration used to calculate distance


void setup() {
  // put your setup code here, to run once:
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ButtonPin, INPUT);
  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin (9600);
}

void loop() {

  buttonState = digitalRead(ButtonPin); //read the state of the button
  static byte forwardRequest;
  checkDistance();//update distance in global
  if (buttonState != lastButtonState) {//button changed state
    if (buttonState == HIGH) {//state is high
      forwardRequest = 1;// i want to move forwards
      buttonPushCounter++;
    }//add a else if you want motor to stop when button released
  }
  lastButtonState = buttonState;

  if (distance1 > 100 && forwardRequest == 1) {//i want to move forwards until distance is 100 or lower
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    // set speed to 210 out of possible range 0~255
    analogWrite(enA, 200);
    // turn on motor B
    digitalWrite(in3, HIGH);
    digitalWrite(in4, LOW);
    // set speed to 200 out of possible range 0~255
    analogWrite(enB, 200);
    delay(50);
  } else {//distance is smaller than 100 or im not told to move forwards
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    forwardRequest = 0;//cancels the call to move forwards when lower than 100
  }

  Serial.print(distance1);
  Serial.print("cm");
  Serial.println();
}//end loop

void checkDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration1 = pulseIn(echoPin, HIGH);
  distance1 = duration1 / 58; // distance in cm
}

Gabriel_swe,

I understand you're using a boolean as it hold two values, however I dont understand it's application? Are you using it for a further condition for when the motors must stop? Will the boolean value go back to false after all the code has been run, if I'm using the code shown below to make the momentary button a trigger? Do I have to set it back to false at the end of the code?

Gpop1,

You use a static byte forward request, I've tried to research the and haven't been able to find anything in relation to what we're working on :frowning: could you please describe it's use and/or why

void loop() {
  buttonState = digitalRead(ButtonPin); //read the state of the button
  if (digitalRead(ButtonPin) == HIGH) {
    if (buttonState != lastButtonState) {
      if (buttonState == HIGH) {

        buttonPushCounter++;

khoy91:
Gabriel_swe,

I understand you're using a boolean as it hold two values, however I dont understand it's application? Are you using it for a further condition for when the motors must stop? Will the boolean value go back to false after all the code has been run, if I'm using the code shown below to make the momentary button a trigger? Do I have to set it back to false at the end of the code?

Gpop1,

You use a static byte forward request, I've tried to research the and haven't been able to find anything in relation to what we're working on :frowning: could you please describe it's use and/or why

void loop() {

buttonState = digitalRead(ButtonPin); //read the state of the button
  if (digitalRead(ButtonPin) == HIGH) {
    if (buttonState != lastButtonState) {
      if (buttonState == HIGH) {

buttonPushCounter++;

its just a flag. I called it forwardRequest because that's kinda what its being used to do (name is not important call it fred if you like).

As for static that's telling the compiler that forwardRequest will be used in loop. Do not reassign it a new memory spot and don't forget whats in it. (bit like a global except only loop see's it).
Had I not added static the compiler would have deleted it at the end of loop and made a new one when it got to the line

byte forwardRequest;

that would have made forwardRequest =0 and that's not what we want to happen.

By setting a flag I can create a if that will run until I unset the flag. so push button sets it to 1 and less than 100mm unsets it back to 0.

Gabriel has done the same thing.

He called his flag

isRunning and he placed it in global

he sets the flag to true (compiler sees not 0 (1 for instance) and True as the same thing)

he then added

if (distance1 > 100){

//your code

isRunning = false;// unset the flag
}

False (compiler sees 0 and false as the same thing)

You just need to understand that a flag is used as you have the power to set and unset it when ever you like.

khoy91:
Gabriel_swe,

I understand you're using a boolean as it hold two values, however I dont understand it's application? Are you using it for a further condition for when the motors must stop? Will the boolean value go back to false after all the code has been run, if I'm using the code shown below to make the momentary button a trigger? Do I have to set it back to false at the end of the code?

Gpop1,

You use a static byte forward request, I've tried to research the and haven't been able to find anything in relation to what we're working on :frowning: could you please describe it's use and/or why

void loop() {

buttonState = digitalRead(ButtonPin); //read the state of the button
  if (digitalRead(ButtonPin) == HIGH) {
    if (buttonState != lastButtonState) {
      if (buttonState == HIGH) {

buttonPushCounter++;

gpop1 has already described it, so this is a repeat, but with my own words.

isRunning is a flag that says you have commanded your robot to run. I removed the state change and counter stuff as it doesn't add anything useful to the code as it is now. Only thing we need right now is to detect and remember that you have pushed the button. That is the purpose of isRunning.

For your robot to run, two statements must be valid.

  1. You have pushed the button. (isRunning == true)
  2. Distance measured is less than 100 cm (distance1 < 100)

For your robot to stop, only one statement must be true.

  1. Distance measured is more than 100 cm (distance1 > 100)

If distance is ok and you push the button, both those run conditions will be true until distance1>100. Then we have another if statement that stop the motors and set isRunning=false. Even if distance1 becomes <100 again, it will not run as isRunning was set to false when it stopped.
Once it has stopped, it will stay stopped until both those two run statements above is true again.

I could have used if..else instead as gpop1, but I think two separate if statements is slightly more easy to understand.

You need to make sure you don't have your button pin floating as it can give you a false reading and activate your robot. A 10k ohm pulldown resistor between pin7 and gnd will do. Or you can reverse the the logic and use builtin pull-up resistor instead. No need for external resistor.

  pinMode(ButtonPin, INPUT_PULLUP);//connect one side to ButtonPin and the other to gnd,
.
.
.
void loop() {
  if (digitalRead(ButtonPin) == LOW) //Button becomes active low when builtin pullup resistor is used.