Trouble with obstacle avoiding robot

I’m using an Arduino Uno, an HC-SR04 ultrasonic sensor mounted on a servo, and an L298n dual h-bridge motor controller. The L298n is powered with a 7.2v battery pack and the Uno with a 9V (or usb for testing).

The goal is like most other obstacle avoiding robots. It should check the distance in front and move forward as long as the measured distance is greater than the distanceLimit. If the distance is less than distanceLimit, the robot should stop, then take a measurement to the left and right, then compare. To keep it simple, if one side measures higher than the other then the robot turns that direction and starts the loop over again.

Unfortunately, the results are so varied that I can’t pin down what the issues are. Most times the bot will run right into an object or wall, sometimes stopping other times not. Other times the robot won’t even start moving despite receiving values greater than the distanceLimit (as confirmed by serial monitor). There are also times where it will seem to get stuck in a “look around” mode and/or keep turning, stopping, looking, then turning again. This is especially interesting in a hallway where it seems unable to just move down a hallway. The other concern is that despite which of my sensors I’m using I still get quite a few 0’s.

So my first question is whether or not I’ve missed a condition in my loop that causes it to get stuck in the “look around” and/or turn mode instead of moving forward when it should be clear.

#include <NewPing.h>
#include <Servo.h>

#define TRIGGER_PIN 12
#define ECHO_PIN 13
#define MAX_DISTANCE 50
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);  // distance sensor

int enableA = 11; // H bridge pins
int pinIN1 = 6;
int pinIN2 = 5;
int enableB = 10;
int pinIN3 = 4;
int pinIN4 = 3;

Servo head;  // servo naming

const int distanceLimit = 20; // collision distance limit

unsigned int frontcm; // distance measurements
unsigned int leftcm;
unsigned int rightcm;

void setup() {
  Serial.begin(9600);
  head.attach(2);
  head.write(90);
  pinMode(enableA, OUTPUT);
  pinMode(pinIN1, OUTPUT);
  pinMode(pinIN2, OUTPUT);
  pinMode(enableB, OUTPUT);
  pinMode(pinIN3, OUTPUT);
  pinMode(pinIN4, OUTPUT);
  enableMotors();
}

void loop() {
	delay(50); // this delay is supposedly for pings?
	frontcm = sonar.ping_cm(); // take a front measurement
	if (frontcm > distanceLimit || frontcm == 0) {
		forward;
	}
	else {
		stopMove();
		checkPath();
		turnDirection();
	}
}
	
void checkPath() {
	head.write(170);  // look left
	delay(300); // wait for servo to turn
	leftcm = sonar.ping_cm(); // take left measurement
	head.write(10); // now turn right
	delay(300);
	rightcm = sonar.ping_cm();
	head.write(90); //return to front
	delay(200);
}
	
void turnDirection() {
	if (leftcm > rightcm || leftcm == 0) {
		turnLeft();
		delay(200);
	}
	else if (rightcm > leftcm || rightcm == 0) {
		turnRight();
		delay(200);
	}
	else if (leftcm < distanceLimit && rightcm < distanceLimit) {
		reverse();
		delay(400);
	}
}

// high level motor functions
void enableMotors() {
  motorAon();
  motorBon();
}

void forward() {
  motorAforward();
  motorBforward();
}

void reverse() {
  motorAreverse();
  motorBreverse();
}

void turnLeft() {
  motorAreverse();
  motorBforward();
}

void turnRight() {
  motorAforward();
  motorBreverse();
}

void stopMove() {
  motorAstop();
  motorBstop();
}

// low level motor functions
void motorAon() {
  digitalWrite(enableA, HIGH);
}

void motorBon() {
  digitalWrite(enableB, HIGH);
}

void motorAforward() {
  digitalWrite(pinIN1, HIGH);
  digitalWrite(pinIN2, LOW);
}

void motorBforward() {
  digitalWrite(pinIN3, HIGH);
  digitalWrite(pinIN4, LOW);
}

void motorAreverse() {
  digitalWrite(pinIN1, LOW);
  digitalWrite(pinIN2, HIGH);
}

void motorBreverse() {
  digitalWrite(pinIN3, LOW);
  digitalWrite(pinIN4, HIGH);
}

void motorAstop() {
  digitalWrite(pinIN1, HIGH);
  digitalWrite(pinIN2, HIGH);
}

void motorBstop() {
  digitalWrite(pinIN3, HIGH);
  digitalWrite(pinIN4, HIGH);
}
if (frontcm > distanceLimit || frontcm == 0) {
		forward;
	}

"forward;" ?

AWOL:

if (frontcm > distanceLimit || frontcm == 0) {
	forward;
}


"forward;" ?

That should just be a mistype though would likely explain the wackiness of the last iteration I tried before giving up yesterday. Looking at my previous versions I at least had it entered correctly as "forward();"

Hi,
Why use Ping.h? can't understand it, the basic code is so simple and for me works everytime.

Here's some code cut from one of my programs:

ong scanner(long cm)
{
	const int pingPin=7, EchoPin=8;
	long duration;

	// The SRF005/HC-SR04 is triggered by a HIGH pulse of 2 or more microseconds.
	// Give a short LOW pulse before to ensure a clean HIGH pulse:
	pinMode(pingPin, OUTPUT);
	pinMode(EchoPin, INPUT);  

	digitalWrite(pingPin, LOW);
	delayMicroseconds(2);
	digitalWrite(pingPin, HIGH);
	delayMicroseconds(2);
	digitalWrite(pingPin, LOW); 
	duration = pulseIn(EchoPin, HIGH);
	delay(100);

	// convert the time into a distance
	// inches = microsecondsToInches(duration);
	cm = microsecondsToCentimeters(duration);
	return (cm);
}
//------------------------------------------------------------------
long microsecondsToCentimeters(long microseconds)
{
	// The speed of sound is 340 m/s or 29 microseconds per centimeter.
	// The ping travels out and back, so to find the distance of the
	// object we take half of the distance travelled.
	return microseconds / 29 / 2;
}

void Radar()
{
	Halt();
	BackOff();
	Lturn();
	sound(2200,20);
	Halt();
	A=scanner(cm);
	delay(100);
	Rturn();
	Rturn(); 
	sound(2200,20);
	Halt();
	B=scanner(cm);
	delay(100);
	Lturn();
	delay(50);

	if (A>B) 
	{
		Lturn();  //Then turn left
		A=0; 
	}
	else  
	{
		Rturn();  //Then turn right
		B = 0;
	}
}

By the way the L329/L398 are poor drivers as you lose power (2v+) on the output transistors use something with FET outputs, more power... You have called the motors A & B that's fine so why not call the pins MA- MA+ makes sense!

Hope it helps, regards. (see www.melsaunders.co.uk for my bots)

Mel.

Unfortunately, the results are so varied that I can't pin down what the issues are.

What do your Serial.print()s tell you?

Why not?

Cactusface:
Hi,
Why use Ping.h? can't understand it, the basic code is so simple and for me works everytime.

Here's some code cut from one of my programs:

ong scanner(long cm)

{
const int pingPin=7, EchoPin=8;
long duration;

// The SRF005/HC-SR04 is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse before to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
pinMode(EchoPin, INPUT);  

digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(2);
digitalWrite(pingPin, LOW); 
duration = pulseIn(EchoPin, HIGH);
delay(100);

// convert the time into a distance
// inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
return (cm);

}
//------------------------------------------------------------------
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}

void Radar()
{
Halt();
BackOff();
Lturn();
sound(2200,20);
Halt();
A=scanner(cm);
delay(100);
Rturn();
Rturn();
sound(2200,20);
Halt();
B=scanner(cm);
delay(100);
Lturn();
delay(50);

if (A>B) 
{
	Lturn();  //Then turn left
	A=0; 
}
else  
{
	Rturn();  //Then turn right
	B = 0;
}

}




By the way the L329/L398 are poor drivers as you lose power (2v+) on the output transistors use something with FET outputs, more power... You have called the motors A & B that's fine so why not call the pins MA- MA+ makes sense!

Hope it helps, regards. (see www.melsaunders.co.uk for my bots)

Mel.

Thanks for the response. I used NewPing because it looked simple enough, was recommended on Arduino's page for ultrasonic sensors, and this is really only my second arduino project. I actually had your page open from another related post on these forums so I'll take a look around. I'll also take a look at the regular ping library. Perhaps there's an issue with NewPing that is returning some of the strange readings.

Here's a snippet from the terminal after fixing the forward(); and adding some serial.print to give me an indication of what it's doing:

front 0
front 0
front 0
front 0
front 0
front 0
front 0
front 11
left ping 7
right ping 6
turning left
front 9
left ping 0
right ping 0
turning left
front 0
front 0
front 0

an indication of what it's doing:

Do those values (and actions) seem reasonable? We can't see your robot, or what you are placing in front of it.

The zero's worry me, supposedly they happen when the ping return times out. The first time I simply placed my hands in a u-shape so that it would detect something on all three sides. The second time, without changing the position of the robot, I simply placed my hand in front to trigger the "checkPath" and "turnDirection" parts. During my lunch I may hookup the motors and run the bot to see if it does anything differently.

Hi,
Make sure your hands are not too close as I think that may return a zero too! In my code I just get the distance returned in CM's in the Radar fuction, which then makes the correct turn, after comparing LEFT and RIGHT distances..

Regards

Mel.

Okay, so far the best code I have is the following (cutting out the motor functions for length). There’s still the occasion where I get a zero for both left and right so it will just turn left. Until I know what situations cause that, I can’t modify or add an argument for it. Thanks for the input so far folks, sometimes I just need to work it out with someone to help me understand what I’m trying to do.

#include <NewPing.h>
#include <Servo.h>

#define TRIGGER_PIN 12
#define ECHO_PIN 13
#define MAX_DISTANCE 50
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);  // distance sensor

int enableA = 11; // H bridge pins
int pinIN1 = 6;
int pinIN2 = 5;
int enableB = 10;
int pinIN3 = 4;
int pinIN4 = 3;

Servo head;  // servo naming

const int distanceLimit = 20; // collision distance limit

unsigned int frontcm; // distance measurements
unsigned int leftcm;
unsigned int rightcm;

void setup() {
  Serial.begin(9600);
  head.attach(2);
  head.write(90);
  pinMode(enableA, OUTPUT);
  pinMode(pinIN1, OUTPUT);
  pinMode(pinIN2, OUTPUT);
  pinMode(enableB, OUTPUT);
  pinMode(pinIN3, OUTPUT);
  pinMode(pinIN4, OUTPUT);
  enableMotors();
}

void loop() {
	delay(50); // this delay is supposedly for pings?
	frontcm = sonar.ping_cm(); // take a front measurement
        Serial.print("front ");
        Serial.println(frontcm);
	if (frontcm > distanceLimit || frontcm == 0) {
		forward();
	}
	else {
                Serial.print("stopping distance");
                Serial.println(frontcm);
		stopMove();
		checkPath();
		turnDirection();
	}
}
	
void checkPath() {
	head.write(170);  // look left
	delay(300); // wait for servo to turn
	leftcm = sonar.ping_cm(); // take left measurement
        Serial.print("left ping ");
        Serial.println(leftcm);
	head.write(10); // now turn right
	delay(300);
	rightcm = sonar.ping_cm();
        Serial.print("right ping ");
        Serial.println(rightcm);
	head.write(90); //return to front
	delay(200);
}
	
void turnDirection() {
        if (leftcm < distanceLimit && leftcm > 0 && rightcm < distanceLimit && rightcm > 0) {
		reverse();
                Serial.println("going reverse");
		delay(400);
        }
	else if (leftcm > rightcm || leftcm == 0) {
                Serial.println("turning left");
		turnLeft();
		delay(300);
	}
	else if (rightcm > leftcm || rightcm == 0) {
                Serial.println("turning right");
		turnRight();
		delay(300);
	}
}

Have you tried to test the sensor out just by itself? To possibly see if it is something with the sensor, or with your code?

Hope it helps :slight_smile: