1. 程式人生 > >樹莓派 智慧小車 自動抓取乒乓球

樹莓派 智慧小車 自動抓取乒乓球

所需硬體

  • 智慧小車
  • 樹莓派3B
  • Pi Camera

環境配置

  • 安裝opencv
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python-opencv
  • 安裝PiCamera來控制攝像頭
sudo apt-get install python-pip 
sudo apt-get install python-dev 
sudo pip install picamera

程式碼

import cv2
import cv2.cv as cv
import cv
import picamera
import
picamera.array import math import numpy as np import zmq import time import serial, time, sys from PIL import Image # For OpenCV2 image display IMAGE_WINDOW_NAME = 'YelloBarTracker' CONTROL_WINDOW_NAME = 'Control' MASK_WINDOW_NAME = 'Mask' # For socket communication port = '5556' context = zmq.Context() socket = context.socket(zmq.PUB) # Setting the initial mask threshold
# 根據環境除錯資料以便準確的捕捉小球 iLowH = 5 iHighH = 22 iLowS = 219 iHighS = 255 iLowV = 149 iHighV = 255 # 是否抓到球 getball = 0 # connect arduino # 將arduino接到樹莓派上,輸入ls /dev檢視,我的是ttyUSB0 def connect_arduino(): arduino = serial.Serial('/dev/ttyUSB0',9600,timeout=1) arduino.close() arduino.open() return arduino # Require by cv2.createTrackbar. we have nothing to do with nothing method
def nothing(var): pass def connect(): print('Getting data from camera...') socket.bind('tcp://*:%s' % port) # Create trackbars for easier adjustment of the HSV threshold 方便手動調節區間 def make_hsv_adjustment(): cv2.namedWindow(CONTROL_WINDOW_NAME) cv2.createTrackbar('LowH', CONTROL_WINDOW_NAME, iLowH, 255, nothing); #Hue (0 - 179) cv2.createTrackbar('HighH', CONTROL_WINDOW_NAME, iHighH, 255, nothing); cv2.createTrackbar('LowS', CONTROL_WINDOW_NAME, iLowS, 255, nothing); #Saturation (0 - 255) cv2.createTrackbar('HighS', CONTROL_WINDOW_NAME, iHighS, 255, nothing); cv2.createTrackbar('LowV', CONTROL_WINDOW_NAME, iLowV, 255, nothing); #Value (0 - 255) cv2.createTrackbar('HighV', CONTROL_WINDOW_NAME, iHighV, 255, nothing); def track(image): '''Accepts BGR image as Numpy array Returns: (x,y) coordinates of centroid if found (-1,-1) if no centroid was found None if user hit ESC ''' # Blur the image to reduce noise blur = cv2.GaussianBlur(image, (5,5),0) # Convert BGR to HSV hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV) # Get the treshold from the trackbars iLowH = cv2.getTrackbarPos('LowH', CONTROL_WINDOW_NAME) iHighH = cv2.getTrackbarPos('HighH', CONTROL_WINDOW_NAME) iLowS = cv2.getTrackbarPos('LowS', CONTROL_WINDOW_NAME) iHighS = cv2.getTrackbarPos('HighS', CONTROL_WINDOW_NAME) iLowV = cv2.getTrackbarPos('LowV', CONTROL_WINDOW_NAME) iHighV = cv2.getTrackbarPos('HighV', CONTROL_WINDOW_NAME) # Threshold the HSV image for only green colors lower_yellow = np.array([iLowH,iLowS,iLowV]) upper_yellow = np.array([iHighH,iHighS,iHighV]) # Threshold the HSV image to get only yellow colors mask = cv2.inRange(hsv, lower_yellow, upper_yellow) cv2.imshow(MASK_WINDOW_NAME, mask) # Blur the mask bmask = cv2.GaussianBlur(mask, (5,5),0) # Take the moments to get the centroid moments = cv2.moments(bmask) m00 = moments['m00'] centroid_x, centroid_y, radius = None, None, None if m00 != 0: centroid_x = int(moments['m10']/m00) centroid_y = int(moments['m01']/m00) radius = int(math.sqrt(m00 / 255 / 3.14159265358979323846)) # Assume no centroid ball = (-1,-1, 0) # Use centroid if it exists if centroid_x != None and centroid_y != None and radius != None: ball = (centroid_x, centroid_y, radius) # 中心座標及半徑 # Put red circle in at centroid in image cv2.circle(image, (centroid_x, centroid_y), 4, (255,0,0)) # center cv2.circle(image, (centroid_x, centroid_y), radius, (0,255,0)) # Display full-color image cv2.imshow(IMAGE_WINDOW_NAME, image) # Force image display, setting centroid to None on ESC key input if cv2.waitKey(1) & 0xFF == 27: ball = None # Return coordinates of ball return ball if __name__ == '__main__': connect() make_hsv_adjustment(); arduino = connect_arduino(); with picamera.PiCamera() as camera: with picamera.array.PiRGBArray(camera) as stream: camera.resolution = (320, 240) while True: camera.capture(stream, 'bgr', use_video_port=True) # stream.array now contains the image data in BGR order image = stream.array ball = track(image) if not ball: break if cv2.waitKey(1) & 0xFF == 27: break msg = '%d %d %d' % ball print(msg) socket.send(msg) # try # 未抓到球時發現距離較近,嘗試抓取 if ball[2] > 55 and getball == 0: # 前進一步 arduino.write('1') # 夾取 arduino.write('s') # 假設夾取到 getball = 1 # 已成功夾取到 elif ball[2] > 55 and getball == 1: # 小車停止 arduino.write('9') break; # 未成功抓取 釋放夾手 else: arduino.write('r') getball = 0 if getball == 0: # 前方未發現有小球 if ball[2] <= 2: # 原地右轉 arduino.write('8') arduino.write('9') else: # 小球在前方偏右 (攝像頭安裝時是倒的) if ball[0] < 130 and ball[2] <= 20: # 原地右轉 arduino.write('8') arduino.write('9') # 小球在前方偏左 elif ball[0] > 190 and ball[2] <= 20: # 原地左轉 arduino.write('7') arduino.write('9') else: arduino.write('1') # reset the stream before the next capture stream.seek(0) stream.truncate() time.sleep(1); # 完成夾取小球的任務後可以通過在控制檯敲入指令控制小車 while True: cmd = sys.stdin.readline() arduino.write(cmd) cv2.destroyAllWindows()

(實訓時做的,水平有限,易受環境光照影響,小車找尋與抓取速度也較慢,僅供參考)