要追蹤人臉就需要可以動的相機,這邊使用的是 露天 買的二軸雲台,使用兩個 SG90 伺服馬達來帶動雲台。
馬達由 Raspberry Pi 供給 5VDC,並使用 GPIO pin 控制角度,Python 控制 Servo 的方法,參考 http://www.toptechboy.com/raspberry-pi/raspberry-pi-lesson-28-controlling-a-servo-on-raspberry-pi-with-python/ 這篇專業文... 剛剛發現 這一篇 文章跟我做類似的事情... 我的接線圖,如下:
基本上 SG90 這顆便宜馬達的公差還滿大的,因此建議對每一顆馬達做範圍校正,先抓出最大和最小的 DutyCycle,盡量避免 Raspberry Pi 輸出超過範圍的 DutyCycle,這樣馬達很容易燒壞的。下面這一段 code 主要就是在做校正。手動輸入 DutyCycle,看馬達的反應...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import datetime
import sys
import RPi.GPIO as GPIO
def initGPIO():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
GPIO.cleanup()
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
class servoSG90():
def __init__(self, GPIO_Pin=12, PWM_Freq=50, dc0=5, dc100=10):
self.dc0 = dc0
self.dc100 = dc100
self.pwm_now = 50
self.deg_now = 90
self.pwm_gpio = GPIO_Pin
self.pwm_freq = PWM_Freq
self.servo = GPIO.PWM(GPIO_Pin,50)
self.servo.start( (self.dc0+self.dc100)/2 )
self.setPWM( self.pwm_now )
time.sleep(1)
def setPWM(self, pwm): ## Range 0 - 100
if pwm > self.pwm_now:
pwm_step = 5
elif pwm < self.pwm_now:
pwm_step = -5
else:
return
for pwm_new in range(self.pwm_now, int(pwm), pwm_step):
dc_new = round( ( self.dc100 - self.dc0 )/100*pwm_new + self.dc0 ,1)
if dc_new > self.dc100:
dc_new = self.dc100
elif dc_new < self.dc0:
dc_new = self.dc0
self.servo.ChangeDutyCycle( dc_new )
print(" --- Change PWM Steping... %d - %.1f"%(pwm_new, dc_new) )
time.sleep(.1)
self.pwm_now = int(pwm_new)
def setDutyCycle(self, dc):
self.servo.ChangeDutyCycle( dc )
time.sleep(0.2)
def stop(self):
self.servo.ChangeDutyCycle( 7 )
time.sleep(1)
self.servo.stop()
def testServo1(servo):
for x in range(50,100,2):
pwm = float(x)/10
print("Current Location %.1f ..." %(pwm))
servo.setDutyCycle(pwm)
time.sleep(.1)
def testServo2(servo):
print("\n\n --- Test Servo ---\n\tPress 'q' to exit test mode...\n\tPress 'dc0' to set Min DutyCycle...\n\tPress 'dc100' to set Max DutyCycle...\n")
dc_old = '5.0'
while True:
dc_raw = raw_input("Please enter raw pwm value (%s): "%dc_old)
if 'dc0' in dc_raw:
print("Set DC-0 as %s"%dc_old )
servo.dc0 = float(dc_old)
elif 'dc100' in dc_raw:
print("Set DC-100 as %s"%dc_old )
servo.dc100 = float(dc_old)
elif dc_raw.lower() in 'quit, q':
return
else:
dc_old = dc_raw
servo.setDutyCycle(float(dc_old))
#time.sleep(1)
def testServo3(servo):
for i in range(2):
for x in range(100):
pwm = int(x)
print("Change PWM to %d ..." %(pwm))
servo.setPWM(pwm)
time.sleep(.1)
print("\n --- Test-3 Stop --- ")
servo.setPWM(50)
time.sleep(1)
def main():
initGPIO()
servo1 = servoSG90(12, 50, 5, 10.) ## 建立馬達 instant,DutyCycle範圍是 5 ~ 10.
testServo1(servo1) ## 測試一:讓馬達由最小 DutyCycle 轉到最大 DutyCycle
testServo2(servo1) ## 測試二:手動輸入 DutyCycle,確認馬達的 DutyCycle 範圍
testServo3(servo1) ## 測試三:讓馬達由新的最小 DutyCycle 轉到最大 DutyCycle
servo1.stop()
if __name__ == "__main__":
main()
GPIO.cleanup()
sys.exit()
|
說完雲台的部分,再來講相機... 我用的是 PiCamera,OpenCV沒有直接支援它,需要另外裝 PiCamera 的 Python module,Google一下,有很多人分享怎麼用 Python + OpenCV + PiCamera,我主要參考 這一篇,另外 這一篇 也不錯... 幸好安裝不難...
pi@rpi:~ $ workon cv
(cv) pi@rpi:~ $ sudo pip install "picamera[array]"
## 安裝 PiCamera 的重點是... 要加參數 [array] ,這樣才可以把照片餵給 OpenCV
|
再來就是測試 PiCamera了,測試 Code 如下:
(cv) pi@rpi:~ $ nano picam.py
#!/usr/bin/env python
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import time
import sys
def initPiCamera():
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
camera.hflip = False
camera.vflip = False # True
rawCapture = PiRGBArray(camera, size=(640, 480))
# allow the camera to warmup
time.sleep(1)
return(camera, rawCapture)
def main():
(camera, rawCapture) = initPiCamera()
i, t0, t1 = 0, time.time(), time.time()
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
# grab the raw NumPy array representing the image, then initialize the timestamp
# and occupied/unoccupied text
image = frame.array
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# show the frame
cv2.imshow("Detect Face - Press 'q' to stop", image)
key = cv2.waitKey(1) & 0xFF
# clear the stream in preparation for the next frame
rawCapture.truncate(0)
# if the `q` key was pressed, break from the loop
if key == ord("q"):
rawCapture.truncate(0)
cv2.destroyAllWindows()
print("\n\n --- Test PiCamera Done --- " )
break
i += 1
if i == 50:
print("\n PiCamera FPS : %.1f"%(50/(time.time() - t1)) )
i, t1 = 0, time.time()
if __name__ == "__main__":
main()
sys.exit()
(cv) pi@rpi:~ $ python picam.py
PiCamera FPS : 7.2
PiCamera FPS : 7.1
|
測試了一下,雖然我設定 32 framerate,但是實際上 OpenCV 由 PiCamera 抓出影像,再顯示在視窗上,只有 7.1 FPS。
下一篇:人臉追蹤相機-初體驗
留言列表