Obstacle Avoidance robot using L293D motor driver

Creating a self-driving obstacle avoidance robot is an exciting venture, and with this obstacle-avoidance robot, you’ll learn how to navigate an Arduino-based project to avoid obstacles autonomously. Using sensors, motors, and some clever programming, this robot will detect obstacles and adjust its path accordingly—essentially a self-driving car!

Hardware Components Used in This Project

Here are the main components used to build the obstacle avoidance robot:

S/NOComponentsSpecificationQTY
1Arduino uno1
2Ultrasonic sensorHC-SR041
3Servo MotorSG901
4DC Motor2-4
5Motor DriverL293D1
6Wheels and Chassis1
7Batteries3.7v lithium3
8Push buttons2
9Breadboard1
10NPN TransistorBC5471
11Timer IC
NE555
1
12Resistors1KΩ and 10KΩ
13Jumper WiresAs needed
table 1: Components

Circuit diagram for the Autonomous Obstacle Avoidance Robot

obstacle avoidance robot

Code for Obstacle Avoidance Robot

#include "AFMotor.h"
#include <Servo.h>

#define echopin A4 // Echo pin
#define trigpin A5 // Trigger pin

Servo myservo;

const int MOTOR_1 = 1; 
const int MOTOR_2 = 2; 
const int MOTOR_3 = 3; 
const int MOTOR_4 = 4; 

AF_DCMotor motor1(MOTOR_1, MOTOR12_64KHZ); // create motor object, 64KHz pwm
AF_DCMotor motor2(MOTOR_2, MOTOR12_64KHZ); // create motor object, 64KHz pwm
AF_DCMotor motor3(MOTOR_3, MOTOR12_64KHZ); // create motor object, 64KHz pwm
AF_DCMotor motor4(MOTOR_4, MOTOR12_64KHZ); // create motor object, 64KHz pwm

//===============================================================================
//  Initialization
//===============================================================================

int distances[8];  // Array to store distances at each angle
long distance;
const int stopDistance = 30; // Stop distance in cm
int motorSpeed = 180; // Initial motor speed
int servoAngles[] = {0, 30, 60, 90, 120, 150, 180};  // Angles for scanning, including 0° and 180°

void setup() {
  Serial.begin(9600);           // Initialize serial port
  Serial.println("Start");

  myservo.attach(10);
  myservo.write(90); // Servo facing forward

  pinMode(trigpin, OUTPUT);
  pinMode(echopin, INPUT);
  
  // Set the motor speed to 30% higher
  motorSpeed = motorSpeed * 1.3; // Increase motor speed by 30%
  motor1.setSpeed(motorSpeed);
  motor2.setSpeed(motorSpeed);
  motor3.setSpeed(motorSpeed);
  motor4.setSpeed(motorSpeed);
}

//===============================================================================
//  Main
//=============================================================================== 
void loop() {
  // Measure the distance in front of the car
  long distance_F = getAverageDistance();
  
  // Print the distance
  Serial.print("Front Distance = ");
  Serial.println(distance_F);

  // If distance in front is greater than the stop threshold, move forward
  if (distance_F > stopDistance) {
    Serial.println("Moving Forward");
    moveForward();
  } else {
    // If object is detected within stop distance, stop the car and scan for available paths
    Serial.println("Object Detected - Stopping");
    stopCar();
    scanForClearPath();
  }

  delay(100); // Short delay for smooth operation
}

//===============================================================================
//  Distance Measurement Function (with Averaging)
//===============================================================================
long getDistance() {
  digitalWrite(trigpin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin, LOW);

  long duration = pulseIn(echopin, HIGH);
  long distance = duration / 29 / 2;  // Convert time to distance in cm
  return distance;
}

// Function to get average distance for better accuracy
long getAverageDistance() {
  long totalDistance = 0;
  const int numReadings = 3; // Number of readings to average

  for (int i = 0; i < numReadings; i++) {
    totalDistance += getDistance();
    delay(10); // Small delay between readings
  }

  return totalDistance / numReadings;
}

//===============================================================================
//  Motor Control Functions
//===============================================================================
void moveForward() {
  motor1.run(FORWARD);
  motor2.run(FORWARD);
  motor3.run(FORWARD);
  motor4.run(FORWARD);
}

void stopCar() {
  motor1.run(RELEASE);         // Stop motors
  motor2.run(RELEASE);
  motor3.run(RELEASE);
  motor4.run(RELEASE);
}

//===============================================================================
//  Servo Scanning for Clear Path (Scanning Diagonally and at Extremes)
//===============================================================================
void scanForClearPath() {
  // Loop through each servo angle for scanning
  for (int i = 0; i < 7; i++) {
    myservo.write(servoAngles[i]); // Set servo to angle
    delay(120); // Delay to allow servo to move and stabilize
    distances[i] = getAverageDistance(); // Store the measured distance
    Serial.print("Distance at ");
    Serial.print(servoAngles[i]);
    Serial.print("° = ");
    Serial.println(distances[i]);
  }

  // Return servo to center (90°)
  myservo.write(90);
  delay(120);

  // Determine the direction with the longest clear distance
  int maxDistanceIndex = 0;
  for (int i = 1; i < 7; i++) {
    if (distances[i] > distances[maxDistanceIndex]) {
      maxDistanceIndex = i;
    }
  }

  int maxDistance = distances[maxDistanceIndex];
  int chosenAngle = servoAngles[maxDistanceIndex];

  // Decide direction based on the longest clear distance
  if (maxDistance > stopDistance) {
    if (chosenAngle == 90) {
      Serial.println("Clear path ahead, moving forward");
      moveForward();
    } else if (chosenAngle < 90) {
      Serial.println("Clear diagonal path to the right, turning right");
      turnRight(chosenAngle);
    } else {
      Serial.println("Clear diagonal path to the left, turning left");
      turnLeft(chosenAngle);
    }
  } else {
    Serial.println("No clear path, moving backward to rescan.");
    moveBackward(); // Move backward if no clear path found
    stopCar();
    scanForClearPath(); // Rescan environment
  }
}

//===============================================================================
//  Turning Functions with Diagonal Angle
//===============================================================================
void turnRight(int angle) {
  // Adjust turn based on angle
  int turnTime = map(angle, 0, 90, 100, 400); // Adjust turn time based on angle (faster for smaller angles)
  motor1.run(FORWARD);
  motor2.run(FORWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(turnTime); // Adjust turning time
  moveForward(); // Continue moving forward after turning
}

void turnLeft(int angle) {
  // Adjust turn based on angle
  int turnTime = map(angle, 90, 180, 400, 600); // Adjust turn time based on angle
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(FORWARD);
  motor4.run(FORWARD);
  delay(turnTime); // Adjust turning time
  moveForward(); // Continue moving forward after turning
}

//===============================================================================
//  New Function: Move Backward
//===============================================================================
void moveBackward() {
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  motor3.run(BACKWARD);
  motor4.run(BACKWARD);
  delay(1000); // Move backward for 1 second
}

How the Obstacle-Avoidance Robot Works

This robot uses an ultrasonic sensor to detect obstacles and adjust its path to avoid them. Here’s a breakdown of its functioning:

  1. component assembly and Circuit connections:
  • The Arduino controls the entire system, sending commands to the motor driver (L293D) to drive the DC motors.
  • The NE555 timer operates in a bistable mode, managed by push buttons to control the PWR pins.
  • A BC547 NPN transistor is used to switch the circuit and bridge the PWR pins of the motor shield. A resistor is included in the NE555 timer circuit to stabilize its output.
  • The ultrasonic sensor (HC-SR04) detects obstacles by measuring the time it takes for sound waves to bounce back from objects. If an obstacle is detected within a set range(30 cm in this case), the Arduino sends signals to adjust the robot’s path.

2. Programming the Robots Movement:

  • The ultrasonic sensor scans in intervals of 0°, 30°, 60°, 90°, 120°, 150° and 180°.
  • Based on sensor readings, the Arduino calculates the safest path and adjusts motor speed and direction accordingly.
  • The servo motor rotates the ultrasonic sensor, allowing the robot to scan its surroundings.

3. Enhancing Obstacle Avoidance:

  • If obstacles are detected on all sides, the robot will reverse and rescan for a new path.
  • Fine-tuning the motor speeds and sensor accuracy ensures smoother and more precise obstacle avoidance.

4. Testing and Optimization:

  • Test the robot in different environments, refining the code and position of the sensor, sometimes the obstacle may not be high enough to be sensed by the sensor.

Applications and Uses of Obstacle Avoidance Robot

The obstacle-avoidance robot is ideal for robotics beginners and enthusiasts interested in creating autonomous vehicles. This project has applications in:

  • Robotics education and workshops
  • Autonomous vehicle research and development
  • Indoor navigation systems

Additional Resources and Connect with Me

  • Code & Documentation: Check out the project’s full code, circuit diagrams, and documentation on my GitHub.
  • Project Files: Download all project files, schematics, and additional resources from my Google Drive.
  • Professional Networking: Connect with me on LinkedIn for updates on new projects and tutorials.
  • Stay Updated: For more hands-on electronics projects and tutorials, follow me on YouTube and X.

Leave a Comment