第六届全国光电赛解决方案

1 篇文章 0 订阅
1 篇文章 0 订阅

根据题目要求我们制定了两套方案,第一套是用树莓派+opencv+openmv+arduino作为主方案。树莓派作为图像处理的芯片,openmv作为辅助摄像头,arduino 作为控制舵机以及速度控制的芯片。为什么要这么做呢?主要目的是为了提高帧率以及去掉无效路径。

具体方案:

首先树莓派一个上系统后安装opencv库,采用python编程用hsv/灰度的方式找到色块并将位置信息发送给arduino。

我们将比赛地图作为绝对坐标,车自身分为6个象限,四个摄像头,前后摄像头是采用120帧的CMOS高速摄像头结合树莓派作为第1和第4象限,而左,右摄像头以x的中点分为5,6,2,3象限。这样可以时时无死角的确定信标灯的位置,再根据象限确定车的运动轨迹以取消无效路径。

# -*- coding: utf-8 -*-
"""
Created on Mon Jun  4 09:41:46 2018

@author: Hong
"""
import cv2
#from interfere import Servo          #90 center
from interfere.data  import switch
#from interfere import data
#from interfere.pid import PID
import RPi.GPIO as GPIO
import time
KP= 0.05
KI= 0
KD= 0
sum_error = 0
derror = 0
last_error = 0
Delay_1=0
Delay_2=0
lower_red = [150,50,60]               #hsv色彩空间低值
upper_red = [180,255,255]             #hsv色彩空间的高值
hightbigain = 100                     #roi 的起点
hight = 140                           #roi 的高
graylow = 130                         #阈值分割的阈值
pixw = 320                            #图像的像素宽度
pixh = 240                            #图像得像素高
length_y = 200                        #减速标志位
camera0 = cv2.VideoCapture(0)         #前摄像头
camera1 = cv2.VideoCapture(1)         #前摄像头
camera0.set(3,pixw)
camera0.set(4,pixh)
camera1.set(3,pixw)
camera1.set(4,pixh)
#============================Initializer_GPIO=======================
GPIO.setmode(GPIO.BCM)
GPIO.setup(16,GPIO.IN)                # input (close the camere)
GPIO.setup(2,GPIO.OUT)                #1 (main camera)   
GPIO.setup(3,GPIO.OUT)                #2 (behind camera)
GPIO.setup(20,GPIO.OUT)
#========================set_high===================================
GPIO.output(2,GPIO.HIGH)
GPIO.output(3,GPIO.HIGH)
def onMouse(event, x, y, flags, prams):   
    global xs,ys,ws,hs,selectObject,xo,yo,trackObject  
    if selectObject == True:  
        xs = min(x, xo)  
        ys = min(y, yo)  
        ws = abs(x-xo)  
        hs = abs(y-yo)  
    if event == cv2.EVENT_LBUTTONDOWN:  
        xo,yo = x, y  
        xs,ys,ws,hs= x, y, 0, 0  
        selectObject = True  
    elif event == cv2.EVENT_LBUTTONUP:  
        selectObject = False  
        trackObject = -1  
#++++++++++++++++++++++Initializer_camera+++++++++++++++++++++++++++
infor0 = camera0.isOpened()
infor1 = camera1.isOpened()
print(infor0,infor1)
if (infor0 & infor1):
    while(1):
        t1 = time.time()
#def Read(camera0,camera1,graylow,med,hig,hiw,Delay_1,Delay_2): #find light
        inputvalue0 = GPIO.input(16)
        #print(inputvalue0)
        x0 = x1 = y0 =y1 = 0
        ret0,img0 = camera0.read(0)
        ret1,img1 = camera1.read(0)
        gray0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
        gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
        cv2.threshold(gray0,graylow, 255, 0, gray0)
        cv2.threshold(gray1,graylow, 255, 0, gray1)
        roigray0 = gray0[hightbigain:hightbigain+hight,:]
        roigray1 = gray1[hightbigain:hightbigain+hight,:]
        aa0, contours0, hierarchy0  = cv2.findContours(roigray0, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        aa1, contours1, hierarchy1  = cv2.findContours(roigray1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        rests0 = []
        rests1 = []
#=================1摄像头图像===================================================
        for contour0 in contours0:
            approx0 = cv2.convexHull(contour0)
            area0=cv2.contourArea(approx0)
            rests0.append(area0)
#================2摄像头图像====================================================
        for contour1 in contours1:
            approx1 = cv2.convexHull(contour1)
            area1=cv2.contourArea(approx1)
            rests1.append(area1)
#==============================================================================
        if inputvalue0==0:# go ahead and find light
            if rests0: # go ahead
                mx0 = max(rests0)
                local0 = rests0.index(mx0)
                x0,y0,w0,h0 = cv2.boundingRect(contours0[local0])
                print("x0",x0,y0)
                if  y0 > length_y:
                    GPIO.output(2,GPIO.LOW) #give drive signal
                    GPIO.output(3,GPIO.HIGH)
                    GPIO.output(20,GPIO.LOW)
                    data.x_to_angle(x0)
                else:
                    GPIO.output(2,GPIO.LOW) #give drive signal
                    GPIO.output(3,GPIO.HIGH)
                    GPIO.output(20,GPIO.HIGH)
                    data.x_to_angle(x0)
            elif rests1 : # go  back
                mx1 = max(rests1)
                local1 = rests1.index(mx1)
                x1,y1,w1,h1 = cv2.boundingRect(contours1[local1])
                if y1 > length_y:
                    GPIO.output(3,GPIO.LOW)
                    GPIO.output(2,GPIO.HIGH)
                    GPIO.output(20,GPIO.LOW)
                    print("x1",x1,y1)
                    data.x_to_angle(x1)
                else:
                    GPIO.output(3,GPIO.LOW)
                    GPIO.output(2,GPIO.HIGH)
                    GPIO.output(20,GPIO.HIGH)
                    print("x1",x1,y1)
                    data.x_to_angle(x1)
            else:
                print("error!!!")
        else: # direct back
            print("zhitui")
            data.x_to_angle(160)
#===================================================================================================
        cv2.imshow("my0",img0)
        cv2.imshow("my1",img1)
        cv2.imshow("gray0",roigray0)
        cv2.imshow("gray1",roigray1)
        t2 = time.time()
        print(t2-t1)
        if (cv2.waitKey(1) & 0xff == ord('q')):
            break
        else:
            continue
    camera0.release()
    camera1.release()
    cv2.destroyAllWindows()
else:
    print("Try again!\n")
        

由于树莓派串口发送数据只有少部分数据可以用因此我们采用映射的方式将数据压缩后发送给Arduino

data源码:

import serial
import time
ser = serial.Serial('/dev/ttyUSB0',9600,timeout = 1)

class switch(object):
  def __init__(self,value):
    self.value = value
    self.fall = False

  def __iter__(self):
    yield self.match
    raise StopIteration

  def match(self,*args):
    if self.fall or not args:
      return True

    elif self.value in args:
      self.fall = True
      return True

    else:
      return False

def x_to_angle(x):
  if((x >= 130)and(x <= 190)):
    x = (int)(x/2)
  elif(x <130):
    x = 0
  else:
    x = 31

# 75  83____98____113  121        servo
# 0   130___160___190  320        camera_x
# 0   65____80____95   320        camera_x / 2  
# 4b  53____62____71   79         hex

  for case in switch(x):
    if case(0):
      ser.write('\x4b'.encode())
      break
    if case(65):
      ser.write('\x53'.encode())
      break
    if case(66):
      ser.write('\x54'.encode())
      break
    if case(67):
      ser.write('\x55'.encode())
      break
    if case(68):
      ser.write('\x56'.encode())
      break
    if case(69):
      ser.write('\x57'.encode())
      break
    if case(70):
      ser.write('\x58'.encode())
      break
    if case(71):
      ser.write('\x59'.encode())
      break
    if case(72):
      ser.write('\x5a'.encode())
      break
    if case(73):
      ser.write('\x5b'.encode())
      break
    if case(74):
      ser.write('\x5c'.encode())
      break
    if case(75):
      ser.write('\x5d'.encode())
      break
    if case(76):
      ser.write('\x5e'.encode())
      break
    if case(77):
      ser.write('\x5f'.encode())
      break
    if case(78):
      ser.write('\x60'.encode())
      break
    if case(79):
      ser.write('\x61'.encode())
      break
    if case(80):
      ser.write('\x62'.encode())
      break
    if case(81):
      ser.write('\x63'.encode())
      break
    if case(82):
      ser.write('\x64'.encode())
      break
    if case(83):
      ser.write('\x65'.encode())
      break
    if case(84):
      ser.write('\x66'.encode())
      break
    if case(85):
      ser.write('\x67'.encode())
      break
    if case(86):
      ser.write('\x68'.encode())
      break
    if case(87):
      ser.write('\x69'.encode())
      break
    if case(88):
      ser.write('\x6a'.encode())
      break
    if case(89):
      ser.write('\x6b'.encode())
      break
    if case(90):
      ser.write('\x6c'.encode())
      break
    if case(91):
      ser.write('\x6d'.encode())
      break
    if case(92):
      ser.write('\x6e'.encode())
      break
    if case(93):
      ser.write('\x6f'.encode())
      break
    if case(94):
      ser.write('\x70'.encode())
      break
    if case(95):
      ser.write('\x71'.encode())
      break
    if case(31):
      ser.write('\x79'.encode())
      break
    if case():
      break



以上完成了树莓派上面处理的全部内容。

速度控制以及舵机控制待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值