首页 > Python资料 博客日记
入门级基于Python的伺服电机控制应用程序
2024-08-04 09:00:07Python资料围观51次
入门级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应用程序就完成了,感谢大家的耐心阅读,若有不当之处,请批评指正。
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj