2013-03-21

Raspberry Pi parking camera with distance sensor

This build brings together a few other projects to make something potentially quite useful for a change - a parking camera with distance sensor. The feed from the webcam is shown on the LCD with a distance read-out underneath. As you get closer to the object (my hand in the videos) a circle is overlaid on the video which gets larger as you move closer. Once you get to within 30cm of the object the word "STOP" is overlaid and everything turns red.

Here it is in action:

And a close-up of the screen:


The project is made up of the following:

Camera: Microsoft Lifecam Cinema - I've used this with lots of Raspberry Pi projects - it works nicely and has a good microphone too.

Distance sensorSharp GP2Y0A02YK0F - my article Raspberry Pi distance measuring sensor with LCD output explains how to put this together.

I'm also using an Adafruit Pi Cobbler to breakout the header onto the breadboard.




For the software I'm using Pygame. Thankfully the camera supports a 176x144 resolution and since my screen is 176x220 this fits perfectly. So, after some initializing there is a main loop which simply: blits the image from the camera, reads from the distance sensor, draws the circle and text. Finally update() is called to send this to the framebuffer.

import pygame
import pygame.camera
import os
import mcp3008

BLACK = 0,0,0
GREEN = 0,255,0
RED = 255,0,0

if not os.getenv('SDL_FBDEV'):
    os.putenv('SDL_FBDEV', '/dev/fb1')

if not os.getenv('SDL_VIDEODRIVER'):
    os.putenv('SDL_VIDEODRIVER', 'fbcon')

pygame.init()
lcd = pygame.display.set_mode((176, 220))
pygame.mouse.set_visible(False)
lcd.fill(BLACK)
pygame.display.update()

pygame.camera.init()
 
size = (176,144)
cam = pygame.camera.Camera('/dev/video0', size, 'RGB')

cam.start()

font_big = pygame.font.Font(None, 50)
surf = pygame.Surface(size)
while True:
    lcd.fill(BLACK)
    cam.get_image(surf)
    lcd.blit(surf, (0,0))

    cm = mcp3008.read_2Y0A02_sensor(7)
    colour = GREEN
    if cm < 30:
        colour = RED
        text_surface = font_big.render('STOP', True, colour)
        rect = text_surface.get_rect(center=(88,72))
        lcd.blit(text_surface, rect)

    if cm < 140:
        pygame.draw.circle(lcd, colour, (88,72), (150-cm)/2, 3)
    
    text_surface = font_big.render('%dcm'%cm, True, colour)
    rect = text_surface.get_rect(center=(88,180))
    lcd.blit(text_surface, rect)

    pygame.display.update()


Finally here's the mcp3008 module which is imported above. NOTE: Since the LCD is using SPI 0.0 I have used SPI 0.1 for the mcp3008. You'll see this in the code below:

import spidev

spi = spidev.SpiDev()
spi.open(0,1)

# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
def readadc(adcnum):
    if ((adcnum > 7) or (adcnum < 0)):
        return -1
    r = spi.xfer2([1,(8+adcnum)<<4,0])
    adcout = ((r[1]&3) << 8) + r[2]
    return adcout

def read_3v3(adcnum):
    r = readadc(adcnum)
    v = (r/1023.0)*3.3
    return v

def read_2Y0A02_sensor(adcnum):
    r = []
    for i in range (0,10):
        r.append(readadc(adcnum))
    a = sum(r)/10.0
    v = (a/1023.0)*3.3
    d = 16.2537 * v**4 - 129.893 * v**3 + 382.268 * v**2 - 512.611 * v + 306.439
    cm = int(round(d))
    return cm


11 comments:

Anonymous said...

RGB is red green blue, not black. And I'm wondering, Blue must be 0, 0, 255.. Why was taken black with 0,0,0? Thanks for answer

jerbly said...

The BLACK, GREEN and RED constants are just there to make the code prettier. BLACK is used for colour keying and clearing. GREEN and RED are used for the display. I'm not using a blue colour anywhere.

Ben23 said...

This is pretty cool. Obvious enhancement would be to provide audio feedback of some kind, so the driver is not encouraged to be looking solely at the LCD when they should be regularly looking around the car during any reversing manoeuvre. Perhaps some kind of regular pulsed tone where the pulses get closer together as the distance closes, and then become a solid tone at the stop distance?

Genecyber said...

What is powering this rig? I'm having a hard time finding a battery pack that will power the Pi with attached 16x2 LCD and an attached iPhone or android device.

jerbly said...

@Genecyber - I get about 12 hours out of one of these with wifi and lcd etc. New Trent iCruiser 11000mAh External Battery Pack

Thanh Chung said...

The LCD seems no need. Use the computer screen is fine enough. The main thing we want is sensing distance anyway.

Unknown said...

@Thanh Chung - the purpose of this is to be mounted in a car.

Terry said...

Well done on the proof of concept. The audio option mentioned above sounds feasible. The camera needs to be much smaller and lighter (e.g. phone camera) with a field of view as wide as the vehicle. A distance sensor would need to be on each rear corner of vehicle for either side of road parallel parking. I'd like to see activation on engaging reverse (separate white light circuit in Australian vehicles). Screen could be mounted at the rear so that it is only visible when turning around. Any ideas for an extension of the sensors to fit to trailers and caravans? Any problems with the distance of separation of the various components? 12 volt supply?

محمد ابوخميس said...

may i connect TFT screen on pic 18f4550???

jerbly said...

I don't know. Sorry.

Brian said...

Kudos Jeremy, I really like this idea. It would be a _great_ tool for backing a truck up to connect to a trailer. @Terry had a great idea too with attaching to the trailer or caravan. I would also think about using my mobile phone as the video display.