From f92b62a5354dcfe189a31d76d4004006354bf16b Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Tue, 2 Jun 2015 21:55:09 +0200 Subject: [PATCH] qtosd: port in pyqt5 --- qtosd/qtosd.py | 143 ++++++++++++++++----------------------------- qtosd/qtosd.ui | 3 - qtosd/qtosd_ui.py | 66 +++++++++++++++++++++ qtosd/serialfpv.py | 5 +- 4 files changed, 119 insertions(+), 98 deletions(-) create mode 100644 qtosd/qtosd_ui.py diff --git a/qtosd/qtosd.py b/qtosd/qtosd.py index dd2a6ee..37bbfcb 100644 --- a/qtosd/qtosd.py +++ b/qtosd/qtosd.py @@ -21,9 +21,13 @@ # http://pytricity.com/qt-artificial-horizon-custom-widget/ import math -from PyQt4 import QtCore, QtGui +import argparse + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtCore import pyqtSlot import serialfpv +import qtosd_ui try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -32,18 +36,19 @@ except AttributeError: return s try: - _encoding = QtGui.QApplication.UnicodeUTF8 + _encoding = QtWidgets.QApplication.UnicodeUTF8 def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig, _encoding) + return QtWidgets.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig) + return QtWidgets.QApplication.translate(context, text, disambig) -class OSDWidget(QtGui.QWidget): - def __init__(self, roundWidget = False): +class OSDWidget(QtWidgets.QWidget): + def __init__(self, roundWidget = False, filename = None): super(OSDWidget, self).__init__() # init parameters self.roundWidget = roundWidget + self.fpv = None # parameters that will be modified by the user self.user_pitch = 0 self.user_roll = 0 @@ -111,11 +116,16 @@ class OSDWidget(QtGui.QWidget): self.ALT_REFLINES_NUM_LINES) self.ALT_REFLINES_SIZE_FACTOR = 0.7 + if filename: + self.fpv = serialfpv.SerialFPV() + self.fpv.open_file(filename) + self.FPS = 50. self.timer = QtCore.QTimer(self) - self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.frameTimerCb) + self.timer.timeout.connect(self.frameTimerCb) self.timer.start(1000. / self.FPS) + @pyqtSlot(name = "paintEvent") def paintEvent(self, evt): """Paint callback, this is the entry point for all drawings.""" painter = QtGui.QPainter() @@ -129,11 +139,15 @@ class OSDWidget(QtGui.QWidget): self.draw(painter) painter.end() + @pyqtSlot(name = "frameTimerCb") def frameTimerCb(self): - """called periodically, every frame, it calls the user_frame_cb function, - updates the filter and updates the widget""" - if self.user_frame_cb != None: - self.user_frame_cb() + # read from SerialFPV object + if self.fpv: + self.fpv.update_state() + self.user_speed = self.user_speed + 1 + self.setRoll(self.fpv.roll) + self.setPitch(self.fpv.pitch) + self.setYaw(self.fpv.yaw) # avoid filter bugs when changing between 180 and -180 self.pitch += round((self.user_pitch - self.pitch) / 360.) * 360 @@ -327,6 +341,7 @@ class OSDWidget(QtGui.QWidget): sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val) lefttxt = QtCore.QRect(QtCore.QPoint(0, 0), sz) lefttxt.moveCenter(pt1 - QtCore.QPoint(0.2 * r, 0)) + # XXX #pen.setWidth(1); #brush = QtGui.QBrush(QtCore.Qt.white) #painter.setBrush(brush) @@ -645,105 +660,49 @@ class OSDWidget(QtGui.QWidget): """set the left text""" self.right_txt = txt - def setFrameCb(self, user_frame_cb): - """set a function that is called every frame, before updating the widget""" - self.user_frame_cb = user_frame_cb +class Ui_MainWindow(QtWidgets.QMainWindow): + def __init__(self, parent = None, roundWidget = False, filename = None): + super(Ui_MainWindow, self).__init__(parent) + self.ui = qtosd_ui.Ui_MainWindow() + self.ui.setupUi(self) -class Ui_MainWindow(object): - def __init__(self, filename = None, roundWidget = False): self.roundWidget = roundWidget self.filename = filename - def update_fpv_info(self): - self.fpv.update() - self.osd.user_speed = self.osd.user_speed + 1 - self.osd.setRoll(self.fpv.roll) - self.osd.setPitch(self.fpv.pitch) - self.osd.setYaw(self.fpv.yaw) - - def setupUi(self, MainWindow): - MainWindow.setObjectName(_fromUtf8("MainWindow")) - MainWindow.resize(400, 300) - self.centralWidget = QtGui.QWidget(MainWindow) - self.centralWidget.setObjectName(_fromUtf8("centralWidget")) - self.gridLayout = QtGui.QGridLayout(self.centralWidget) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - - self.pitchSlider = QtGui.QSlider(self.centralWidget) - self.pitchSlider.setMinimum(-180) - self.pitchSlider.setMaximum(180) - self.pitchSlider.setOrientation(QtCore.Qt.Vertical) - self.pitchSlider.setObjectName(_fromUtf8("pitchSlider")) - self.pitchSlider.valueChanged[int].connect(self.changePitch) - self.gridLayout.addWidget(self.pitchSlider, 0, 0) - - self.osd = OSDWidget(self.roundWidget) - if self.filename: - self.fpv = serialfpv.SerialFPV() - self.fpv.open_file(self.filename) - self.osd.setFrameCb(self.update_fpv_info) - self.gridLayout.addWidget(self.osd, 0, 1) - - self.rollSlider = QtGui.QSlider(self.centralWidget) - self.rollSlider.setMinimum(-180) - self.rollSlider.setMaximum(180) - self.rollSlider.setOrientation(QtCore.Qt.Horizontal) - self.rollSlider.setObjectName(_fromUtf8("rollSlider")) - self.rollSlider.valueChanged[int].connect(self.changeRoll) - self.gridLayout.addWidget(self.rollSlider, 1, 1) - - self.yawSlider = QtGui.QSlider(self.centralWidget) - self.yawSlider.setMaximum(360) - self.yawSlider.setProperty("value", 180) - self.osd.setYaw(180) - self.yawSlider.setOrientation(QtCore.Qt.Horizontal) - self.yawSlider.setObjectName(_fromUtf8("yawSlider")) - self.yawSlider.valueChanged[int].connect(self.changeYaw) - self.gridLayout.addWidget(self.yawSlider, 2, 1) - - MainWindow.setCentralWidget(self.centralWidget) - self.menuBar = QtGui.QMenuBar(MainWindow) - self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 23)) - self.menuBar.setObjectName(_fromUtf8("menuBar")) - MainWindow.setMenuBar(self.menuBar) - self.mainToolBar = QtGui.QToolBar(MainWindow) - self.mainToolBar.setObjectName(_fromUtf8("mainToolBar")) - MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar) - self.statusBar = QtGui.QStatusBar(MainWindow) - self.statusBar.setObjectName(_fromUtf8("statusBar")) - MainWindow.setStatusBar(self.statusBar) - - self.retranslateUi(MainWindow) - QtCore.QMetaObject.connectSlotsByName(MainWindow) + self.osd = OSDWidget(roundWidget = self.roundWidget, + filename = self.filename) + self.ui.gridLayout.addWidget(self.osd, 0, 1) + self.ui.pitchSlider.valueChanged[int].connect(self.changePitch) + self.ui.rollSlider.valueChanged[int].connect(self.changeRoll) + self.ui.yawSlider.valueChanged[int].connect(self.changeYaw) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) + @pyqtSlot(int, name = "changePitch") def changePitch(self, value): self.osd.setPitch(value) - self.osd.update() + @pyqtSlot(int, name = "changeRoll") def changeRoll(self, value): self.osd.setRoll(value) - self.osd.update() + @pyqtSlot(int, name = "changeYaw") def changeYaw(self, value): self.osd.setYaw(value) - self.osd.update() if __name__ == "__main__": import sys - app = QtGui.QApplication(sys.argv) - if "round" in sys.argv: - roundWidget = True - else: - roundWidget = False - MainWindow = QtGui.QMainWindow() - if len(sys.argv) > 1: - ui = Ui_MainWindow(sys.argv[1], roundWidget) - else: - ui = Ui_MainWindow(roundWidget = roundWidget) - ui.setupUi(MainWindow) - MainWindow.show() + + parser = argparse.ArgumentParser(description='OSD written in Qt.') + parser.add_argument('--round', '-r', action="store_true", + help='display the widget as a round attitude meter') + parser.add_argument('--filename', '-f', + help='specify the log file') + args = parser.parse_args() + + app = QtWidgets.QApplication(sys.argv) + ui = Ui_MainWindow(filename = args.filename, roundWidget = args.round) + ui.show() sys.exit(app.exec_()) diff --git a/qtosd/qtosd.ui b/qtosd/qtosd.ui index 05f288e..11aaf4f 100644 --- a/qtosd/qtosd.ui +++ b/qtosd/qtosd.ui @@ -28,9 +28,6 @@ - - - diff --git a/qtosd/qtosd_ui.py b/qtosd/qtosd_ui.py new file mode 100644 index 0000000..2089ed5 --- /dev/null +++ b/qtosd/qtosd_ui.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'qtosd.ui' +# +# Created: Tue Jun 2 19:36:00 2015 +# by: PyQt5 UI code generator 5.3.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(400, 300) + self.centralWidget = QtWidgets.QWidget(MainWindow) + self.centralWidget.setObjectName("centralWidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralWidget) + self.gridLayout.setObjectName("gridLayout") + self.pitchSlider = QtWidgets.QSlider(self.centralWidget) + self.pitchSlider.setMinimum(-180) + self.pitchSlider.setMaximum(180) + self.pitchSlider.setOrientation(QtCore.Qt.Vertical) + self.pitchSlider.setObjectName("pitchSlider") + self.gridLayout.addWidget(self.pitchSlider, 0, 0, 1, 1) + self.rollSlider = QtWidgets.QSlider(self.centralWidget) + self.rollSlider.setMinimum(-180) + self.rollSlider.setMaximum(180) + self.rollSlider.setOrientation(QtCore.Qt.Horizontal) + self.rollSlider.setObjectName("rollSlider") + self.gridLayout.addWidget(self.rollSlider, 1, 1, 1, 1) + self.yawSlider = QtWidgets.QSlider(self.centralWidget) + self.yawSlider.setMaximum(360) + self.yawSlider.setProperty("value", 180) + self.yawSlider.setOrientation(QtCore.Qt.Horizontal) + self.yawSlider.setObjectName("yawSlider") + self.gridLayout.addWidget(self.yawSlider, 2, 1, 1, 1) + MainWindow.setCentralWidget(self.centralWidget) + self.menuBar = QtWidgets.QMenuBar(MainWindow) + self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 23)) + self.menuBar.setObjectName("menuBar") + MainWindow.setMenuBar(self.menuBar) + self.mainToolBar = QtWidgets.QToolBar(MainWindow) + self.mainToolBar.setObjectName("mainToolBar") + MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar) + self.statusBar = QtWidgets.QStatusBar(MainWindow) + self.statusBar.setObjectName("statusBar") + MainWindow.setStatusBar(self.statusBar) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec_()) + diff --git a/qtosd/serialfpv.py b/qtosd/serialfpv.py index 6153a3d..f089d1c 100644 --- a/qtosd/serialfpv.py +++ b/qtosd/serialfpv.py @@ -49,7 +49,7 @@ class SerialFPV(): self.prev_reftime = None self.data = "" - def update(self): + def update_state(self): # read from file/serial while len(self.data) < 16384: data = self.f.read(1024) @@ -75,7 +75,7 @@ class SerialFPV(): "\| magnet %s %s %s " % (FLOAT, FLOAT, FLOAT) + "\| angles %s %s %s"% (FLOAT, FLOAT, FLOAT), l) if m: - cur_time = float(m.groups()[0]) / 20. + cur_time = float(m.groups()[0]) / 1000. # first time, init prev_time and prev_reftime if self.realtime == False and self.prev_time == None: self.prev_time = cur_time @@ -88,7 +88,6 @@ class SerialFPV(): break roll, pitch, yaw = ( map(lambda x: float(x), m.groups()[10:13])) - print roll, pitch, yaw self.roll = math.degrees(roll) + 180. self.pitch = math.degrees(pitch) self.yaw = math.degrees(yaw) -- 2.20.1