入门级基于Python的伺服电机控制应用程序

入门级Python应用程序---伺服电机控制

v信@宝德,百度@baode_w

前言

本文只适合像作者这样的入门级小白,大虾级别的请忽略。

由于作者水平有限,不当之处,欢迎批评指正。

本文所述应用程序只考虑功能实现,不考虑程序优化。

一、应用环境

系统环境:Window 10;

Python版本:3.7;

IDE:PyCharm;

界面设计:PYQT5;

电机:光毓机电RMD-S系列电机;

控制端口:RS-485,使用USB转485模块。

二、准备环境

软件安装及环境变量设置方法网上较多,请自行查阅,这里不再赘述。

双击打开PyCharm,新建一个New Project,注意添加项目的环境依赖venv。配置下Python3.7的依赖环境库venv library root,External Libraries—>Python 3.7(venv) —>venv library root—>pyvenv.cfg,将值改成“true”,如下图。

为PyCharm添加外部工具,FileàSettingsàToolsàExternal Toolsà “+”。

以PYQT5为例,单击“+”,弹出新建外部工具对话框,如下图所示。

对话框中Name是在IDE中的显示名字,可以自定义填写。Tool Settings需填写两项,Program项单击浏览Python3.7根目录“Python37\Lib\site-packages\pyqt5_tools\designer.exe”(当然,你得先安装有PYQT5,>_<),Working directory项填入“$ProjectFileDir$”,其他选项默认即可,单击“OK”保存。

其他外部工具如PYUIC、PYRCC等,添加过程类似。

三、编写程序

在项目中新建两个py文件,其中一个py文件(PTContrl.py)关联QT界面的信号(Signal)和槽(Slot),另外一个py文件(PTMainPRO.py)用来编写主程序,如此便于分离QT界面和逻辑程序,避免修改界面时对主程序存在干扰,当修改QT界面时,QT只会更新PTContrl.py,不会更新主程序。

主程序中需要包含PTContrl完成调用,以及主程序需要加载一些要用到的模块,如sys、serial、Qtimer等,如下图所示。

主程序功能包括,串口端口检测、波特率设置、打开端口,串口实时发送两个电机的角度值、速度值、转动方向,定时从串口接收两个电机编码器数据,并解码显示角度值。

主程序PTMainPRO.py完整代码如下:

import sys
import serial
import binascii
import serial.tools.list_ports
#from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication,QMainWindow,QFileDialog
from PyQt5.QtWidgets import QMessageBox
from time import sleep
import PTContrl
#import PDial
 #from ActiveMain import RulerProgress
#
主程序
class MainControl(QMainWindow,PTContrl.Ui_SFmotorcontrol):
   
def __init__(self):
        QMainWindow.
__init__(self)
        PTContrl.Ui_SFmotorcontrol.
__init__(self)
       
self.setupUi(self)
       
self.ser = serial.Serial()
       
self.data_num_sended = 0
       
self.engle1 = (self.dial_engle1.value()-18000)/100
       
self.engle2 = (self.dial_engle2.value() - 9000) / 100
       
self.speed1_H = 1#电机1速度高8位
       
self.speed1_L = 244  # 电机1速度,0x1F4,5dps
       
self.speed2_H = 1#电机2速度5dps高8位
       
self.speed2_L = 244  # 电机2速度5dps,低8位
       
self.engle1_zero = 0#水平电机零位0
       
self.engle2_zero = 0#垂直电机零位0

       
self.BaudSelect_box.addItem("115200")
       
self.BaudSelect_box.addItem("19200")
       
self.BaudSelect_box.addItem("57600")
       
self.BaudSelect_box.addItem("9600")
       
self.engle1_postvalue = 0
       
self.engle2_postvalue = 0
       
self.motor_dir = 0
       
self.motor_dir1 = 0
       
self.address1 = 1
       
self.address2 = 2
       
self.dir_left = 0
       
self.dir_right = 1
       
self.dir_up = 0
       
self.dir_down = 1
       
self.ask_flag = 0
       
self.auto_flag = 0
       
self.auto_stop = 0
       
self.motor_auto_act =0
       
self.timer1 = QTimer(self)
       
self.timer1_timeout = 250#timer1溢出时间250ms
        #for addr in range(1,33,1):
         #   self.AddrSelect1.addItem(str(addr))
          #  self.AddrSelect2.addItem(str(addr))

       
self.port_check()
       
self.Connect.clicked.connect(self.on_Connect)#按钮点击事件链接到自定义对象
        #self.dial_engle1.valueChanged.connect(self.engle1_change)#拨盘值改变事件链接到自定义对象
        #self.dial_engle2.valueChanged.connect(self.engle1_change)
        #self.dial_engle1.sliderMoved.connect(self.engle1_change)
        #self.port_check_button.setVisible(False)
       
self.port_check_button.clicked.connect(self.port_check)
       
#self.dial_engle1.sliderReleased.connect(self.data_send)
        #self.dial_engle2.sliderReleased.connect(self.data_send)
        #self.H_speed_Slider.valueChanged.connect(self.speed_change)
        #self.V_speed_Slider.valueChanged.connect(self.speed_change)
       
self.left_Button.pressed.connect(self.roll_send1)
       
self.right_Button.pressed.connect(self.roll_send2)
       
self.up_Button.pressed.connect(self.pitch_send1)
       
self.down_Button.pressed.connect(self.pitch_send2)
       
self.left_Button.released.connect(self.roll_stop)
       
self.right_Button.released.connect(self.roll_stop)
       
self.up_Button.released.connect(self.pitch_stop)
       
self.down_Button.released.connect(self.pitch_stop)
       
self.auto_Button1.clicked.connect(self.auto_send)
       
self.timer1.timeout.connect(self.ask_send)
       
self.Serialselect_box.activated.connect(self.port_check)
       
self.dial_engle1.setValue(18000)
       
#self.dial_engle1.setEnabled(True)
       
self.left_Button.setEnabled(False)
       
self.right_Button.setEnabled(False)
       
self.up_Button.setEnabled(False)
       
self.down_Button.setEnabled(False)
       
self.auto_Button1.setEnabled(False)

       
self.auto_Button1.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;")
       
self.left_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.right_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.up_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.down_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.dial_engle1.setStyleSheet("border-color:rgb(0,0,255);gridline-color:rgb(0,0,255);color: rgb(0,170,0);border-left-color: rgb(255, 0, 0);")
       
self.Connect.setStyleSheet(
           
"background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.port_check_button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
#self.SetupConnect.setStyleSheet("border:2px groove gray;border-radius:10px;")
        #self.dial_engle1.setStyleSheet("handle{background:blue;}")
    #border:0px solid transparent;
    #border-radius:2px;}  ")

        #while True:
#
在下面编写自己的子程序
    #端口打开或关闭
   
def on_Connect(self):

       
if self.ser.isOpen():
           
self.ser.close()
           
self.timer1.stop()
           
self.Connect.setText("连  接")
           
self.Connect.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font: 12pt;")
           
self.left_Button.setEnabled(False)
           
self.right_Button.setEnabled(False)
           
self.up_Button.setEnabled(False)
           
self.down_Button.setEnabled(False)
           
self.auto_Button1.setEnabled(False)
           
if self.auto_Button1.text() == "停止":
               
self.auto_send()
       
else:
           
self.ser.port = self.Serialselect_box.currentText()
           
self.ser.baudrate = int(self.BaudSelect_box.currentText())
           
self.ser.bytesize = 8
           
self.ser.stopbits = 1
           
self.ser.parity = "N"
           
self.ser.readable = True
           
self.ser.timeout = 2

           
try:
               
self.ser.open()
               
if self.ser.is_open:
                   
self.Connect.setText("断  开")
                   
self.Connect.setStyleSheet(
                       
"background-color:rgb(200,0,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font: 12pt;")
                   
self.timer1.start(self.timer1_timeout)#启动定时器
                   
self.left_Button.setEnabled(True)
                   
self.right_Button.setEnabled(True)
                   
self.up_Button.setEnabled(True)
                   
self.down_Button.setEnabled(True)
                   
self.auto_Button1.setEnabled(True)
                   
#self.thread_read.start()
           
except:
                QMessageBox.critical(
self, "Port Error", "此串口不能被打开!")
               
return None

       
#self.lineEdit_engle1.text = self.dial_engle1.value()
        #self.textEdit.setText(str(self.dial_engle1.value()/100))# =  #self.dial_engle1.value()
        #print(self.textEdit)

#水平转电机停止
   
def roll_stop(self):
       
self.left_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.right_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
        order_sum =
62 + 166 + 8 + self.address1
        order_sum =
int(hex(order_sum)[-2:], 16)
       
self.input_s = [62, 166, self.address1, 8, order_sum, 0, 60, 140, 0, 0, 0, 0, 0, 200# 发送位置359度,速度0dps,顺时针,停止命令
       
self.data_send()
       
#self.engle1_label.setText(str(self.dial_engle1.value()/100)+"度")
        #self.engle2_label.setText(str(self.dial_engle2.value() / 100) + "度")
#俯仰电机停止
   
def pitch_stop(self):
       
self.up_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
self.down_Button.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
        order_sum =
62 + 166 + 8 + self.address2
        order_sum =
int(hex(order_sum)[-2:], 16)
       
self.input_s = [62, 166, self.address2, 8, order_sum, 0, 40, 35, 0, 0, 0, 0, 0, 75# 发送位置90度,速度0dps,顺时针
       
self.data_send()
       
#self.lineEdit_speed1.setText(str(self.H_speed_Slider.value()/100)+"dps")
        #self.lineEdit_speed2.setText(str(self.V_speed_Slider.value() / 100)+"dps")
#
串口端口检测
   
def port_check(self):
        
# 检测所有存在的串口,将信息存储在字典中
       
self.Com_Dict = {}
        port_list =
list(serial.tools.list_ports.comports())
       
self.Serialselect_box.clear()
       
for port in port_list:
           
self.Com_Dict["%s" % port[0]] = "%s" % port[1]
           
self.Serialselect_box.addItem(port[0])
       
if len(self.Com_Dict) == 0:
           
self.statu_label.setText(" 无可用串口")
           
#self.statusbar.setText(" 检测无可用串口")

            # 发送数据

   
def data_send(self):

            
if self.ser.isOpen():

                
if self.input_s != "":
                    
# 非空字符串

                   
self.label_send.setText("发送:" + str(self.input_s))#print(send_list)
                   
input = bytes(self.input_s)
                    
#else:
                         # ascii
发送
                         #input_s = (input_s + '\r\n').encode('utf-8')

                   
num = self.ser.write(input)#发送数据
                   
self.data_num_sended += num
                   
#self.label_send.setText("发送:" + hex(input_s))
            
else:
                 QMessageBox.critical(
self, "Port Error", "串口未打开!")
                
pass


    def
auto_send(self):
       
if self.auto_flag == 0:
           
self.auto_flag = 1
           
self.auto_Button1.setText("停止")
           
self.auto_Button1.setStyleSheet("background-color:rgb(200,0,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
       
else:
           
self.auto_flag = 0
           
self.motor_auto_act = 0
           
self.auto_Button1.setText("自动")
           
self.auto_Button1.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
           
self.auto_stop = 1
           
pass

    def
ask_send(self):
       
if self.ser.isOpen():
            ask_list1 = [
0x3e,0x90,0x01,0x00,0xcf]
            ask_list2 = [
0x3e,0x90,0x02,0x00,0xd0]
           
if self.ask_flag:
               
self.ser.write(ask_list1)
               
self.ask_flag = 0
           
else:
               
self.ser.write(ask_list2)
               
self.ask_flag = 1
       
#else:
           
sleep(0.02)#线程挂起0.05秒
           
rec_data = ""
           
#rec_hex = ""
           
n = self.ser.inWaiting()
           
if n :
                rec_data =
str(binascii.b2a_hex(self.ser.read(n)))[2:-1]
           
#for rec_list in rec_hex:
            #    rec_data = rec_data + str(rec_list) #= rec_data + str(self.ser.readline())
                #print(rec_data)
           
if len(rec_data) > 15:
               
#print(rec_data)
                #print(len(rec_data))
               
self.label_send.setText("接收:" + rec_data + ",长度:" + str(len(rec_data)))  # print(send_list)
                #rec_data = rec_data[0:8]
                #head = rec_data[:2]
                #order = rec_data[3:4]
               
addr = int((rec_data[5:6]),16)
                engle_data1 = rec_data[
10:12]
                engle_data2 = rec_data[
12:14]
                engle_data =
int((engle_data2 + engle_data1),16)
               
#engle_data = engle_data[::-1]#倒置
                #engle_sum = engle_data[1] * 0x100 + engle_data[2]
                #engle_sum = int(str(engle_sum),16)

               
if addr == self.address1:#电机1返回数据
                   
engle_data = (engle_data - self.engle1_zero) * 36000 // 4096#精度360/4096,*100
                   
self.engle1_postvalue = engle_data
                   
self.engle1_label.setText(str('%.1f'%(engle_data/100)))#保留1位小数点
                   
engle_data = engle_data + 18000

                   
if engle_data > 36000:
                        engle_data = engle_data -
36000
                   
self.dial_engle1.setValue(engle_data)
               
if addr == self.address2:#电机2返回数据
                   
engle_data = (engle_data - self.engle2_zero) * 36000 // 4096  # 精度360/4096,*100
                   
self.engle2_postvalue = engle_data
                   
if engle_data > 10000:
                       
self.engle2_label.setText("-" + str('%.1f' % ((36000-engle_data )/ 100)))  # 保留1位小数点
                   
else:
                       
self.engle2_label.setText(str('%.1f' % (engle_data / 100)))  # 保留1位小数点
                   
engle_data = engle_data + 9000
                   
#self.engle2_label.setText(str('%.1f'%(engle_data/100)))#保留1位小数点
                   
self.dial_engle2.setValue(engle_data)

               
if self.auto_flag:
                   
if self.motor_auto_act ==1:#自动翻转
                       
if self.engle1_postvalue > 35500:
                           
self.roll_send1()#send 0deg
                           
self.motor_auto_act = 1
                       
if self.engle1_postvalue < 400:
                           
self.roll_send2()#send 359 deg
                           
self.motor_auto_act = 1
                   
else:#初次自动运行
                       
if self.engle1_postvalue > 18000 or self.engle1_postvalue == 18000 :
                           
self.roll_send2()#send 359 deg
                           
self.motor_auto_act = 1
                       
if self.engle1_postvalue < 18000:
                           
self.roll_send1()#send 0deg
                           
self.data_send()
                           
self.motor_auto_act = 1
               
#自动停止
               
if self.auto_stop == 1:
                   
self.auto_stop = 0
                   
self.roll_stop()#send auto stop




                #print(rec_data)
            #QMessageBox.critical(self, "Port Error", "
串口未打开!")
           # pass

#手动与自动之间的切换?手动点击时停止自动


#水平电机顺时针转动
    def roll_send1(self):
       
if self.left_Button.isDown() and self.auto_flag ==1:
           
self.auto_send()
       
if self.auto_flag ==0:
           
self.left_Button.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")

        order_sum =
62 + 166 + 8 + self.address1
        order_sum =
int(hex(order_sum)[-2:], 16)
        data_sum =
int(hex(1 + self.speed1_H + self.speed1_L)[-2:] ,16)
       
self.input_s = [62,166,self.address1,8,order_sum,1,0,0,0,self.speed1_L,self.speed1_H,0,0,data_sum]#发送位置0度,速度2dps,顺时针
        #input_s = bytes(input_s)
        #self.ser.write(input_s)
       
self.data_send()

 

#水平电机逆时针转动
   
def roll_send2(self):
       
if self.right_Button.isDown() and self.auto_flag ==1:
           
self.auto_send()
       
if self.auto_flag == 0:
           
self.right_Button.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")

        order_sum =
62 + 166 + 8 + self.address1
        order_sum =
int(hex(order_sum)[-2:], 16)
        data_sum =
int(hex(60+140 + self.speed1_H + self.speed1_L)[-2:], 16)
       
self.input_s = [62,166,self.address1,8,order_sum,0,60,140,0,self.speed1_L,self.speed1_H,0,0,data_sum]#发送位置359度,速度2dps,逆时针
        #input_s = bytes(input_s)
        #self.ser.write(input_s)
       
self.data_send()

 

#俯仰电机顺时针转动
   
def pitch_send1(self):
       
self.up_Button.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
        order_sum =
62 + 166 + 8 + self.address2
        order_sum =
int(hex(order_sum)[-2:], 16)
        data_sum =
int(hex(40 + 35 + self.speed2_H + self.speed2_L)[-2:], 16)
       
self.input_s = [62,166,self.address2,8,order_sum,0,40,35,0,self.speed2_L,self.speed2_H,0,0,data_sum]#发送位置90度,速度2dps,顺时针
        #input_s = bytes(input_s)
        #self.ser.write(input_s)
       
self.data_send()

 

#俯仰电机逆时针转动
   
def pitch_send2(self):
       
self.down_Button.setStyleSheet("background-color:rgb(0,200,0);border:2px groove gray;border-radius:10px;padding:2px 4px;font:12pt;")
        order_sum =
62 + 166 + 8 + self.address2
        order_sum =
int(hex(order_sum)[-2:], 16)
        data_sum =
int(hex(1+120 + 105 + self.speed2_H + self.speed2_L)[-2:], 16)
       
self.input_s = [62,166,self.address2,8,order_sum,1,120,105,0,self.speed2_L,self.speed2_H,0,0,data_sum]#发送位置270度,速度2dps,逆时针
        #input_s = bytes(input_s)
        #self.ser.write(input_s)
       
self.data_send()
#
程序启动关联
if __name__ == "__main__":
    app=QApplication(sys.argv) 
# 创建一个QApplication,也就是你要开发的软件app
    #MainWindow = QtWidgets.QMainWindow()    # 创建一个QMainWindow,用来装载你需要的各种组件、控件
   
ui = MainControl()                    # ui是Ui_SFmotorcontrol类的实例化对象
   #ui.setupUi(MainWindow)                  # 执行类中的setupUi方法,方法的参数是第二步中创建的QMainWindow
   
ui.show()                       # 执行QMainWindow的show()方法,显示这个QMainWindow
   
sys.exit(app.exec_())                   # 使用exit()或者点击关闭按钮退出QApplication

四、设计QT界面

在PyCharm软件中启动外部工具PYQT5,Tools—>External Tools—>QT5,如下图所示。

启动PYQT5的设计界面,进入创建对话框,如下图,创建一个新的Main Window。

修改Main Window的对象名称ObjectName为“SFmotorcontrol”(也可以自己定义),但要记住,在关联py文件里面要用到。QT设计界面左侧有许多控件,将需要的控件直接往建好的空白Main Window里拖,简单排布一下,统一修改好记的对象名称,具体设计方法自行参阅QT使用方法,设计好的界面如下图所示。

编辑好后保存成ui文件(PTContrl.ui),并添加到PyCharm项目中,使用PyCharm的外部工具PYUIC将做好的ui文件转换成py文件(就是前文所说的界面关联py文件),得到PTContrl.py,完整的PTContrl.py代码如下。

QT界面关联py文件PTContrl.py完整代码:

# -*- coding: utf-8 -*-



# Form implementation generated from reading ui file 'PTContrl.ui'

#

# Created by: PyQt5 UI code generator 5.11.3

#

# WARNING! All changes made in this file will be lost!



from PyQt5 import QtCore, QtGui, QtWidgets



class Ui_SFmotorcontrol(object):

    def setupUi(self, SFmotorcontrol):

        SFmotorcontrol.setObjectName("SFmotorcontrol")

        SFmotorcontrol.resize(640, 580)

        SFmotorcontrol.setMinimumSize(QtCore.QSize(640, 580))

        SFmotorcontrol.setMaximumSize(QtCore.QSize(640, 580))

        font = QtGui.QFont()

        font.setFamily("宋体")

        font.setPointSize(12)

        SFmotorcontrol.setFont(font)

        icon = QtGui.QIcon()

        icon.addPixmap(QtGui.QPixmap("LOGO.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)

        SFmotorcontrol.setWindowIcon(icon)

        self.centralwidget = QtWidgets.QWidget(SFmotorcontrol)

        self.centralwidget.setObjectName("centralwidget")

        self.SetupConnect = QtWidgets.QGroupBox(self.centralwidget)

        self.SetupConnect.setGeometry(QtCore.QRect(10, 410, 621, 131))

        self.SetupConnect.setFlat(False)

        self.SetupConnect.setCheckable(False)

        self.SetupConnect.setObjectName("SetupConnect")

        self.Connect = QtWidgets.QPushButton(self.SetupConnect)

        self.Connect.setGeometry(QtCore.QRect(500, 50, 111, 41))

        self.Connect.setObjectName("Connect")

        self.Serialselect_box = QtWidgets.QComboBox(self.SetupConnect)

        self.Serialselect_box.setGeometry(QtCore.QRect(70, 60, 69, 22))

        self.Serialselect_box.setEditable(True)

        self.Serialselect_box.setCurrentText("")

        self.Serialselect_box.setObjectName("Serialselect_box")

        self.BaudSelect_box = QtWidgets.QComboBox(self.SetupConnect)

        self.BaudSelect_box.setGeometry(QtCore.QRect(350, 60, 71, 22))

        self.BaudSelect_box.setEditable(True)

        self.BaudSelect_box.setObjectName("BaudSelect_box")

        self.label = QtWidgets.QLabel(self.SetupConnect)

        self.label.setGeometry(QtCore.QRect(20, 60, 54, 21))

        self.label.setObjectName("label")

        self.label_3 = QtWidgets.QLabel(self.SetupConnect)

        self.label_3.setGeometry(QtCore.QRect(280, 55, 71, 31))

        self.label_3.setObjectName("label_3")

        self.port_check_button = QtWidgets.QPushButton(self.SetupConnect)

        self.port_check_button.setGeometry(QtCore.QRect(150, 50, 81, 41))

        self.port_check_button.setObjectName("port_check_button")

        self.label_send = QtWidgets.QLabel(self.SetupConnect)

        self.label_send.setGeometry(QtCore.QRect(20, 100, 571, 21))

        self.label_send.setText("")

        self.label_send.setObjectName("label_send")

        self.dial_engle1 = QtWidgets.QDial(self.centralwidget)

        self.dial_engle1.setEnabled(False)

        self.dial_engle1.setGeometry(QtCore.QRect(50, 36, 181, 181))

        self.dial_engle1.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

        self.dial_engle1.setStyleSheet("border-color: rgb(0, 0, 255);\n"

"gridline-color: rgb(0, 0, 255);\n"

"color: rgb(0, 170, 0);")

        self.dial_engle1.setMaximum(36000)

        self.dial_engle1.setPageStep(100)

        self.dial_engle1.setProperty("value", 18000)

        self.dial_engle1.setSliderPosition(18000)

        self.dial_engle1.setTracking(True)

        self.dial_engle1.setWrapping(True)

        self.dial_engle1.setNotchTarget(10.0)

        self.dial_engle1.setNotchesVisible(True)

        self.dial_engle1.setObjectName("dial_engle1")

        self.dial_engle2 = QtWidgets.QDial(self.centralwidget)

        self.dial_engle2.setEnabled(False)

        self.dial_engle2.setGeometry(QtCore.QRect(380, 36, 181, 181))

        self.dial_engle2.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

        self.dial_engle2.setMinimum(0)

        self.dial_engle2.setMaximum(36000)

        self.dial_engle2.setSingleStep(1)

        self.dial_engle2.setPageStep(100)

        self.dial_engle2.setProperty("value", 9000)

        self.dial_engle2.setSliderPosition(9000)

        self.dial_engle2.setTracking(True)

        self.dial_engle2.setOrientation(QtCore.Qt.Vertical)

        self.dial_engle2.setInvertedAppearance(False)

        self.dial_engle2.setInvertedControls(True)

        self.dial_engle2.setWrapping(True)

        self.dial_engle2.setNotchTarget(10.0)

        self.dial_engle2.setNotchesVisible(True)

        self.dial_engle2.setObjectName("dial_engle2")

        self.label_4 = QtWidgets.QLabel(self.centralwidget)

        self.label_4.setGeometry(QtCore.QRect(40, 320, 91, 31))

        font = QtGui.QFont()

        font.setPointSize(16)

        font.setBold(True)

        font.setWeight(75)

        self.label_4.setFont(font)

        self.label_4.setObjectName("label_4")

        self.label_5 = QtWidgets.QLabel(self.centralwidget)

        self.label_5.setGeometry(QtCore.QRect(480, 320, 91, 31))

        font = QtGui.QFont()

        font.setPointSize(16)

        font.setBold(True)

        font.setWeight(75)

        self.label_5.setFont(font)

        self.label_5.setObjectName("label_5")

        self.label_9 = QtWidgets.QLabel(self.centralwidget)

        self.label_9.setGeometry(QtCore.QRect(129, 225, 54, 12))

        self.label_9.setObjectName("label_9")

        self.label_10 = QtWidgets.QLabel(self.centralwidget)

        self.label_10.setGeometry(QtCore.QRect(463, 15, 54, 12))

        self.label_10.setObjectName("label_10")

        self.label_11 = QtWidgets.QLabel(self.centralwidget)

        self.label_11.setGeometry(QtCore.QRect(235, 120, 54, 12))

        self.label_11.setObjectName("label_11")

        self.label_12 = QtWidgets.QLabel(self.centralwidget)

        self.label_12.setGeometry(QtCore.QRect(360, 120, 54, 12))

        self.label_12.setTextFormat(QtCore.Qt.AutoText)

        self.label_12.setObjectName("label_12")

        self.label_13 = QtWidgets.QLabel(self.centralwidget)

        self.label_13.setGeometry(QtCore.QRect(136, 14, 54, 12))

        self.label_13.setObjectName("label_13")

        self.label_14 = QtWidgets.QLabel(self.centralwidget)

        self.label_14.setGeometry(QtCore.QRect(454, 222, 54, 12))

        self.label_14.setObjectName("label_14")

        self.label_15 = QtWidgets.QLabel(self.centralwidget)

        self.label_15.setGeometry(QtCore.QRect(20, 120, 54, 12))

        self.label_15.setObjectName("label_15")

        self.statu_label = QtWidgets.QLabel(self.centralwidget)

        self.statu_label.setGeometry(QtCore.QRect(20, 511, 131, 21))

        self.statu_label.setText("")

        self.statu_label.setObjectName("statu_label")

        self.engle1_label = QtWidgets.QLabel(self.centralwidget)

        self.engle1_label.setGeometry(QtCore.QRect(105, 110, 71, 31))

        font = QtGui.QFont()

        font.setFamily("Times New Roman")

        font.setPointSize(16)

        font.setBold(True)

        font.setWeight(75)

        self.engle1_label.setFont(font)

        self.engle1_label.setAlignment(QtCore.Qt.AlignCenter)

        self.engle1_label.setObjectName("engle1_label")

        self.auto_Button1 = QtWidgets.QPushButton(self.centralwidget)

        self.auto_Button1.setGeometry(QtCore.QRect(280, 270, 50, 50))

        font = QtGui.QFont()

        font.setPointSize(12)

        self.auto_Button1.setFont(font)

        self.auto_Button1.setObjectName("auto_Button1")

        self.engle2_label = QtWidgets.QLabel(self.centralwidget)

        self.engle2_label.setGeometry(QtCore.QRect(436, 113, 71, 31))

        font = QtGui.QFont()

        font.setFamily("Times New Roman")

        font.setPointSize(16)

        font.setBold(True)

        font.setWeight(75)

        self.engle2_label.setFont(font)

        self.engle2_label.setAlignment(QtCore.Qt.AlignCenter)

        self.engle2_label.setObjectName("engle2_label")

        self.widget = QtWidgets.QWidget(self.centralwidget)

        self.widget.setGeometry(QtCore.QRect(474, 30, 120, 191))

        self.widget.setToolTip("")

        self.widget.setStatusTip("")

        self.widget.setAutoFillBackground(True)

        self.widget.setObjectName("widget")

        self.up_Button = QtWidgets.QPushButton(self.centralwidget)

        self.up_Button.setGeometry(QtCore.QRect(280, 210, 50, 50))

        self.up_Button.setObjectName("up_Button")

        self.right_Button = QtWidgets.QPushButton(self.centralwidget)

        self.right_Button.setGeometry(QtCore.QRect(340, 270, 50, 50))

        self.right_Button.setObjectName("right_Button")

        self.left_Button = QtWidgets.QPushButton(self.centralwidget)

        self.left_Button.setGeometry(QtCore.QRect(220, 270, 50, 50))

        self.left_Button.setObjectName("left_Button")

        self.down_Button = QtWidgets.QPushButton(self.centralwidget)

        self.down_Button.setGeometry(QtCore.QRect(280, 330, 50, 50))

        self.down_Button.setObjectName("down_Button")

        self.SetupConnect.raise_()

        self.dial_engle1.raise_()

        self.dial_engle2.raise_()

        self.label_4.raise_()

        self.label_5.raise_()

        self.label_9.raise_()

        self.label_10.raise_()

        self.label_11.raise_()

        self.label_12.raise_()

        self.label_13.raise_()

        self.label_15.raise_()

        self.statu_label.raise_()

        self.engle1_label.raise_()

        self.auto_Button1.raise_()

        self.widget.raise_()

        self.label_14.raise_()

        self.engle2_label.raise_()

        self.up_Button.raise_()

        self.right_Button.raise_()

        self.left_Button.raise_()

        self.down_Button.raise_()

        SFmotorcontrol.setCentralWidget(self.centralwidget)

        self.menubar = QtWidgets.QMenuBar(SFmotorcontrol)

        self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 23))

        self.menubar.setObjectName("menubar")

        SFmotorcontrol.setMenuBar(self.menubar)

        self.statusbar = QtWidgets.QStatusBar(SFmotorcontrol)

        self.statusbar.setObjectName("statusbar")

        SFmotorcontrol.setStatusBar(self.statusbar)



        self.retranslateUi(SFmotorcontrol)

        QtCore.QMetaObject.connectSlotsByName(SFmotorcontrol)



    def retranslateUi(self, SFmotorcontrol):

        _translate = QtCore.QCoreApplication.translate

        SFmotorcontrol.setWindowTitle(_translate("SFmotorcontrol", "云台控制软件"))

        self.SetupConnect.setTitle(_translate("SFmotorcontrol", "连接设置"))

        self.Connect.setText(_translate("SFmotorcontrol", "连   接"))

        self.BaudSelect_box.setCurrentText(_translate("SFmotorcontrol", "115200"))

        self.label.setText(_translate("SFmotorcontrol", "串口:"))

        self.label_3.setText(_translate("SFmotorcontrol", "波特率:"))

        self.port_check_button.setText(_translate("SFmotorcontrol", "串口检测"))

        self.dial_engle1.setToolTip(_translate("SFmotorcontrol", "<html><head/><body><p><span style=\" font-size:10pt;\">使用鼠标拖动</span></p></body></html>"))

        self.label_4.setText(_translate("SFmotorcontrol", "水平旋转"))

        self.label_5.setText(_translate("SFmotorcontrol", "垂直俯仰"))

        self.label_9.setText(_translate("SFmotorcontrol", "180"))

        self.label_10.setText(_translate("SFmotorcontrol", "90"))

        self.label_11.setText(_translate("SFmotorcontrol", "90"))

        self.label_12.setText(_translate("SFmotorcontrol", "0"))

        self.label_13.setText(_translate("SFmotorcontrol", "0"))

        self.label_14.setText(_translate("SFmotorcontrol", "-90"))

        self.label_15.setText(_translate("SFmotorcontrol", "270"))

        self.engle1_label.setText(_translate("SFmotorcontrol", "0.0"))

        self.auto_Button1.setText(_translate("SFmotorcontrol", "自动"))

        self.engle2_label.setText(_translate("SFmotorcontrol", "0.0"))

        self.up_Button.setText(_translate("SFmotorcontrol", "上"))

        self.right_Button.setText(_translate("SFmotorcontrol", "右"))

        self.left_Button.setText(_translate("SFmotorcontrol", "左"))

        self.down_Button.setText(_translate("SFmotorcontrol", "下"))

在PyCharm中运行主程序,点击“RUN”—>RUN‘PTMainPRO’,无错则显示设计好的界面,如下图所示,按钮在程序中做了些美化,形状和颜色和前文所述的有所不同。

五、应用程序打包

程序编好后,最后一步当然是打包成可执行的exe文件啦,如此才能摆脱程序对IDE环境的依赖,能够在其他电脑上运行。在这里,我们使用pyinstaller来进行程序打包,当然还有其他方法来完成这件事情,感兴趣的可以自行尝试一哈。

首先,需要安装pyinstaller,懒人可在cmd中pip安装,输入“pip install pyinstaller”回车,然后等待即可。

在执行pyinstaller之前,需要确认所有关于应用程序所需的资源(包含图片以及依赖的.py文件都放进dist下的项目目录中),否则会打包不成功。

为确保打包成功,项目路径中最好不要出现中文(大虾指导的,具体为什么,额,不清楚,包括前文所述的环境搭建时也有这个坑,爬过的才知道)。

管理员运行cmd,cd到项目路径下,执行“pyinstaller PTMainPRO.py”回车,执行结果如下图。

如此表明打包成功,来到我们的项目目录下,会发现在dist文件夹下多了一个文件夹PTMainPRO,这就是我们的应用程序所有需要的文件,当然包括可执行文件,如下图所示。

当然,也可以打包成只有一个exe文件,有兴趣的朋友可以深入研究下pyinstaller的执行参数。

至此,一个简单的基于Python+QT的PC应用程序就完成了,感谢大家的耐心阅读,若有不当之处,请批评指正。

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值