#!/usr/bin/env python
# coding: Latin-1
# Creates a web-page interface for DiddyBorg Metal Edition
# Import library functions we need
import PicoBorgRev
import time
import sys
import threading
import SocketServer
import picamera
import picamera.array
import cv2
import UltraBorg
import datetime
# Settings for the web-page
webPort = 80 # Port number for the web-page, 80 is what web-pages normally use
imageWidth = 240 # Width of the captured image in pixels
imageHeight = 180 # Height of the captured image in pixels
frameRate = 10 # Number of images to capture per second
displayRate = 2 # Number of images to request per second
photoDirectory = '/home/pi' # Directory to save photos to
# Global values
global PBR
global lastFrame
global lockFrame
global camera
global processor
global running
global watchdog
running = True
# Setup the UltraBorg
global UB
UB = UltraBorg.UltraBorg() # Create a new UltraBorg object
UB.Init() # Set the board up (checks the board is connected)
# Setup the PicoBorg Reverse
PBR = PicoBorgRev.PicoBorgRev()
#PBR.i2cAddress = 0x44 # Uncomment and change the value if you have changed the board address
PBR.Init()
if not PBR.foundChip:
boards = PicoBorgRev.ScanForPicoBorgReverse()
if len(boards) == 0:
print 'No PicoBorg Reverse found, check you are attached :)'
else:
print 'No PicoBorg Reverse at address %02X, but we did find boards:' % (PBR.i2cAddress)
for board in boards:
print ' %02X (%d)' % (board, board)
print 'If you need to change the I²C address change the setup line so it is correct, e.g.'
print 'PBR.i2cAddress = 0x%02X' % (boards[0])
sys.exit()
#PBR.SetEpoIgnore(True) # Uncomment to disable EPO latch, needed if you do not have a switch / jumper
PBR.SetCommsFailsafe(False) # Disable the communications failsafe
PBR.ResetEpo()
# Power settings
voltageIn = 1.2 * 12 # Total battery voltage to the PicoBorg Reverse
voltageOut = 12.0 # Maximum motor voltage
# Setup the power limits
if voltageOut > voltageIn:
maxPower = 1.0
else:
maxPower = voltageOut / float(voltageIn)
# Timeout thread
class Watchdog(threading.Thread):
def __init__(self):
super(Watchdog, self).__init__()
self.event = threading.Event()
self.terminated = False
self.start()
self.timestamp = time.time()
def run(self):
timedOut = True
# This method runs in a separate thread
while not self.terminated:
# Wait for a network event to be flagged for up to one second
if timedOut:
if self.event.wait(1):
# Connection
print 'Reconnected...'
timedOut = False
self.event.clear()
else:
if self.event.wait(1):
self.event.clear()
else:
# Timed out
print 'Timed out...'
timedOut = True
PBR.MotorsOff()
# Image stream processing thread
class StreamProcessor(threading.Thread):
def __init__(self):
super(StreamProcessor, self).__init__()
self.stream = picamera.array.PiRGBArray(camera)
self.event = threading.Event()
self.terminated = False
self.start()
self.begin = 0
def run(self):
global lastFrame
global lockFrame
# This method runs in a separate thread
while not self.terminated:
# Wait for an image to be written to the stream
if self.event.wait(1):
try:
# Read the image and save globally
self.stream.seek(0)
flippedArray = cv2.flip(self.stream.array, -1) # Flips X and Y
retval, thisFrame = cv2.imencode('.jpg', flippedArray)
del flippedArray
lockFrame.acquire()
lastFrame = thisFrame
lockFrame.release()
finally:
# Reset the stream and event
self.stream.seek(0)
self.stream.truncate()
self.event.clear()
# Image capture thread
class ImageCapture(threading.Thread):
def __init__(self):
super(ImageCapture, self).__init__()
self.start()
def run(self):
global camera
global processor
print 'Start the stream using the video port'
camera.capture_sequence(self.TriggerStream(), format='bgr', use_video_port=True)
print 'Terminating camera processing...'
processor.terminated = True
processor.join()
print 'Processing terminated.'
# Stream delegation loop
def TriggerStream(self):
global running
while running:
if processor.event.is_set():
time.sleep(0.01)
else:
yield processor.stream
processor.event.set()
# Class used to implement the web server
class WebServer(SocketServer.BaseRequestHandler):
def handle(self):
global PBR
global lastFrame
global watchdog
# Get the HTTP request data
reqData = self.request.recv(1024).strip()
reqData = reqData.split('\n')
# Get the URL requested
getPath = ''
for line in reqData:
if line.startswith('GET'):
parts = line.split(' ')
getPath = parts[1]
break
watchdog.event.set()
if getPath.startswith('/distances-once'):
# Ultrasonic distance readings
# Get the readings
distance1 = int(UB.GetDistance1())
distance2 = int(UB.GetDistance2())
distance3 = int(UB.GetDistance3())
distance4 = int(UB.GetDistance4())
# Build a table for the values
httpText = '