Skip to main content

Build. Learn.
Innovate.

Basic Obstacle Avoidance Robot

Written By:

Published on:

Project Overview

This project combines several components to build a simple robot that can detect and avoid obstacles. Students will integrate sensors and motors.

Educational Goals

  • Integrate multiple sensors and actuators.
  • Develop basic robot navigation logic.
  • Practice conditional programming (if-else statements).
  • Combine concepts from previous projects (motor control, distance sensing).

Detailed Parts List

  • ESP32 – 1
  • L298N Motor Driver – 1
  • TT Motor Dual DC 3-6V Gearbox Motor – 2
  • HC-SR04 Ultrasonic Module Distance Sensor – 1
  • External Power Supply for Motors (appropriate voltage, e.g., 3-6V) – 1
  • Robot Chassis/Platform (can be simple cardboard or plastic)
  • Wheels for TT Motors – 2
  • Caster Wheel (for balance) – 1
  • Breadboard – 1
  • Jumper Wires – Male-to-Male
  • Voltage Divider components for HC-SR04 Echo pin (2 resistors)

Circuit Diagram Description

Mount the ESP32, L298N, and breadboard onto the robot chassis. Connect the L298N to the ESP32 and the two TT motors as described in Project 4 (using both motor channels of the L298N). Connect the external motor power supply to the L298N. Mount the HC-SR04 ultrasonic sensor to the front of the chassis. Connect the HC-SR04 to the ESP32 as described in Project 3, including the voltage divider for the Echo pin.

Software Functionality

The MicroPython code will continuously read the distance from the ultrasonic sensor. If the distance is below a certain threshold, the robot will stop and perform an obstacle avoidance maneuver (e.g., turn in place, back up and turn). If no obstacle is detected, the robot will move forward.

Web Interface Features

A web interface could display the current distance reading and the robot’s current status (e.g., “Moving Forward”, “Obstacle Detected”, “Turning”).

Implementation Steps

  • Assemble the robot chassis, motors, and wheels.
  • Mount the electronics onto the chassis and wire everything according to the circuit descriptions for motor control and the ultrasonic sensor.
  • Write the MicroPython code for obstacle avoidance logic.
  • Upload and run the code on the ESP32.
  • Test the robot’s movement and obstacle avoidance capabilities.

Extensions and Challenges

  • Add more ultrasonic sensors for better obstacle detection coverage.
  • Incorporate IR sensors for line following.
  • Implement more complex obstacle avoidance algorithms.
  • Add a simple arm using a servo motor.

Troubleshooting Guide

  • Robot not moving: Check all power connections (ESP32 and motor driver). Verify motor connections and the L298N wiring. Ensure the motor control code is functioning correctly.
  • Robot not avoiding obstacles: Check the ultrasonic sensor wiring and code for reading distance. Verify the distance threshold in the code is appropriate. Debug the obstacle avoidance logic to ensure it’s executing correctly when an obstacle is detected.
  • Erratic movement: This could be due to power issues or noisy sensor readings. Ensure stable power supplies and consider adding decoupling capacitors if needed.

Project Code

# This script controls a robot with obstacle avoidance and displays status
# and distance on an OLED screen.

from machine import Pin, PWM, I2C # Import necessary classes
import time

# Import SSD1306 library.
try:
    import ssd1306
except ImportError:
    print("ssd1306.py library not found. Please upload it.")
    class MockSSD1306:
        def __init__(self, width, height, i2c): print(f"MockSSD1306 initialized ({width}x{height}).")
        def fill(self, color): pass
        def text(self, text, x, y, color): pass
        def show(self): print(f"OLED display content not shown (ssd1306 library missing): {text}")
    ssd1306 = type('ssd1306', (object,), {'SSD1306_I2C': MockSSD1306})()


# --- Motor Control Setup (from Project 4) ---
in1_pin_A = 17
in2_pin_A = 16
ena_pin_A = 18 # PWM-capable
in3_pin_B = 13
in4_pin_B = 12
enb_pin_B = 14 # PWM-capable

in1_A = Pin(in1_pin_A, Pin.OUT)
in2_A = Pin(in2_pin_A, Pin.OUT)
in3_B = Pin(in3_pin_B, Pin.OUT)
in4_B = Pin(in4_pin_B, Pin.OUT)

pwm_ena_A = PWM(Pin(ena_pin_A), freq=1000)
pwm_enb_B = PWM(Pin(enb_pin_B), freq=1000)

def control_motor_A(direction, speed):
    speed = max(0, min(1023, speed))
    if direction == "forward":
        in1_A.value(1)
        in2_A.value(0)
    elif direction == "reverse":
        in1_A.value(0)
        in2_A.value(1)
    else: # stop
        in1_A.value(0)
        in2_A.value(0)
    pwm_ena_A.duty(speed)

def control_motor_B(direction, speed):
    speed = max(0, min(1023, speed))
    if direction == "forward":
        in3_B.value(1)
        in4_B.value(0)
    elif direction == "reverse":
        in3_B.value(0)
        in4_B.value(1)
    else: # stop
        in3_B.value(0)
        in4_B.value(0)
    pwm_enb_B.duty(speed)

# Function to move the robot and update OLED status
def move_robot(left_direction, left_speed, right_direction, right_speed, status_text):
    control_motor_A(left_direction, left_speed)
    control_motor_B(right_direction, right_speed)
    print("Robot:", status_text) # Print to console for debugging
    # Update OLED status
    oled.text("Status:", 0, 16, 1)
    # Clear previous status text (optional, but good for fixed position updates)
    oled.fill_rect(0, 24, oled_width, 8, 0) # Clear line below status label
    oled.text(status_text, 0, 24, 1)
    oled.show()


# Robot basic movements with OLED status update
def move_forward(speed):
    move_robot("forward", speed, "forward", speed, "Moving Forward")

def move_reverse(speed):
    move_robot("reverse", speed, "reverse", speed, "Moving Reverse")

def turn_left(speed):
    move_robot("reverse", speed, "forward", speed, "Turning Left")

def turn_right(speed):
    move_robot("forward", speed, "reverse", speed, "Turning Right")

def stop_robot():
    move_robot("stop", 0, "stop", 0, "Stopped")


# --- Ultrasonic Sensor Setup (from Project 3) ---
trigger_pin_us = 4
echo_pin_us = 5
trigger_us = Pin(trigger_pin_us, Pin.OUT)
echo_us = Pin(echo_pin_us, Pin.IN)
speed_of_sound_cm_per_us = 0.0343

def measure_distance():
    trigger_us.value(0)
    time.sleep_us(2)
    trigger_us.value(1)
    time.sleep_us(10)
    trigger_us.value(0)

    pulse_start = time.ticks_us()
    pulse_end = time.ticks_us()

    timeout_us = 20000 # Timeout after 20ms
    start_time = time.ticks_us()
    while echo_us.value() == 0:
        pulse_start = time.ticks_us()
        if time.ticks_diff(pulse_start, start_time) > timeout_us:
            return -1

    start_time = time.ticks_us()
    while echo_us.value() == 1:
        pulse_end = time.ticks_us()
        if time.ticks_diff(pulse_end, start_time) > timeout_us:
            return -1


    pulse_duration_us = time.ticks_diff(pulse_end, pulse_start)

    if pulse_duration_us > 0:
        distance_cm = (pulse_duration_us * speed_of_sound_cm_per_us) / 2
        return distance_cm
    else:
        return -1


# --- OLED Setup ---
i2c_sda = 21
i2c_scl = 22
oled_width = 128
oled_height = 32

i2c = I2C(0, sda=Pin(i2c_sda), scl=Pin(i2c_scl), freq=400000)
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

# Clear the OLED display on startup
oled.fill(0)
oled.text("Robot Starting...", 0, 0, 1)
oled.show()
time.sleep(1)


# --- Robot Control Logic ---
obstacle_threshold_cm = 25
drive_speed = 600
turn_speed = 500
turn_duration = 0.8 # Duration in seconds for turning

print("Starting obstacle avoidance robot script with OLED display...")

# Start the main robot control loop.
while True:
    # Measure the distance.
    distance = measure_distance()

    # --- Display Distance on OLED ---
    oled.fill_rect(0, 0, oled_width, 8, 0) # Clear previous distance text line
    oled.text("Dist: ", 0, 0, 1)

    if distance != -1:
        oled.text("{:.1f} cm".format(distance), 35, 0, 1) # Display value
    else:
        oled.text("N/A", 35, 0, 1) # Indicate no reading

    oled.show() # Update OLED with distance

    # Check for obstacle and control robot movement.
    if distance != -1 and distance < obstacle_threshold_cm:
        stop_robot() # This function also updates OLED status
        time.sleep(0.5)

        move_reverse(drive_speed)
        time.sleep(1)
        stop_robot()
        time.sleep(0.5)

        turn_right(turn_speed)
        time.sleep(turn_duration)
        stop_robot()
        time.sleep(0.5)

        time.sleep(0.5) # Give sensor time to settle
        distance_after_turn = measure_distance()
        print("Distance after turn:", distance_after_turn, "cm")


    else:
        move_forward(drive_speed) # This function also updates OLED status

    time.sleep(0.1)

# This loop will run forever.

# Troubleshooting notes:
# - See troubleshooting notes from Project 7, Project 3 (Ultrasonic), and Project 2 (OLED).
# - Ensure both ssd1306.py is on the ESP32.
# - Debug motor control and ultrasonic sensor functionality independently first.
# - Check OLED wiring and I2C communication.

STEM Benefits

Science:

  • Physics of Motion: Understanding how motors create movement.
  • Sound Waves (from Ultrasonic Sensor): Reinforcing concepts from Project 3.

Technology:

  • Robotics: Building and programming a simple mobile robot.
  • Sensor Integration: Combining input from a sensor (ultrasonic) to control actuators (motors).

Engineering:

  • System Integration: Combining multiple electronic and mechanical components into a functional system.
  • Control Algorithms (basic): Developing logic for navigation and obstacle avoidance (sense-plan-act cycle).
  • Mechanical Design (basic): Assembling a robot chassis and mounting components.

Mathematics:

  • Spatial Reasoning: Thinking about the robot’s position and movement in space.
  • Thresholds and Comparisons: Using numerical thresholds from the distance sensor to make decisions in the code.
  • Geometry (implicit in turns): Understanding that turning involves changing direction by a certain angle.

Projects
ShowCase

Real-World Projects
with Code & Hardware

Insights, Ideas
& How-Tos

Help, Support, and
Common Questions

What types of projects can I find on your website?

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.