Path Finder

../_images/PathFinder.JPG

Description

This vehicle is designed to follow a specific colored path and measure the distance of the flat surface it is traveling. It is built to run on Raspberry Pi board, based on the Coder-Maker prototype : a combination of technology and scientific concepts.

Learning Objectives

  • Conversion of angular to linear motion
  • Relate wheel circumference and radius of a moving device to the distance traveled.
  • Design and make an application based on the engineering design process
  • Replicate the wiring connection and the Python code used on the Raspberry Pi
  • Relate science concepts to real-life applications

Materials Needed

  • Raspberry Pi with micro SD card with Raspbian
  • Breadboard & Jumper Wires
  • 2x Gear motors
  • 2x Wheels
  • L293d (H-bridge)
  • Wheel Encoder
  • MCP3008 (ADC)
  • Analog Grayscale Sensor
  • Glue gun
  • Rectangular Plexiglas Board
  • 6V battery
  • 5V Power supply

Setup and Functionality

This application consists on controlling the wheels (aka gear motors) based on the grayscale sensor output, which detects black and white. According to the algorithm used, it outputs a result very close to zero when it detects white, and a larger output when it detects black. It is coded such that the machine will follow a white path: when it detects a black one, it will stop, and check left then right for a white path.

Meanwhile, it is measuring the distance traveled using a wheel encoder attached to one of the gear motors.

The H-bridge L293D is used to control the rotational direction of the gear motors.

The MCP3008 is used as an ADC to read the analog signal from the grayscale sensor and convert it to a digital signal for the Raspberry Pi to read.

Circuitry and Electronics:

All the electronics used are to be connected as shown in the picture below:

../_images/PathFinder.png

Programming

This application is coded using Python :

import RPi.GPIO as GPIO
import time
import spidev

# INITIALIZING

#CODE FOR GEAR MOTOR using H-bridge (L293d)
# Act upon the results of the grey sensor data

GPIO.setmode(GPIO.BOARD)

Motor1A = 7
Motor1B = 8
Motor1E = 10

GPIO.setup(Motor1A,GPIO.OUT)
GPIO.setup(Motor1B,GPIO.OUT)
GPIO.setup(Motor1E,GPIO.OUT)

Motor2A = 33
Motor2B = 35
Motor2E = 37

GPIO.setup(Motor2A,GPIO.OUT)
GPIO.setup(Motor2B,GPIO.OUT)
GPIO.setup(Motor2E,GPIO.OUT)

#CODE FOR WHEEL ENCODER // INITIALIZE

encoder=0
sum0=0
sum1=0
sum00=0
sum11=0
HighLow = -0.05

GPIO.setmode(GPIO.BOARD)
GPIO.setup(40,GPIO.IN)

temp = GPIO.input(40)

#CODE FOR GREY SENSOR using MCP 
#MCP3008 uses SPI(Serial Peripheral Interface bus)
#SPI uses SPIDev library from Python

delay = 0.5
ldr_channel = 0 #Grey Sensor is connected to channel 0(pin 1) of MCP
	
spi = spidev.SpiDev()
spi.open(0,0)


#creating a function to read from channel 
def readadc (adcnum):
    if adcnum>7 or adcnum < 0:
        return -1
    adc = spi.xfer2([1, 8 + adcnum << 4, 0])
    data = (( adc[1]&3) << 8 + adc[2])
    return data

def color() :
    sum1 = 0
    sum2 = 0
    ldr_value = readadc(ldr_channel)
    if ldr_value != 0:
        result = ldr_value/1024
        sum1 = sum1 + 10
        while result != (ldr_value%1023):
            result = result/1024
            sum1 = sum1 + 10
            if sum1 > 1024:
                break

        result = ldr_value%1023
        while result != 1:
            result = result/2
            sum2 = sum2 + 1
            if sum2>1024:
                break
             
    result = ((sum1 + sum2)/1024.0)
    print result
    return result

# RUNNING 

while True :
    result = color()
    while( result > 0.05):
        print result
        print 'BLACK'
        print "Stopping motor"
        GPIO.output(Motor1E,GPIO.LOW)
        GPIO.output(Motor2E,GPIO.LOW)
        time.sleep(1)
        print "Checking white path"

        GPIO.output(Motor1E,GPIO.HIGH)
        GPIO.output(Motor1A,GPIO.HIGH)
        GPIO.output(Motor1B,GPIO.LOW)
        GPIO.output(Motor2E,GPIO.HIGH)
        GPIO.output(Motor2A,GPIO.HIGH)
        GPIO.output(Motor2B,GPIO.LOW)
        time.sleep(0.5)       

        print "Checking TO THE LEFT"
        GPIO.output(Motor1E,GPIO.HIGH)
        GPIO.output(Motor1A,GPIO.LOW)
        GPIO.output(Motor1B,GPIO.HIGH)
        GPIO.output(Motor2E,GPIO.HIGH)
        GPIO.output(Motor2A,GPIO.HIGH)
        GPIO.output(Motor2B,GPIO.LOW)
        time.sleep(3)
        result = color()
        if result < 0.05:
            break
                

        else :
                print "Checking TO THE Right"
                GPIO.output(Motor1E,GPIO.HIGH)
                GPIO.output(Motor1A,GPIO.HIGH)
                GPIO.output(Motor1B,GPIO.LOW)
                GPIO.output(Motor2E,GPIO.HIGH)
                GPIO.output(Motor2A,GPIO.LOW)
                GPIO.output(Motor2B,GPIO.HIGH)
                time.sleep(6)
                result = color()
                if result < 0.05:
                    break
    else:        
        print 'WHITE'
        print "Turning motor on"
        GPIO.output(Motor1E,GPIO.HIGH)
        GPIO.output(Motor1A,GPIO.LOW)
        GPIO.output(Motor1B,GPIO.HIGH)
        GPIO.output(Motor2E,GPIO.HIGH)
        GPIO.output(Motor2A,GPIO.LOW)
        GPIO.output(Motor2B,GPIO.HIGH)
        
    #Measuring flat distance of path 
        start = time.time()
        for i in range(0,1000000):
            encoder = GPIO.input(40)
            if(encoder==0):
                sum0 = sum0 + 1
                if(temp != encoder):
                    temp = encoder
                    HighLow = HighLow + 0.05
                    sum00 = sum0
                    sum0 = 0
                    #print "zeros", sum00
                    print HighLow #distance
                    
            else :
                sum1 = sum1 + 1
                if(temp != encoder):
                    temp = encoder
                    HighLow = HighLow + 0.05
                    sum11 = sum1
                    sum1 = 0
                    #print "ones", sum11
                   print HighLow #distance
        if( HighLow!= -0.05):
            stop = time.time()
            timepassed = stop-start
            print timepassed
            rpm = HighLow/(timepassed/60)
            ms = 3.141*0.21*(HighLow/timepassed)
        else :
            rpm = 0;
        f=open('/home/pi/Desktop/Speed.txt','w')
        f.write("speed:" + str(int(rpm)) + " rpm   ")
        f.write( str(round(ms,2)) + " m/s ")
        f.close()
            print rpm
            if ( ( ( int(HighLow%2) == 1) or ( int(HighLow%2) == 0) ) and int(HighLow) > 0 ):
                print 'rounds', HighLow
        time.sleep(delay)

Science Concepts and Skills

The distance travelled by the vehicle is determined by the data collected by the wheel encoder, which is actually measuring the number of revolutions per minute of the rotating wheels.

The total distance travelled by the vehicle can be determined in 2 ways:

Way 1, Tech-based: The distance travelled can be calculated through the code above based on the diameter of the wheel of the encoder. It can also be calculated using the formula:

v = r × v_a × 0.10472

Where:
v is the linear velocity in m/s
r is the radius of anemometer revolving piece
v_a is the angular velocity (circular), in rpm (rotations per minute)

Read more.

Way 2, Mechanical-based: Students can measure the circumference of the wheel and put a mark on it. They will count the number of rotations of the wheel for a certain distance and multiply it with the circumference. This will give them the total distance travelled. They can also find the circumference of the wheel by using the formula:

D = 2*π*r
Where D is the circumference of the wheel in cm or m
R is the radius of the wheel in cm or m
(The unit of r determines the unit of D. If r in cm, then D is in cm.)

Flex your brain! How can you improve this device by adding safety options that will prevent it from hitting obstacles?