Introduction: Obstacle and Cliff Detection Robotic Car

This is a robotic car that can detect obstacles as well as cliffs and steer away accordingly.

Supplies

HC-SR04 Ultrasonic Sensor and Holder

HW-201 Infrared Sensor

Cytron Maker Pi RP2040 Microcontroller

Chassis (including wheels and motors)

SG90 Servo Motor

Batteries (6V)

Battery Holder

Connecting Wires

Step 1: Assemble the Chassis

  1. Attach the motors on either side of the chassis using the given materials (including screws).
  2. Then attach the wheels to both of the motors.
  3. Test the motors by connecting 3V batteries to each and seeing if the wheels move in the same direction and with the same speed. Keep in the position of the wires to ensure the the wheels move in the same direction.
  4. Screw in the back wheel as well.

Step 2: RP2040 Setup With Motors

This setup requires switching the interpreter to 'Micropython (Raspberry Pi Pico)' on your IDE. In Thonny, it comes under the 'Run' tab in 'Configure Interpreter'.

  1. Connect 6V battery (preferably in the form of 4 1.5 V batteries) to the green coloured port near the ON/OFF switch. Preferably keep the batteries in a 4 - battery holder. I have connected them as a 3 - battery and a single battery holder.
  2. Connect the motors to the other two ports near the battery port. In this step you can connect any wire to any port but while coding need to adjust accordingly.
  3. Turn the switch on to see if the board lights up.

Step 3: External Components

This step involves the integration of components like Ultrasonic Sensor, Infrared Sensors and a Servo Motor.


Cytron usually provides joined wires for connecting these sensors to the white/beige coloured ports on the board, with the pin number/ground/voltage written beside. I connected the Ultrasonic to the port with GP0 and GP1, and sensors to those with GP28 and 7, and GP2 and 3, but there isn't any rule regarding which port you can connect either sensor to. The Servo motors are connected to the pins jutting out of the board with 5V potential, opposite to the 'sensor ports'. Connect all the 3 pins to the servo: (+) VCC-Middle Red Wire, (-) Ground-Brown, (S) PWM-Orange/Yellow.


Note: If your ultrasonic sensor requires 5V, DO NOT connect the voltage and ground pin from the sensor ports. Instead, head over to the servo motor pins and use an empty row to connect both the voltage (+) and ground (-) pin to the sensor and leave the ones in the sensor port hanging.

Step 4: Positioning

At the front of the car, connect the Servo from under the car to the Ultrasonic Sensor with a screw. Make sure the sensor is mobile and not tightened too much. This will observe the surroundings for any nearby obstacles in its line of sight.

Then, connect the IR Sensor on either side of the Ultrasonic, pointing downwards. This is your cliff detection sensor. Make sure to tape them so that they don't move around loosely.

Also ensure the wires don't dangle around much. Try tying them up so that they don't look messy or come in the way of your car's movement.

Step 5: The Code

This is a fairly simple code which involves an integration of Ultrasonic Sensor code, followed by the Infrared Code, and instructions for the car in each of the permutations.


from machine import Pin,PWM
from time import sleep
import time


M1A = PWM(Pin(10))
M1B = PWM(Pin(11))


M2A = PWM(Pin(8))
M2B = PWM(Pin(9))


trigger= Pin(0,Pin.OUT)  #connect ultrasonic Vcc to 5V 
echo= Pin(1,Pin.IN)


ir1 = Pin(7, Pin.IN)
ir2 = Pin(2, Pin.IN)


pwm = PWM(Pin(12))


M1A.freq(50)
M1B.freq(50)
M2A.freq(50)
M2B.freq(50)


pwm.freq(50)


def forward():
    M1A.duty_u16(0)
    M1B.duty_u16(30000)
    M2A.duty_u16(30000)
    M2B.duty_u16(0)




def backward():
    M1A.duty_u16(30000)
    M1B.duty_u16(0)
    M2A.duty_u16(0)
    M2B.duty_u16(30000)
    sleep(3)

def right():
    M1A.duty_u16(0)
    M1B.duty_u16(30000)
    M2A.duty_u16(0)
    M2B.duty_u16(0)
    #sleep(3)

def left():
    M1A.duty_u16(0)
    M1B.duty_u16(0)
    M2A.duty_u16(30000)
    M2B.duty_u16(0)
    sleep(3)

def stop():
    M1A.duty_u16(0)
    M1B.duty_u16(0)
    M2A.duty_u16(0)
    M2B.duty_u16(0)
    sleep(3)

def servo_motor_right():
    pwm.duty_u16(1500)
    time.sleep(2)

def servo_motor_left():
    pwm.duty_u16(6400)
    time.sleep(2)

def servo_motor_front():
    pwm.duty_u16(4400)
    time.sleep(2)


def distance():
    #timeelapsed = 0
    #print("start")
    trigger.off() #reset trigger
    sleep(0.2)
    trigger.on()
    sleep(0.00001) #send a short 0.01ms trigger pulse
    trigger.off()
    while echo.value()==0:
        start_time= time.ticks_us() #save start time
        #print(start_time, "STARTTIME")
        #sleep(1)
    while echo.value()==1:
        stop_time=time.ticks_us() #get the arrival time
        #print(stop_time, "STOPTIME")
        #sleep(1)
    timeelapsed = stop_time-start_time
   # multiply with the sound speed (34300 cm/s)
    obstacle_distance = int((timeelapsed *0.0343)/2)    # dis = speed*time speed of sound=343.2m/s  . divide by 2 as we half the distance echo travelled
    print("distance from object is", obstacle_distance,"cm")
    return obstacle_distance

while True:
    if distance() >=25:
        forward()

    else:
        while True:
            stop()
            if ir1.value()==0 or ir2.value()==0:
                print("FORWARD")
                print(ir1.value())
                print(ir2.value())
                forward()

            if ir1.value() == 1 and ir2.value()==1:
                stop()
                print("Move backward")
                print(ir1.value())
                print(ir2.value())

                stop()
                left()
                stop()
            servo_motor_right()
            distance_right = distance()
            servo_motor_left()
            distance_left = distance()
            servo_motor_front()
            distance_front = distance()

            if distance_right <=25:
                right()
                sleep(0.5)
                forward()
                sleep(2)
            if distance_left <=25:
                left()
                sleep(0.5)
                forward()
                sleep(2)
            if distance_front <= 25:
                forward()
                sleep(3)

            if ir1.value()==0 or ir2.value()==0:
                print("No Cliff Detected")
                print(ir1.value())
                print(ir2.value())
                forward()

            if ir1.value() == 1 and ir2.value()==1:
                stop()
                print("Cliff Detected")
                print(ir1.value())
                print(ir2.value())



                left()
                stop()
                forward()

            #sleep(2)



Step 6: Finishing

And that's it! You're done with your obstacle-avoiding, cliff-detecting robot!



Few suggestions:

  1. You could possibly stick a colour sensor to the bottom of your servo motor and now the robot can detect colours as well.
All Things Pi Contest

This is an entry in the
All Things Pi Contest