Use HC-SR04 Ultrasonic Sensor to move a motor

Hello everyone :slight_smile:

I am currently in the process of a school project, and I need some help.

My basic components are; a stepper motor, an ultrasonic sensor, and a breadboard.

I am not completely new to using an Arduino board, but not exactly experienced either. My assignment basically boils down to making a motor move if the distance to an object changes. I have tried a lot of things now, but none of them seemed to work.

The current code I have worked out is this:

#define trigPin 4

#define echoPin 5

#include <Stepper.h>

const int stepsPerRevolution = 400; //number of steps per 
                                    //revolution for your motor
 
 // initialize the stepper library on the motor shield
 Stepper myStepper(stepsPerRevolution, 12,13);     
 
 // give the motor control pins names:
 const int pwmA = 3;
 const int pwmB = 11;
 const int brakeA = 9;
 const int brakeB = 8;
 const int dirA = 12;
 const int dirB = 13;
 const int STOP = 0;
 
 int x = 0;

void setup() {

pinMode(trigPin, OUTPUT);

pinMode(echoPin, INPUT);

pinMode(pwmA, OUTPUT);
 pinMode(pwmB, OUTPUT);
 pinMode(brakeA, OUTPUT);
 pinMode(brakeB, OUTPUT);
 digitalWrite(pwmA, HIGH);
 digitalWrite(pwmB, HIGH);
 digitalWrite(brakeA, LOW);
 digitalWrite(brakeB, LOW);
 
  // initialize the serial port:
 Serial.begin(9600);
 // set the motor speed (for multiple steps only):
 myStepper.setSpeed(75);

}

void loop() {

  dist(); 
//This function vill show the distance (ctrl + M).

  accel();
//This function was supposed to turen the only motor when the 
//distance changes


}

void dist(){
  
  long duration, distance;

digitalWrite(trigPin, LOW); 

delayMicroseconds(2);

digitalWrite(trigPin, HIGH);

delayMicroseconds(10); 

digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH);

distance = (duration/2) / 29.1;

if (distance >= 200 || distance <= 4){

Serial.println("STOP");

}

else {

Serial.print(distance);

Serial.println(" cm");

}
}

void accel(){
  
  long duration, distance, dist1, dist2;

digitalWrite(trigPin, LOW); 

delayMicroseconds(2);

digitalWrite(trigPin, HIGH);

delayMicroseconds(10); 

digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH);

dist1 = (duration/2) / 29.1;
dist2 = dist1 - ((pulseIn(echoPin, HIGH)/2) / 29.1);

if (dist1 < 20){
  if (dist2 < 0){
    myStepper.setSpeed(75);
    myStepper.step(-4);
  }
    
  else if (dist2 == 0){
    myStepper.setSpeed(STOP);
  }
  
  else {
    myStepper.setSpeed(75);
    myStepper.step(4);
  }
}

else {
  if (dist2 < 0){
    myStepper.setSpeed(75);
    myStepper.step(4);
    }
    
  else if (dist2 == 0){
    myStepper.setSpeed(STOP);
    }  
 
  else {
    myStepper.setSpeed(75);
    myStepper.step(-4); 
  }
}
}

Can anybody tell me what I am doing wrong?

Can anybody tell me what I am doing wrong?

You're assuming that the distance measured in "dist()" is the same as the one measured by duplicated code in "accel()".
You're not using auto-format on your code before posting it?

I give up, what are you doing wrong?

I give up, what are you doing wrong?

I did not mean can you tell I meant will you.

is the distance measured in "dist()" and "accel()" not the same? (I suppose not) How can I make sure they are the same?
Also, what do you mean auto-format?

is the distance measured in "dist()" and "accel()" not the same?

They won't be if the vehicle has moved between measurements.

How can I make sure they are the same?

By measuring it once in a single function, and passing the value to the other function

I did not mean can you tell I meant will you.

.
I know what you meant, but you haven't told us your plans and expectations, and how what you observe differs from this.

Sorry.

The stepper is just moving 4 steps according to the distance from the sensor. It was supposed to move if and only if there was a change in the distance.

I have tried this, but it still does not work:

#define trigPin 4

#define echoPin 5

#include <Stepper.h>

const int stepsPerRevolution = 400; //number of steps per 
                                    //revolution for your motor
 
 // initialize the stepper library on the motor shield
 Stepper myStepper(stepsPerRevolution, 12,13);     
 
 // give the motor control pins names:
 const int pwmA = 3;
 const int pwmB = 11;
 const int brakeA = 9;
 const int brakeB = 8;
 const int dirA = 12;
 const int dirB = 13;
 const int STOP = 0;
 
 int x = 0;

void setup() {

pinMode(trigPin, OUTPUT);

pinMode(echoPin, INPUT);

pinMode(pwmA, OUTPUT);
 pinMode(pwmB, OUTPUT);
 pinMode(brakeA, OUTPUT);
 pinMode(brakeB, OUTPUT);
 digitalWrite(pwmA, HIGH);
 digitalWrite(pwmB, HIGH);
 digitalWrite(brakeA, LOW);
 digitalWrite(brakeB, LOW);
 
  // initialize the serial port:
 Serial.begin(9600);
 // set the motor speed (for multiple steps only):
 myStepper.setSpeed(75);

}

void loop() {
  
  long duration, distance, dist2;

digitalWrite(trigPin, LOW); 

delayMicroseconds(2);

digitalWrite(trigPin, HIGH);

delayMicroseconds(10); 

digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH);

distance = (duration/2) / 29.1;

if (distance >= 200 || distance <= 4){

Serial.println("STOP");

}

else {

Serial.print(distance);

Serial.println(" cm");
}

dist2 = distance - ((pulseIn(echoPin, HIGH)/2) / 29.1);

if (distance < 20){
  if (dist2 < 0){
    myStepper.setSpeed(75);
    myStepper.step(-4);
  }
    
  else if (dist2 == 0){
    myStepper.setSpeed(STOP);
  }
  
  else {
    myStepper.setSpeed(75);
    myStepper.step(4);
  }
}

else {
  if (dist2 < 0){
    myStepper.setSpeed(75);
    myStepper.step(4);
    }
    
  else if (dist2 == 0){
    myStepper.setSpeed(STOP);
    }  
 
  else {
    myStepper.setSpeed(75);
    myStepper.step(-4); 
  }
}
}

I put it all in one function. Will that work?

dist2 = distance - ((pulseIn(echoPin, HIGH)/2) / 29.1);

I don't see where you triggered the sensor for this reading.

Do you mean I have to write:

digitalWrite(trigPin, LOW); 

delayMicroseconds(2);

digitalWrite(trigPin, HIGH);

delayMicroseconds(10); 

digitalWrite(trigPin, LOW);

Before the second reading as well? Or how do you do that?

Before the second reading as well?

Yes.

Or, you could easily convert "dist()" into a function returning a single range measurement.

unsigned long dist()
{
  digitalWrite(trigPin, LOW); 

  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH);

  delayMicroseconds(10); 

  digitalWrite(trigPin, LOW);

  return (pulseIn(echoPin, HIGH) / 2) / 29.1;
}

Neat :slight_smile:

Am how do I make a reference to it in the other function?

In the same way you reference other functions, like "pulseIn()".

You mean like this?

dist2 = (return (pulseIn(echoPin, HIGH) / 2) / 29.1)) - ((pulseIn(echoPin, HIGH)/2) / 29.1);

or how?

No, I wrote "like" not "exactly" as pulseIn.

"dist()" is a function, it returns a value, just like "pulseIn()", but instead of the duration of the echo pulse in microseconds, it returns the distance, in centimetres.

Sorry, but then I still do not get it.

I know that my function "dist()" returns a value in centimetres, and that much is working. The problem is getting the stepper to move accordingly.

Are you remembering that your two readings are very close together in time, and that your target is unlikely to have moved very far?

I am aware.

At the moment the target is a piece of paper I move myself. I do not want to mount it to anything until it works.

I'm puzzled by the lack of debug prints in your code.
Why not add some, and use the output to tell you what is going on - debugging with stepper motors isn't easy.

I am starting to feel like such a noob, but how do you add debug prints?

In your first post on this thread, you had some Serial.print in your function "dist()".
If you know the values "dist" is returning, you can have a better idea how your sketch is performing.

Yes, but is it not just the values I get when I press ctrl + shift + m?

Yes, but you've not shown that you're doing that.