From 247353153f31f5418784d7b4c1c99eb34fada2ec Mon Sep 17 00:00:00 2001 From: Kuba Sawulski Date: Wed, 15 Jan 2020 02:25:10 +0100 Subject: [PATCH] Plots added --- .gitignore | 4 ++ car/canListener.py | 6 ++- car/motion.py | 13 +++++- gui/mainWindow.py | 75 +++++++++++++++++++----------- gui/mainWindow.ui | 107 +++++++++++++++++++++++++++++-------------- main.py | 111 +++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 248 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index ffe2dae..3b75ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,7 @@ venv.bak/ # Test snippets test*.py + +# Log files +logs/ +log.dat \ No newline at end of file diff --git a/car/canListener.py b/car/canListener.py index 37033a5..34c1550 100644 --- a/car/canListener.py +++ b/car/canListener.py @@ -1,4 +1,5 @@ from struct import unpack +from time import time import serial from PyQt5.QtCore import * @@ -37,7 +38,7 @@ class myCan(QObject): strSignal = pyqtSignal(str) tupleSignal = pyqtSignal(tuple) - def __init__(self, serialPortName, strSlots=[], tupleSlots=[], loopTime=1): + def __init__(self, serialPortName, strSlots=[], tupleSlots=[], loopTime=1.0): super().__init__() self.__serialhandle = serial.Serial(serialPortName, 115200) self.__serialhandle.reset_input_buffer() @@ -119,10 +120,11 @@ def sendMsg(self, msg): class canMsg(): def __init__(self, StdId, Data): + self.timestamp = time() self.stdId = StdId self.data = Data self.dlc = len(Data) - + def __str__(self): if self.stdId == 19: return "ID: {ID:#x}\t Data: {Data}".format(Data=unpack( diff --git a/car/motion.py b/car/motion.py index c19819c..f69b1d4 100644 --- a/car/motion.py +++ b/car/motion.py @@ -29,7 +29,7 @@ def __init__(self, trackProfile): super().__init__(trackProfile) self.__length = max(pos[0] for pos in self.val) self.__interpolant = interp1d([pos[0] for pos in self.val], [ - pos[1] for pos in self.val], kind='cubic', bounds_error=True, copy=False, assume_sorted=False) + pos[1] for pos in self.val], kind='linear', bounds_error=True, copy=False, assume_sorted=False) def getSlopeSine(self, point, positionInterval=2): """Compute track slope sine @@ -217,6 +217,10 @@ def setThrottle(self, throttle): except: raise ValueError( "Throttle value have to be choosen from unit interval [0-1]") + + if (self.__throttle <= 0 and temp >= 0): + self.__state[2] += self.param.get("r0") + self.__throttle = temp def setTimestep(self, dt): @@ -295,7 +299,6 @@ def carDynamics(t, x, throttle): self.__state = solve_ivp(lambda t, x: carDynamics(t, x, self.__throttle), (t0, __nextSwitch), self.__state, t_eval=[__nextSwitch])['y'].flatten() if (self.__throttle <= 0): - self.__state[2] += self.param.get("r0") self.setThrottle(1) else: self.setThrottle(0) @@ -306,6 +309,12 @@ def carDynamics(t, x, throttle): else: self.__state = solve_ivp(lambda t, x: carDynamics(t, x, self.__throttle), (t0, tf), self.__state, t_eval=[tf])['y'].flatten() + if(__nextSwitch == tf): + if (self.__throttle <= 0): + self.setThrottle(1) + else: + self.setThrottle(0) + self.__time = tf return self.__state diff --git a/gui/mainWindow.py b/gui/mainWindow.py index 554b090..7480359 100644 --- a/gui/mainWindow.py +++ b/gui/mainWindow.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'mainWindow.ui' # -# Created by: PyQt5 UI code generator 5.13.0 +# Created by: PyQt5 UI code generator 5.14.1 # # WARNING! All changes made in this file will be lost! @@ -51,33 +51,11 @@ def setupUi(self, MainWindow): self.Simulation = QtWidgets.QWidget() self.Simulation.setObjectName("Simulation") self.gridLayoutWidget = QtWidgets.QWidget(self.Simulation) - self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 317, 99)) + self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 317, 128)) self.gridLayoutWidget.setObjectName("gridLayoutWidget") self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") - self.speedField = QtWidgets.QLineEdit(self.gridLayoutWidget) - self.speedField.setReadOnly(True) - self.speedField.setObjectName("speedField") - self.gridLayout.addWidget(self.speedField, 1, 2, 1, 1) - self.timeField = QtWidgets.QLineEdit(self.gridLayoutWidget) - self.timeField.setReadOnly(True) - self.timeField.setObjectName("timeField") - self.gridLayout.addWidget(self.timeField, 1, 0, 1, 1) - self.engineLabel = QtWidgets.QLabel(self.gridLayoutWidget) - self.engineLabel.setAlignment(QtCore.Qt.AlignCenter) - self.engineLabel.setObjectName("engineLabel") - self.gridLayout.addWidget(self.engineLabel, 0, 4, 1, 1) - self.makeStepButton = QtWidgets.QPushButton(self.gridLayoutWidget) - self.makeStepButton.setObjectName("makeStepButton") - self.gridLayout.addWidget(self.makeStepButton, 2, 0, 1, 5) - self.engineField = QtWidgets.QLineEdit(self.gridLayoutWidget) - self.engineField.setObjectName("engineField") - self.gridLayout.addWidget(self.engineField, 1, 4, 1, 1) - self.positionLabel = QtWidgets.QLabel(self.gridLayoutWidget) - self.positionLabel.setAlignment(QtCore.Qt.AlignCenter) - self.positionLabel.setObjectName("positionLabel") - self.gridLayout.addWidget(self.positionLabel, 0, 1, 1, 1) self.fuelField = QtWidgets.QLineEdit(self.gridLayoutWidget) self.fuelField.setReadOnly(True) self.fuelField.setObjectName("fuelField") @@ -86,14 +64,32 @@ def setupUi(self, MainWindow): self.fuelLabel.setAlignment(QtCore.Qt.AlignCenter) self.fuelLabel.setObjectName("fuelLabel") self.gridLayout.addWidget(self.fuelLabel, 0, 3, 1, 1) + self.engineLabel = QtWidgets.QLabel(self.gridLayoutWidget) + self.engineLabel.setAlignment(QtCore.Qt.AlignCenter) + self.engineLabel.setObjectName("engineLabel") + self.gridLayout.addWidget(self.engineLabel, 0, 4, 1, 1) + self.positionLabel = QtWidgets.QLabel(self.gridLayoutWidget) + self.positionLabel.setAlignment(QtCore.Qt.AlignCenter) + self.positionLabel.setObjectName("positionLabel") + self.gridLayout.addWidget(self.positionLabel, 0, 1, 1, 1) self.timeLabel = QtWidgets.QLabel(self.gridLayoutWidget) self.timeLabel.setAlignment(QtCore.Qt.AlignCenter) self.timeLabel.setObjectName("timeLabel") self.gridLayout.addWidget(self.timeLabel, 0, 0, 1, 1) + self.speedField = QtWidgets.QLineEdit(self.gridLayoutWidget) + self.speedField.setReadOnly(True) + self.speedField.setObjectName("speedField") + self.gridLayout.addWidget(self.speedField, 1, 2, 1, 1) + self.engineField = QtWidgets.QLineEdit(self.gridLayoutWidget) + self.engineField.setObjectName("engineField") + self.gridLayout.addWidget(self.engineField, 1, 4, 1, 1) self.positionField = QtWidgets.QLineEdit(self.gridLayoutWidget) self.positionField.setReadOnly(True) self.positionField.setObjectName("positionField") self.gridLayout.addWidget(self.positionField, 1, 1, 1, 1) + self.makeStepButton = QtWidgets.QPushButton(self.gridLayoutWidget) + self.makeStepButton.setObjectName("makeStepButton") + self.gridLayout.addWidget(self.makeStepButton, 2, 0, 1, 5) self.speedLabel = QtWidgets.QLabel(self.gridLayoutWidget) self.speedLabel.setAlignment(QtCore.Qt.AlignCenter) self.speedLabel.setObjectName("speedLabel") @@ -102,6 +98,31 @@ def setupUi(self, MainWindow): self.simulationStart.setCheckable(True) self.simulationStart.setObjectName("simulationStart") self.gridLayout.addWidget(self.simulationStart, 3, 0, 1, 5) + self.timeField = QtWidgets.QLineEdit(self.gridLayoutWidget) + self.timeField.setReadOnly(True) + self.timeField.setObjectName("timeField") + self.gridLayout.addWidget(self.timeField, 1, 0, 1, 1) + self.resetSimulationButton = QtWidgets.QPushButton(self.gridLayoutWidget) + self.resetSimulationButton.setObjectName("resetSimulationButton") + self.gridLayout.addWidget(self.resetSimulationButton, 4, 0, 1, 5) + self.gridLayoutWidget_2 = QtWidgets.QWidget(self.Simulation) + self.gridLayoutWidget_2.setGeometry(QtCore.QRect(329, 9, 631, 301)) + self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2") + self.chartsGrid = QtWidgets.QGridLayout(self.gridLayoutWidget_2) + self.chartsGrid.setContentsMargins(0, 0, 0, 0) + self.chartsGrid.setObjectName("chartsGrid") + self.fuelChartW = QChartView(self.gridLayoutWidget_2) + self.fuelChartW.setObjectName("fuelChartW") + self.chartsGrid.addWidget(self.fuelChartW, 1, 0, 1, 1) + self.positionChartW = QChartView(self.gridLayoutWidget_2) + self.positionChartW.setObjectName("positionChartW") + self.chartsGrid.addWidget(self.positionChartW, 0, 0, 1, 1) + self.engineChartW = QChartView(self.gridLayoutWidget_2) + self.engineChartW.setObjectName("engineChartW") + self.chartsGrid.addWidget(self.engineChartW, 1, 1, 1, 1) + self.speedChartW = QChartView(self.gridLayoutWidget_2) + self.speedChartW.setObjectName("speedChartW") + self.chartsGrid.addWidget(self.speedChartW, 0, 1, 1, 1) self.tabWidget.addTab(self.Simulation, "") self.Settings = QtWidgets.QWidget() self.Settings.setObjectName("Settings") @@ -154,13 +175,14 @@ def retranslateUi(self, MainWindow): self.refreshAvailablePorts.setText(_translate("MainWindow", "Refresh")) self.connectPort.setText(_translate("MainWindow", "Connect")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Connection), _translate("MainWindow", "Connection")) + self.fuelLabel.setText(_translate("MainWindow", "Fuel")) self.engineLabel.setText(_translate("MainWindow", "Engine")) - self.makeStepButton.setText(_translate("MainWindow", "Make Simulation &Step!")) self.positionLabel.setText(_translate("MainWindow", "Position")) - self.fuelLabel.setText(_translate("MainWindow", "Fuel")) self.timeLabel.setText(_translate("MainWindow", "Time")) + self.makeStepButton.setText(_translate("MainWindow", "Make Simulation &Step!")) self.speedLabel.setText(_translate("MainWindow", "Speed")) self.simulationStart.setText(_translate("MainWindow", "Start Simulation!")) + self.resetSimulationButton.setText(_translate("MainWindow", "Reset Simulation!")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Simulation), _translate("MainWindow", "Simulation")) self.langSelectorLabel.setText(_translate("MainWindow", "Language")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.Settings), _translate("MainWindow", "Settings")) @@ -170,6 +192,7 @@ def retranslateUi(self, MainWindow): self.actionAbout.setText(_translate("MainWindow", "About")) self.actionImport_Settings.setText(_translate("MainWindow", "Import Settings")) self.actionExport_Settings.setText(_translate("MainWindow", "Export Settings")) +from PyQt5.QtChart import QChartView if __name__ == "__main__": diff --git a/gui/mainWindow.ui b/gui/mainWindow.ui index ac28e78..d17fe57 100644 --- a/gui/mainWindow.ui +++ b/gui/mainWindow.ui @@ -132,21 +132,24 @@ 10 10 317 - 99 + 128 - - + + true - - - - true + + + + Fuel + + + Qt::AlignCenter @@ -160,16 +163,6 @@ - - - - Make Simulation &Step! - - - - - - @@ -180,23 +173,6 @@ - - - - true - - - - - - - Fuel - - - Qt::AlignCenter - - - @@ -207,6 +183,16 @@ + + + + true + + + + + + @@ -214,6 +200,13 @@ + + + + Make Simulation &Step! + + + @@ -234,6 +227,44 @@ + + + + true + + + + + + + Reset Simulation! + + + + + + + + + 329 + 9 + 631 + 301 + + + + + + + + + + + + + + + @@ -321,6 +352,14 @@ + + + QChartView + QWidget +
PyQt5.QtChart
+ 1 +
+
diff --git a/main.py b/main.py index 0bbc930..d255dc2 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ from PyQt5 import QtWidgets from PyQt5.QtCore import * +from PyQt5.QtChart import QChart, QLineSeries import os import sys @@ -25,6 +26,49 @@ def __init__(self): self.__translator = QTranslator(self) self.setupUi(self) + + self.positionChart = QChart() + self.positionSeries = QLineSeries() + + self.speedChart = QChart() + self.speedSeries = QLineSeries() + + self.fuelChart = QChart() + self.fuelSeries = QLineSeries() + + self.engineChart = QChart() + self.engineSeries = QLineSeries() + + self.positionChart.addSeries(self.positionSeries) + self.speedChart.addSeries(self.speedSeries) + self.fuelChart.addSeries(self.fuelSeries) + self.engineChart.addSeries(self.engineSeries) + + self.positionChart.legend().hide() + self.speedChart.legend().hide() + self.fuelChart.legend().hide() + self.engineChart.legend().hide() + + self.positionChart.createDefaultAxes() + self.speedChart.createDefaultAxes() + self.fuelChart.createDefaultAxes() + self.engineChart.createDefaultAxes() + + self.positionChart.setTitle("Position") + self.speedChart.setTitle("Speed") + self.fuelChart.setTitle("Fuel") + self.engineChart.setTitle("Engine") + + self.positionChart.setMargins(QMargins()) + self.speedChart.setMargins(QMargins()) + self.fuelChart.setMargins(QMargins()) + self.engineChart.setMargins(QMargins()) + + self.positionChartW.setChart(self.positionChart) + self.speedChartW.setChart(self.speedChart) + self.fuelChartW.setChart(self.fuelChart) + self.engineChartW.setChart(self.engineChart) + self.populateFields() self.engineField.setText("1") @@ -44,6 +88,18 @@ def on_langSelector_currentTextChanged(self, lang): QtWidgets.QApplication.instance().installTranslator(self.__translator) else: QtWidgets.QApplication.instance().removeTranslator(self.__translator) + + @pyqtSlot() + def on_resetSimulationButton_clicked(self): + self.__car = car.motion() + self.__car.param.fromJSON(car.defaultParams()) + + self.positionSeries = QLineSeries() + self.speedSeries = QLineSeries() + self.fuelSeries = QLineSeries() + self.engineSeries = QLineSeries() + + self.populateFields() @pyqtSlot() def on_makeStepButton_clicked(self): @@ -55,13 +111,16 @@ def on_makeStepButton_clicked(self): StdId=18, Data=self.__car.getCanBytes()[:]) print(motionMessage) self.__canbus.sendMsg(motionMessage) + with open('log.dat', 'a') as outfile: + outfile.write("%.1f\t%f\t%f\t%f\n" % (self.__car.getSimTime(), + self.__car.getSimDistance(), self.__car.getSimSpeed(), self.__car.getSimFuel())) except Exception as e: - QtWidgets.QMessageBox.critical( + QtWidgets.QMessageBox.warning( self, _translate("Dialog", "Error"), str(e)) self.populateFields() - if float(self.timeField.text())>=240: - if self.simulationStart.isChecked()==True: + if float(self.timeField.text()) >= 240: + if self.simulationStart.isChecked() == True: self.simulationStart.click() def populateFields(self): @@ -71,6 +130,36 @@ def populateFields(self): self.fuelField.setText(f"{self.__car.getSimFuel():.2f}") self.engineField.setText(f"{self.__car.getThrottle():.2f}") + xax = self.positionChart.axisX() + + if(self.__car.getSimTime()>self.positionChart.axisX().max()): + self.positionChart.axisX().setMax(self.__car.getSimTime()) + self.speedChart.axisX().setMin(self.__car.getSimTime()) + self.fuelChart.axisX().setMin(self.__car.getSimTime()) + self.engineChart.axisX().setMin(self.__car.getSimTime()) + elif(self.__car.getSimTime()self.speedChart.axisY().max()): + self.speedChart.axisY().setMax(self.__car.getSimSpeed()) + elif(self.__car.getSimSpeed()self.fuelChart.axisY().max()): + self.fuelChart.axisY().setMax(self.__car.getSimFuel()) + elif(self.__car.getSimFuel()