Exemplo n.º 1
0
class TunnelGui(QtWidgets.QMainWindow, Tunnel_Model.Ui_MainWindow):

    sensorRdr = None
    sampleCollector = None

    enableGraphs = False
    liftGraph = None
    dragGraph = None
    pitchMomentGraph = None
    airspeedGraph = None
    config = TunnelConfig()

    def __init__(self, qApp):
        super().__init__()
        self.qApp = qApp
        self.setupUi(self)

        # setup the calibrattion dialog
        self.dialogCalibrate = QtWidgets.QDialog()
        self.dialogCalibrateUi = Ui_DialogCalibrate()
        self.dialogCalibrateUi.setupUi(self.dialogCalibrate)

        # Update displayed sample rate
        sampleRate = self.config.getItem("General", "samplerate")

        self.outSampleRate.display(sampleRate)

        # Connect buttons to their corresponding functions
        self.btnCalibrate.clicked.connect(self.showCalibrateDialog)
        self.btnLoadTare.clicked.connect(self.loadTare)
        self.btnSaveResults.clicked.connect(self.saveResults)

        self.dialogCalibrateUi.btnDone.clicked.connect(self.calibrationDone)
        self.dialogCalibrateUi.btnAirspeedTare.clicked.connect(
            self.airspeedTare)
        self.dialogCalibrateUi.btnAoAWingTare.clicked.connect(self.aoaWingTare)
        self.dialogCalibrateUi.btnAoAPlatformTare.clicked.connect(
            self.aoaPlatformTare)

        # Initialize the platform offset from the persist file. Can't wait
        # until SampleCollector is alive, so we read it directly from the
        # file. Woe be unto me if I change the name of the persist value...
        aoaPlatformOffset = TunnelPersist().getItem("AoA", "PlatformOffset")
        if aoaPlatformOffset == None:
            aoaPlatformOffset = 0.0
        else:
            aoaPlatformOffset = float(aoaPlatformOffset)

        self.dialogCalibrateUi.inpAoAOffset.setValue(aoaPlatformOffset)
        self.setAoAOffset(aoaPlatformOffset)

        # Set the Saving... text to nothing for now. When the Save button
        # is clicked, we'll light it up for a moment.
        self.lblSaving.setText("")

        # Show the directory path
        destDirname = self.config.getItem("General", "DataDestinationDir")
        self.lblDirPath.setText(destDirname)

    def showCalibrateDialog(self):
        self.dialogCalibrate.show()

    def calibrationDone(self):
        offset = self.dialogCalibrateUi.inpAoAOffset.value()
        self.sampleCollector.setAoAPlatformOffset(offset)
        self.setAoAOffset(offset)

    def aoaWingTare(self):
        self.sampleCollector.setAoAWingTare()

    def aoaPlatformTare(self):
        self.sampleCollector.setAoAPlatformTare()

    def airspeedTare(self):
        self.sampleCollector.setAirspeedTare()

    def loadTare(self):
        self.sampleCollector.setLoadTare()

    def slugify(self, value):
        """
        Normalizes string, converts to lowercase, removes non-alpha characters,
        and converts spaces to hyphens. Borrowed from
        https://stackoverflow.com/questions/295135/turn-a-string-into-a-valid-filename
        """
        value = str(
            unicodedata.normalize('NFKD', value).encode('ascii', 'ignore'))
        # Chomp the leading 'b\'
        value = value[2:]
        value = str(re.sub("[^\w.\s-]", "", value).strip().lower())
        value = str(re.sub("[-\s]+", "-", value))
        return value

    def saveResults(self):
        fname = self.slugify(str(self.inpRunName.text()))
        if (fname == ""):
            fname = self.config.getItem("General", "DefaultFileName")

        # Append '.csh' if not already there
        if not fname.endswith(".csv"):
            fname += ".csv"

        fname = Path(fname)
        destDirname = self.config.getItem("General", "DataDestinationDir")

        if (destDirname is None):
            destDirname = Path.cwd()
        else:
            Path(destDirname).mkdir(parents=True, exist_ok=True)

        fname = destDirname / fname
        print("Save Results clicked: %s" % fname)

        self.lblSaving.setText("Saving...")

        self.sampleCollector.doSave(fname, str(self.inpRunName.text()),
                                    str(self.inpConfiguration.text()),
                                    str(self.inpComments.text()))

        dieTime = QTime.currentTime().addSecs(1)
        while (QTime.currentTime() < dieTime):
            self.qApp.processEvents()

        self.lblSaving.setText("")
        self.lblSaving.repaint()
        self.qApp.processEvents()

    def startReadingSensors(self):
        sampleRate = self.outSampleRate.value()
        print("Start sampling at " + str(sampleRate) + " samples/sec")

    def setAoa(self, aoa):
        aoa = float('%.1f' % aoa)
        self.outAoaDeg.display(str(aoa))

    def setAoAOffset(self, offset):
        offset = float('%.1f' % offset)
        self.outAoaOffsetDeg.display(str(offset))

    def setAirspeed(self, speed):
        speed = float('%.1f' % speed)
        self.outSpeedMPH.display(str(speed))
        speed = speed * 5280.0 / 3600.0
        speed = float('%.1f' % speed)
        self.outSpeedFps.display(str(speed))

    def setAnenometer(self, speed):
        speed = float('%.1f' % speed)
        self.outAnemometerFps.display(str(speed))
        speed = speed * 3600.0 / 5280.0
        speed = float('%.1f' % speed)
        self.outAnemometerMPH.display(str(speed))

    def setLift(self, lift, stddev):
        lift = float('%.2f' % lift)
        stddev = float('%.2f' % stddev)
        itemKg = QTableWidgetItem()
        itemKg.setData(Qt.DisplayRole, lift)
        self.tblLiftDragMoment.setItem(0, 0, itemKg)
        itemLb = QTableWidgetItem()
        itemLb.setData(Qt.DisplayRole, float('%.2f' % (lift * 2.2046)))
        self.tblLiftDragMoment.setItem(0, 1, itemLb)
        fItemKg = QTableWidgetItem()
        fItemKg.setData(Qt.DisplayRole, stddev)
        self.tblLiftDragMoment.setItem(0, 2, fItemKg)

    def setDrag(self, drag, stddev):
        drag = float('%.2f' % drag)
        stddev = float('%.2f' % stddev)
        itemKg = QTableWidgetItem()
        itemKg.setData(Qt.DisplayRole, drag)
        self.tblLiftDragMoment.setItem(1, 0, itemKg)
        itemLb = QTableWidgetItem()
        itemLb.setData(Qt.DisplayRole, float('%.2f' % (drag * 2.2046)))
        self.tblLiftDragMoment.setItem(1, 1, itemLb)
        fItemKg = QTableWidgetItem()
        fItemKg.setData(Qt.DisplayRole, stddev)
        self.tblLiftDragMoment.setItem(1, 2, fItemKg)

    def setMoment(self, moment, stddev):
        moment = float('%.2f' % moment)
        stddev = float('%.2f' % stddev)
        itemKgM = QTableWidgetItem()
        itemKgM.setData(Qt.DisplayRole, moment)
        self.tblLiftDragMoment.setItem(2, 0, itemKgM)
        itemLbFt = QTableWidgetItem()
        itemLbFt.setData(Qt.DisplayRole, float('%.2f' % (moment * 8.8507)))
        self.tblLiftDragMoment.setItem(2, 1, itemLbFt)
        fItemKgM = QTableWidgetItem()
        fItemKgM.setData(Qt.DisplayRole, stddev)
        self.tblLiftDragMoment.setItem(2, 2, fItemKgM)

    def setPower(self, power):
        power = float('%.1f' % power)
        self.outPower.display(str(power))

    def setRawAoA(self, aoa):
        self.dialogCalibrateUi.txtRawAoA.setText(str(aoa))

    def setRawAirspeed(self, airspeed):
        self.dialogCalibrateUi.txtRawAirspeed.setText(str(airspeed))

    def saveRunNameAndConfiguration(self):
        if self.savedRunNameText != self.inpRunName.text():
            self.savedRunNameText = self.inpRunName.text()
            self.sampleCollector.saveRunName(self.savedRunNameText)

        if self.savedConfigurationText != self.inpConfiguration.text():
            self.savedConfigurationText = self.inpConfiguration.text()
            self.sampleCollector.saveConfiguration(self.savedConfigurationText)

    @pyqtSlot(ProcessedSample)
    def refreshWindow(self, currentData):
        self.setRawAoA(currentData.rawAoA)
        self.setRawAirspeed(currentData.rawAirspeed)

        self.setPower(currentData.volts * currentData.amps)
        self.setAoa(currentData.wingAoA)
        self.setAirspeed(currentData.airspeed)
        self.setAnenometer(currentData.hotwire)

        self.tblLiftDragMoment.setUpdatesEnabled(False)
        self.setLift(currentData.totalLift, currentData.totalLiftStdDev)
        self.setDrag(currentData.drag, currentData.dragStdDev)
        self.setMoment(currentData.pitchMoment, currentData.pitchMomentStdDev)
        self.tblLiftDragMoment.setUpdatesEnabled(True)

        self.updateGraphs(currentData.totalLift, currentData.drag,
                          currentData.pitchMoment, currentData.airspeed)

        self.saveRunNameAndConfiguration()

    def startSensorReader(self, tunnelWindow, tunnelDataQ):
        useSimulatedData = self.config.getItem("General", "UseSimulatedData")
        if (useSimulatedData is None):
            self.sensorRdr = SensorReader(tunnelWindow, tunnelDataQ)

        if (useSimulatedData.lower() == "true"):
            print("Starting data simulator")
            self.sensorRdr = SensorSimulator(tunnelWindow, tunnelDataQ)
        else:
            self.sensorRdr = SensorReader(tunnelWindow, tunnelDataQ)

        self.sensorRdr.daemon = True
        self.sensorRdr.start()

    def stopSensorReader(self):
        self.sensorRdr.terminate()

    def startSampleCollector(self, tunnelDataQ):
        self.sampleCollector = SampleCollector(tunnelDataQ)
        self.sampleCollector.updateWindow.connect(self.refreshWindow)
        self.sampleCollector.daemon = True
        self.sampleCollector.start()

        # Once SampleCollector is up and running, we can ask it for the
        # previously saved run name and configuraiton
        self.savedRunNameText = self.sampleCollector.getRunName()
        self.savedConfigurationText = self.sampleCollector.getConfiguration()
        self.inpRunName.setText(self.savedRunNameText)
        self.inpConfiguration.setText(self.savedConfigurationText)

    def stopSampleCollector(self):
        self.sampleCollector.terminate()

    def startGraphs(self):

        enableGraphs = self.config.getItem("General", "EnableGraphs")

        if (enableGraphs is None):
            self.enableGraphs = False
            return

        if (enableGraphs.lower() != "true"):
            self.enableGraphs = False
            return

        self.enableGraphs = True
        self.liftGraph = LiveGraph(QtCore.QRect(50, 150, 500, 200), "Lift",
                                   "kg", True)
        self.liftGraph.show()

        self.dragGraph = LiveGraph(QtCore.QRect(50, 375, 500, 200), "Drag",
                                   "Kg", True)
        self.dragGraph.show()

        self.pitchMomentGraph = LiveGraph(QtCore.QRect(50, 600, 500, 200),
                                          "Moment", "Kg-M", True)
        self.pitchMomentGraph.show()

        self.airspeedGraph = LiveGraph(QtCore.QRect(50, 825, 500, 200),
                                       "Airspeed", "Kt", True)
        self.airspeedGraph.show()

    def updateGraphs(self, lift, drag, pitchMoment, airspeed):
        if (self.enableGraphs):
            self.liftGraph.addDataToGraph(lift)
            self.dragGraph.addDataToGraph(drag)
            self.pitchMomentGraph.addDataToGraph(pitchMoment)
            self.airspeedGraph.addDataToGraph(airspeed)