使用樹莓派製作智慧小車
電影裡,時不時地可以看到一些這樣的場景,一輛小車,上面裝有攝像頭,這輛小車可以通過電腦或都是手機進行遠端遙控,車上攝像頭拍到的畫面,可以實時地顯示在電腦或手機上,就像下圖這樣。
沒有接觸過這方面的朋友或許會覺得這是一門很高大上的技術活,其實,並不然,這種小車做起來其實很簡單。那麼,這樣子的小車,需要怎麼去做呢?
其實,我們只需要準備一塊控制小車的電路板(開發板),2到4個電機(馬達)、小車架子一個、攝像頭以及攝像頭雲臺一個,以上這些基礎配件,然後對開發板進行程式設計、控制就可以了,整 體硬體成本加起來不到500塊錢。
開發板:
開發板有很多種,比如51微控制器、樹莓派、STM32、Arduino、micro:bit等等,都可以做為小車的控制板,我使用的是樹莓派開發板,然後,可持樹莓派有很多版本、型號,最便宜的樹莓派zero 68元就可以買到,不過不建議買這種,沒有網絡卡,需要另外買網線模組,我使用的是樹莓派3B,價格220元,帶有無線和有線網絡卡,還帶有藍芽。
小車架子:某寶上有很多這種車架子,各式各樣的,只需要在某寶上搜索“智慧小車”就能找到,帶上馬達一整套,也就五六十塊錢。
攝像頭+雲臺:某寶上也是一搜一大堆,比如我下面用的那個,45塊錢。
配件準備好了,就是給小車的開發板裝系統,然後對小車進行程式設計控制。
小車的控制最主要有兩方面的控制,一個是小車的前後左右的運動控制,一個是攝像頭的拍攝、上下左右轉運的控制。
#-*- coding:UTF-8 -*- import RPi.GPIO as GPIO import time #小車電機引腳定義 LeftIn1 = 20 LeftIn2 = 21 LeftSpeed = 16 RightIn1 = 19 RightIn2 = 26 RightSpeed = 13 #設定GPIO口為BCM編碼方式 GPIO.setmode(GPIO.BCM) #忽略警告資訊 GPIO.setwarnings(False) #電機引腳初始化操作 def car_init(): global pwm_LeftSpeed global pwm_RightSpeed global delaytime GPIO.setup(LeftSpeed,GPIO.OUT,initial=GPIO.LOW) GPIO.setup(LeftIn1,GPIO.OUT,initial=GPIO.LOW) GPIO.setup(LeftIn2,GPIO.OUT,initial=GPIO.LOW) GPIO.setup(RightSpeed,GPIO.OUT,initial=GPIO.LOW) GPIO.setup(RightIn1,GPIO.OUT,initial=GPIO.LOW) GPIO.setup(RightIn2,GPIO.OUT,initial=GPIO.LOW) #設定pwm引腳和頻率為2000hz pwm_LeftSpeed = GPIO.PWM(LeftSpeed, 2000) pwm_RightSpeed = GPIO.PWM(RightSpeed, 2000) pwm_LeftSpeed.start(0) pwm_RightSpeed.start(0) #小車前進 def run(delaytime): GPIO.output(LeftIn1, GPIO.HIGH) GPIO.output(LeftIn2, GPIO.LOW) GPIO.output(RightIn1, GPIO.HIGH) GPIO.output(RightIn2, GPIO.LOW) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車後退 def back(delaytime): GPIO.output(LeftIn1, GPIO.LOW) GPIO.output(LeftIn2, GPIO.HIGH) GPIO.output(RightIn1, GPIO.LOW) GPIO.output(RightIn2, GPIO.HIGH) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車左轉 def left(delaytime): GPIO.output(LeftIn1, GPIO.LOW) GPIO.output(LeftIn2, GPIO.LOW) GPIO.output(RightIn1, GPIO.HIGH) GPIO.output(RightIn2, GPIO.LOW) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車右轉 def right(delaytime): GPIO.output(LeftIn1, GPIO.HIGH) GPIO.output(LeftIn2, GPIO.LOW) GPIO.output(RightIn1, GPIO.LOW) GPIO.output(RightIn2, GPIO.LOW) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車原地左轉 def spin_left(delaytime): GPIO.output(LeftIn1, GPIO.LOW) GPIO.output(LeftIn2, GPIO.HIGH) GPIO.output(RightIn1, GPIO.HIGH) GPIO.output(RightIn2, GPIO.LOW) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車原地右轉 def spin_right(delaytime): GPIO.output(LeftIn1, GPIO.HIGH) GPIO.output(LeftIn2, GPIO.LOW) GPIO.output(RightIn1, GPIO.LOW) GPIO.output(RightIn2, GPIO.HIGH) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime) #小車停止 def brake(delaytime): GPIO.output(LeftIn1, GPIO.LOW) GPIO.output(LeftIn2, GPIO.LOW) GPIO.output(RightIn1, GPIO.LOW) GPIO.output(RightIn2, GPIO.LOW) pwm_LeftSpeed.ChangeDutyCycle(80) pwm_RightSpeed.ChangeDutyCycle(80) time.sleep(delaytime)
攝像頭控制有兩部分,一是拍攝、二是雲臺轉動。
攝像頭的拍攝:拍攝部分,我使用的是mjpg-streamer,這個工具可以把小車上的攝像頭當作遠端攝像頭(Web Camera)使用,安裝的方式也很簡單:
#安裝必要的庫 sudo apt-get update sudo apt-get install libjpeg8-dev sudo apt-get install imagemagick sudo apt-get install libv4l-dev sudo apt-get autoremove cmake sudo apt-get install cmake
必要庫安裝好後,下載mjpg-streamer到樹莓派上,並執行編譯即可:
cd mjpg-streamer/mjpg-streamer-experimental make all sudo make install
通過以上操作,就可以啟動攝像頭了:
#執行mjpg-streamer ./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"
攝像頭啟動後,可以在區域網內的任何一臺電腦上使用瀏覽器輸入:http://樹莓派IP:8080/?action=stream 即可看到攝像頭拍到的畫面。
雲臺控制:雲臺的主是對控制上下和左右的兩舵機進行編碼控制:
import RPi.GPIO as GPIO import time import pygame #舵機引腳定義 ServoUpDownPin = 9 ServoLeftRightPin = 11 #設定GPIO口為BCM編碼方式 GPIO.setmode(GPIO.BCM) #忽略警告資訊 GPIO.setwarnings(False) #初始化上下左右角度為90度 ServoLeftRightPos = 90 ServoUpDownPos = 90 def init(): global pwm_UpDownServo global pwm_LeftRightServo GPIO.setup(ServoUpDownPin, GPIO.OUT) GPIO.setup(ServoLeftRightPin, GPIO.OUT) #設定舵機的頻率和起始佔空比 pwm_UpDownServo = GPIO.PWM(ServoUpDownPin, 50) pwm_LeftRightServo = GPIO.PWM(ServoLeftRightPin, 50) pwm_UpDownServo.start(0) pwm_LeftRightServo.start(0) #攝像頭舵機左右旋轉到指定角度 def leftrightservo_appointed_detection(pos): for i in range(1): pwm_LeftRightServo.ChangeDutyCycle(2.5 + 10 * pos/180) time.sleep(0.02) #等待20ms週期結束 pwm_LeftRightServo.ChangeDutyCycle(0) #歸零訊號 #攝像頭舵機上下旋轉到指定角度 def updownservo_appointed_detection(pos): for i in range(1): pwm_UpDownServo.ChangeDutyCycle(2.5 + 10 * pos/180) time.sleep(0.02) #等待20ms週期結束 pwm_UpDownServo.ChangeDutyCycle(0) #歸零訊號 #攝像頭舵機向上運動 def servo_up(): global ServoUpDownPos pos = ServoUpDownPos updownservo_appointed_detection(pos) #time.sleep(0.05) pos +=0.7 ServoUpDownPos = pos if ServoUpDownPos >= 180: ServoUpDownPos = 180 #攝像頭舵機向下運動 def servo_down(): global ServoUpDownPos pos = ServoUpDownPos updownservo_appointed_detection(pos) #time.sleep(0.05) pos -= 0.7 ServoUpDownPos = pos if ServoUpDownPos <= 45: ServoUpDownPos = 45 #攝像頭舵機向左運動 def servo_left(): print("servo_left") global ServoLeftRightPos pos = ServoLeftRightPos leftrightservo_appointed_detection(pos) #time.sleep(0.10) pos += 0.7 ServoLeftRightPos = pos print('ServoLeftRightPos:',ServoLeftRightPos) if ServoLeftRightPos >= 180: ServoLeftRightPos = 180 #攝像頭舵機向右運動 def servo_right(): global ServoLeftRightPos pos = ServoLeftRightPos leftrightservo_appointed_detection(pos) #time.sleep(0.10) pos -= 0.7 ServoLeftRightPos = pos if ServoLeftRightPos <= 0: ServoLeftRightPos = 0 #所有舵機歸位 def servo_init(): servoflag = 0 servoinitpos = 90 if servoflag != servoinitpos: updownservo_appointed_detection(servoinitpos) leftrightservo_appointed_detection(servoinitpos) time.sleep(0.5) pwm_LeftRightServo.ChangeDutyCycle(0) #歸零訊號 pwm_UpDownServo.ChangeDutyCycle(0) #歸零訊號 #舵機停止 def servo_stop(): pwm_LeftRightServo.ChangeDutyCycle(0) #歸零訊號 pwm_UpDownServo.ChangeDutyCycle(0) #歸零訊號
對小車的控制程式設計完成後,最後我們使用WebSocket遠端連線小車,傳送相關的控制命令,就可以使用電腦或手機遠端控制小車了。
完整的教學視訊可檢視:http://www.diyabc.com/frontweb/product400.html
&n