【樹莓派-網絡監控(3)】基於python3控制兩自由度舵機,實現攝像頭拍攝角度的遙控

基於python3控制兩自由度舵機,實現攝像頭拍攝角度的遙控【樹莓派-網絡監控(3)】


前期內容提要:


在完成網絡攝像頭的前期準備並實現監控畫面的正常傳輸後,我們需要實現工程的第二個需求,監控畫面角度的實時遙控在這裏插入圖片描述
基本思路:憑藉兩個舵機實現攝像頭水平方向與垂直方向轉動;選用Python的RPi.GPIO模塊控制舵機所連針腳實現舵機的旋轉以控制攝像頭拍攝畫面角度;後續工程由於需要引入異步io框架搭建Web控制頁面,因此舵機的方向控制程式和攝像頭主控制程式應當分離以保障代碼的簡潔性和可讀性:

文件 功能
/steering.py 舵機控制程序
/config.ini 配置文件(寫入舵機接入的針腳數、舵機初始角度、最大最小旋轉角度等信息)
/index.py 主程序(後續python異步io框架tornado也會在此文件中加工)

一、舵機控制程式(/steering.py)編寫思路

SG90 脈衝週期爲20毫秒(millisecond),脈寬0.5ms-2.5ms對應的角度-90到+90度,範圍180度(3度左右偏差)。

1. 用Python的GPIO提供的PWM控制舵機。
# -*- coding: UTF-8 -*-
import RPi.GPIO as GPIO
import time
import atexit

class Steering:
    max_delay = 0.2
    min_delay = 0.04
 
    def __init__(self, channel, init_position, min_angle, max_angle, speed):
        self.channel = channel
        self.init_position = init_position
        self.position = init_position
        self.min_angle = min_angle
        self.max_angle = max_angle
        self.speed = speed
 
        atexit.register(GPIO.cleanup)
        GPIO.setmode(GPIO.BOARD)
        GPIO.setwarnings(False)
        GPIO.setup(self.channel, GPIO.OUT, initial=False)
 
        self.pwm = GPIO.PWM(self.channel, 50)  # PWM
        self.pwm.start(2.5 + 10 * self.position / 180)  # 讓舵機轉到初始位置
        time.sleep(Steering.max_delay)
        self.pwm.ChangeDutyCycle(0)
        time.sleep(Steering.min_delay)
2. 舵機要麼正轉、要麼反轉,再加上一個位置初始化,因此只需要在Steering類中定義三個方法。
3. 程式僅用於主程序的調用,無需編寫執行命令。
    def forwardRotation(self):
        print("current position 1: " + str(self.position))
        if (self.position + self.speed) <= self.max_angle:
            self.position = self.position + self.speed
            self.pwm.ChangeDutyCycle(2.5 + 10 * self.position / 180)  # 設置舵機角度
            time.sleep(Steering.min_delay)
            self.pwm.ChangeDutyCycle(0)  # 舵機回到中位
            time.sleep(Steering.min_delay)
        print("current position 2: " + str(self.position))
           
    def reverseRotation(self):
        print("current position 1: " + str(self.position))
        if (self.position - self.speed) >= self.min_angle:
            self.position = self.position - self.speed
            self.pwm.ChangeDutyCycle(2.5 + 10 * self.position / 180)  # 設置舵機角度
            time.sleep(Steering.min_delay)
            self.pwm.ChangeDutyCycle(0)  # 舵機回到中位
            time.sleep(Steering.min_delay)
        print("current position 2: " + str(self.position))
            
    def reset(self):
        print("current position 1: " + str(self.position))
        self.position = self.init_position
        self.pwm.start(2.5 + 10 * self.init_position / 180)  # 讓舵機轉到初始位置
        time.sleep(Steering.max_delay)
        self.pwm.ChangeDutyCycle(0)
        time.sleep(Steering.min_delay)
        print("current position 2: " + str(self.position))        

二、填寫配置文件(/config.ini)

我的垂直移動舵機GPIO口BOARD編碼爲7;左右移動舵機GPIO口BOARD編碼爲12

[camera]
# 控制攝像燈垂直移動的舵機
HIntfNum = 7
HInitPosition = 100     #略微擡升10度以符合通常拍攝角度
HMinPosition = 30       #設置邊界以防止攝像頭俯角過大與舵機碰撞摩擦減損壽命
HMaxPosition = 180
HSpeed = 5
 
# 控制攝像燈水平(左右)移動的舵機
VIntfNum = 12
VInitPosition = 120		#固定雲臺偏移角度還原後的初始角度
VMinPosition = 0
VMaxPosition = 180
VSpeed = 5

在這裏插入圖片描述


三、攝像頭主控制程式(/index.py)編寫思路
1. 定義一個Camera類,調用配置文件(/config.ini)數值放入舵機控制程式(/steering.py)中去。
# -*- coding: UTF-8 -*-
import sys
import RPi.GPIO as GPIO
import time
import sys
from steering import Steering
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.options
from tornado.options import define,options
import configparser
import RPi.GPIO as GPIO

class Camera:
	def __init__(self):

		config = configparser.ConfigParser()
		config.read("./config.ini")
		HIntfNum = config.getint("camera", "HIntfNum")
		HInitPosition = config.getint("camera", "HInitPosition")
		HMinPosition = config.getint("camera", "HMinPosition")
		HMaxPosition = config.getint("camera", "HMaxPosition")
		HSpeed = config.getint("camera", "HSpeed")

		VIntfNum = config.getint("camera", "VIntfNum")
		VInitPosition = config.getint("camera", "VInitPosition")
		VMinPosition = config.getint("camera", "VMinPosition")
		VMaxPosition = config.getint("camera", "VMaxPosition")
		VSpeed = config.getint("camera", "VSpeed")
 
		self.HCameraControl = Steering(HIntfNum, HInitPosition,
		 HMinPosition, HMaxPosition, HSpeed)
		
		self.VCameraControl = Steering(VIntfNum, VInitPosition,
		 VMinPosition, VMaxPosition, VSpeed)
2. 在Camera類中寫入向左 向右 向上 向下 復位五種情況下舵機移動的方法。(注意攝像頭左右移動的鏡面原理)
	def cameraRotate(self,direction):

		if direction == "A":
			self.HCameraControl.forwardRotation()

		elif direction == "D":
			self.HCameraControl.reverseRotation()

		elif direction == "W":
			self.VCameraControl.forwardRotation()

		elif direction == "S":
			self.VCameraControl.reverseRotation()

		elif direction == "Q":
			self.HCameraControl.reset()
			self.VCameraControl.reset()

		else:
			print("D, A, W, S or Q(reset)")
3. 由於工程最後會通過鍵盤(屏幕)按壓的方式爲direction賦值,因此這裏只需要爲程式寫上一個執行方法即可。
camera = Camera()
def run(dir):	
	camera.cameraRotate(dir)

注意:camera = Camera()一定要寫在run方法的外頭,不然舵機控制程式(/steering.py)會不停調用 self.position = init_position,致使舵機無法正常記錄 self.position(current position 2)。


當然了,做了這麼多,如果無法直觀的看到舵機的旋轉,相信大家會放心不下,這裏要感謝 weixin_42534940 博主給出的方法:採用input()給direction賦值的方式檢測程式,註釋上面的camera = Camera()後,創建一個程式執行入口:

if __name__ == "__main__":
    camera = Camera()
    while(True):
        direction = input("Please input direction: ")
        camera.cameraRotate(direction)

在這裏插入圖片描述
在回顯當前位置的同時,我們能看到攝像頭拍攝角度隨着舵機的轉向而轉向。檢測完成後記得及時刪除測試代碼以便工程的後續開展。


至此,我們基於python3成功控制兩自由度舵機,實現了攝像頭拍攝角度的遙控(源碼已上傳),下一章將和大家共同解決的主要問題是如何通過操控Web網頁的方式給direction賦值,實現網頁對攝像頭拍攝角度的操控,完成網絡攝像頭控制功能雛形。有任何疑問或者好的建議,歡迎留言評論!


後期內容提要:

  • 【樹莓派-網絡監控(4)】基於python異步io框架tornado,實現監控遙控命令與web網頁指定按鍵和鼠標(屏幕)點擊事件的綁定
  • 【樹莓派-網絡監控(5)】基於iframe標籤,集成監控實時畫面與遙控功能,製作並優化響應式控制頁面
  • 【樹莓派-網絡監控(完結)】基於內網穿透實現樹莓派監控的公網遠程訪問與遙控
  • 【樹莓派-網絡監控(補充)】基於AndroidStudio以及樹莓派監控及其遙控功能,開發一個簡單的允許公網訪問的監控app
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章