今天我们在树莓派上面运行一个PyQt5的程序,可以通过GPIO口进行舵机转动,可以在Qt界面中操作。
我手里的舵机主要有SG90和MG995这两种,后者主要是组成的二度云台来使用,驱动方式基本都一样所以,所以今天就以SG90舵机的驱动为例。
一、软件编码
1、使用PyQt5设计界面
使用QtDesigner设计一个UI界面,保存为HomePage.ui文件,可以自行设计,主要目的是通过点击软件按钮,达到舵机旋转的目的,如下图:
2、将HomePage.ui文件转换为ui_HomePage.py,使用pyuic5命令或者在PyCharm中直接转换:
pyuic5 -o ui_HomePage.py HomePage.ui
或
这样我们就创建了一个UI界面,目录结构如下:
显示效果如下:
3、编写舵机驱动模块SteeringSG90Module.py
我在这里将驱动模块都放在了DeviceDriver目录下,大家可以根据自己的习惯设计目录结构,只要import的时候包含路径正确就行。
SteeringSG90Module.py文件的内容如下:
#!/usr/bin/env python
"""
SG90舵机控制驱动
"""
import platform
if (platform.system()=='Windows'):
pass
else:
import RPi.GPIO as GPIO
import time
from PyQt5.QtCore import *
global currDir
currDir = 'stop'
class SteeringSG90Worker(QObject):
'SG90舵机工作线程'
def __init__(self):
super(SteeringSG90Worker,self).__init__()
self.gpioFlag = False
self.working = True
self.angle = 0
def __del__(self):
'线程停止'
self.working = False
def setGPIO(self,servopin):
self.ServoPin = servopin
self.gpioFlag = True
def initCheckSelf(self):
'初始化自检'
for i in range(0, 181, 10):
self.p.ChangeDutyCycle(2.5 + 10 * i / 180)
time.sleep(0.02)
self.p.ChangeDutyCycle(0)
time.sleep(0.2)
for i in range(181, 0, -10):
self.p.ChangeDutyCycle(2.5 + 10 * i / 180)
time.sleep(0.02)
self.p.ChangeDutyCycle(0)
time.sleep(0.2)
#自检完毕
self.angle = 0
self.gpioFlag = True
def turnLeft(self):
self.angle += 5
if self.angle >= 180:
# self.angle = 180
return
if (platform.system() == 'Windows'):
pass
else:
self.p.ChangeDutyCycle(2.5 + 10 * self.angle / 180)
time.sleep(0.02)
self.p.ChangeDutyCycle(0)
time.sleep(0.2)
global currDir
currDir = 'stop'
def turnRight(self):
self.angle -= 5
if self.angle <= 0:
return
if (platform.system() == 'Windows'):
pass
else:
self.p.ChangeDutyCycle(2.5 + 10 * self.angle / 180)
time.sleep(0.02)
self.p.ChangeDutyCycle(0)
time.sleep(0.2)
global currDir
currDir = 'stop'
def checkDirection(self):
global currDir
if currDir == 'stop':
pass
elif currDir == 'left':
self.turnLeft()
elif currDir == 'right':
self.turnRight()
def doWork(self):
print('running steeringSG90 ...')
if self.gpioFlag == False:
print('Plase set GPIO by setGPIO()')
return
if (platform.system() == 'Windows'):
pass
else:
self.p = GPIO.PWM(self.ServoPin, 50) # 50HZ
self.p.start(0)
self.gpioFlag = False
self.initCheckSelf()
while self.working == True:
# print('...')
self.checkDirection()
time.sleep(0.2)
class SteeringSG90Manager(QObject):
'SG90舵机管理器'
operate = pyqtSignal()
def __init__(self):
super().__init__()
self.setup()
self.worker = SteeringSG90Worker()
self.thread = QThread()
self.worker.moveToThread(self.thread)
self.worker.setGPIO(self.servopin)
self.thread.finished.connect(self.worker.deleteLater)
self.operate.connect(self.worker.doWork)
self.thread.start()
self.operate.emit()
def __del__(self):
self.thread.quit()
self.thread.wait()
def setup(self):
'Init device gpio.'
self.servopin = 21
if (platform.system() == 'Windows'):
pass
else:
GPIO.setup(self.servopin, GPIO.OUT) # ,initial=False
def controlCommand(self,cmd):
global currDir
if cmd == 'left':
currDir = 'left'
elif cmd == 'right':
currDir = 'right'
注意,由于我软件编写测试是在Windows平台下PyCharm软件,当测试软件结构性的时候,为方便测试,使用“platform.system()”判断当前运行环境的系统平台。
4、编写界面分离文件CallHomePage.py,内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from ui_HomePage import Ui_HomePage
from DeviceDriver.UltrasonicModule import UltrasonicManager
from DeviceDriver.SteeringSG90Module import SteeringSG90Manager
from PyQt5.QtCore import pyqtSignal,Qt
import platform
if (platform.system()=='Windows'):
pass
else:
import RPi.GPIO as GPIO
class HomePage(QWidget,Ui_HomePage):
strSG90 = pyqtSignal(str) #只有水平方向
def __init__(self,parent=None):
super(HomePage, self).__init__(parent)
self.setupUi(self)
self.initUI()
self.initDevice()
def __del__(self):
if (platform.system() == 'Windows'):
pass
else:
GPIO.cleanup()
def initUI(self):
'iniitUI'
self.resize(800,480)
#省略部分界面布局的代码,以下就是绑定舵机左右旋转的两个按钮
self.leftButton_2.clicked.connect(self.buttonSlot)
self.rightButton_2.clicked.connect(self.buttonSlot)
def initDevice(self):
if (platform.system() == 'Windows'):
pass
else:
GPIO.setmode(GPIO.BCM)
# 初始化SG90舵机
self.steeringSG90 = SteeringSG90Manager()
self.strSG90.connect(self.steeringSG90.controlCommand)
def buttonSlot(self):
'按钮点击分发处理函数'
sender = self.sender()
if sender == self.leftButton_2:
self.strSG90.emit('left')#超声波舵机左转
elif sender == self.rightButton_2:
self.strSG90.emit('right')#超声波舵机右转
注意:由于控制舵机时使用的GPIO模式是GPIO.BCM模式,树莓派中的同一个应用程序同时只能使用一种GPIO模式,所以所有驱动都使用的BCM模式。
树莓派管脚的命令如下:
5、编写main程序入口,我在这里新建了一个main_server.py文件,内容如下:
from PyQt5.QtWidgets import *
from CallHomePage import HomePage
import sys
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = HomePage()
mainWindow.show()
sys.exit(app.exec_())
二、连接测试
实际连接状态如下图:
1、将以上代码传到树莓派中,最好目录结构保持一致
使用python3命令运行我们的main入口,这样我们就可通过点击界面的按钮来控制舵机的转动了。
使用舵机控制超声波模块https://www.zhihu.com/video/1193917543478280192
注意:本人树莓派使用的系统是厂家提供的Raspbian系统,里面已经装好了PyQt5的环境了。