def __init__(self, parent = None): """ Initializes the main window, the plot, signals & slots and class global variables """ QMainWindow.__init__(self, parent) self.setupUi(self) self.plot = DataPlot(self.framePlot) self.plot.resize(640, 350) # Signals & Slots # ---------------- # Buttons: self.connect(self.ButtonLoadFile, SIGNAL("clicked()"),self.selectFile) self.connect(self.ButtonLoadVideo, SIGNAL("clicked()"),self.selectVideo) self.connect(self.ButtonQuit, SIGNAL("clicked()"), self.closeFile) self.connect(self.InfoButton, SIGNAL("clicked()"), self.infoPopup) self.connect(self.ButtonDisableVideo, SIGNAL("clicked()"), self.disableVideo) self.connect(self.ButtonEnableVideo, SIGNAL("clicked()"), self.enableVideo) self.connect(self.ButtonPlay, SIGNAL("clicked()"), self.playVideo) self.connect(self.ButtonPause, SIGNAL("clicked()"), self.pauseVideo) # SpinBox & Slider: self.connect(self.horizontalSlider, SIGNAL("valueChanged(int)"), self.spinBoxFrame.setValue) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.horizontalSlider.setValue) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.readFramesForPlot) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.getTime) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.readFrame) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.showVideoFrame) # ComboBox: self.connect(self.comboSelectData, SIGNAL("currentIndexChanged(const QString&)"), self.plot.setTitle) self.connect(self.comboSelectData, SIGNAL("currentIndexChanged(int)"), self.selectionChanged) #DEBUG #self.connect(self.TestButton, SIGNAL("clicked()"), self.debugFunction) # Variables self.fh=0 # file handler self.offset=0 self.selectedFrame=0 self.selectedSlot=0 self.lastFrame=-1 self.elapsedTime=0 self.toggle="A" self.videoMode=0
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent = None): """ Initializes the main window, the plot, signals & slots and class global variables """ QMainWindow.__init__(self, parent) self.setupUi(self) self.plot = DataPlot(self.framePlot) self.plot.resize(640, 350) # Signals & Slots # ---------------- # Buttons: self.connect(self.ButtonLoadFile, SIGNAL("clicked()"),self.selectFile) self.connect(self.ButtonLoadVideo, SIGNAL("clicked()"),self.selectVideo) self.connect(self.ButtonQuit, SIGNAL("clicked()"), self.closeFile) self.connect(self.InfoButton, SIGNAL("clicked()"), self.infoPopup) self.connect(self.ButtonDisableVideo, SIGNAL("clicked()"), self.disableVideo) self.connect(self.ButtonEnableVideo, SIGNAL("clicked()"), self.enableVideo) self.connect(self.ButtonPlay, SIGNAL("clicked()"), self.playVideo) self.connect(self.ButtonPause, SIGNAL("clicked()"), self.pauseVideo) # SpinBox & Slider: self.connect(self.horizontalSlider, SIGNAL("valueChanged(int)"), self.spinBoxFrame.setValue) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.horizontalSlider.setValue) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.readFramesForPlot) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.getTime) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.readFrame) self.connect(self.spinBoxFrame, SIGNAL("valueChanged(int)"), self.showVideoFrame) # ComboBox: self.connect(self.comboSelectData, SIGNAL("currentIndexChanged(const QString&)"), self.plot.setTitle) self.connect(self.comboSelectData, SIGNAL("currentIndexChanged(int)"), self.selectionChanged) #DEBUG #self.connect(self.TestButton, SIGNAL("clicked()"), self.debugFunction) # Variables self.fh=0 # file handler self.offset=0 self.selectedFrame=0 self.selectedSlot=0 self.lastFrame=-1 self.elapsedTime=0 self.toggle="A" self.videoMode=0 def debugFunction(self): print "Start Timer" self.startTimer(80) def playVideo(self): """ Starts the video player and initializes the first two sets of frames The following frames are pre processed by the timerEvent """ import os,time self.toggle = "A" self.ButtonPlay.setEnabled(0) self.ButtonLoadVideo.setEnabled(0) self.ButtonPause.setEnabled(1) self.ButtonDisableVideo.setEnabled(0) self.spinBoxFrame.setEnabled(0) self.horizontalSlider.setEnabled(0) # Process message self.labelFrame.setPixmap(QPixmap()) self.labelFrame.setText(QtGui.QApplication.translate("MainWindow", "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;\"><span style=\" font-size:29pt; font-weight:600; color:#ffa500;\"> Please wait ... processing.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8)) self.repaint() # Processing (1st set) argList = ["-an","-i","\"".join(("",self.videofile,"")),"-ss",self.elapsedTime,"-t","00:00:01","-r","30","-y","-s","640x480","frameshots/videoA%d.jpg"] os.waitpid(os.spawnv(os.P_NOWAIT,FFMPEG, argList), 0) # Processing (2nd set) seektime=time.strftime("%H:%M:%S",time.gmtime((self.selectedFrame+30) / FPS)) argList = ["-an","-i","\"".join(("",self.videofile,"")),"-ss",seektime,"-t","00:00:01","-r","30","-y","-s","640x480","frameshots/videoB%d.jpg"] os.spawnv(os.P_NOWAIT,FFMPEG, argList) #Start timer self.timerID = self.startTimer(80) # Timer for the video player; time in ms; 80 is the current maxiumum due to the time ffmpeg needs for processing print "Start Timer: %i" % self.timerID def pauseVideo(self): print "Kill Timer: %i" % self.timerID self.killTimer(self.timerID) self.ButtonPlay.setEnabled(1) self.ButtonPause.setEnabled(0) self.ButtonLoadVideo.setEnabled(1) self.ButtonDisableVideo.setEnabled(1) self.spinBoxFrame.setEnabled(1) self.horizontalSlider.setEnabled(1) def timerEvent(self, e): """ Timer for the video player Current max. speed is 80ms; ffmpeg isn't fast enough for processing """ if self.labelFrame.isEnabled() and self.selectedFrame <= self.maxFrames-1: # Pre processing: if self.selectedFrame%FPS == 1: import os,time seektime=time.strftime("%H:%M:%S",time.gmtime((self.selectedFrame+30) / FPS)) if self.toggle=="A": argList = ["-an","-i","\"".join(("",self.videofile,"")),"-ss",seektime,"-t","00:00:01","-r","30","-y","-s","640x480","frameshots/videoB%d.jpg"] else: # self.toggle="B" argList = ["-an","-i","\"".join(("",self.videofile,"")),"-ss",seektime,"-t","00:00:01","-r","30","-y","-s","640x480","frameshots/videoA%d.jpg"] os.spawnv(os.P_NOWAIT,FFMPEG, argList) # Show image: image = (self.selectedFrame % FPS) + 1 if self.toggle=="A": pixmap = QPixmap("frameshots/videoA%i.jpg" % image) else: # self.toggle="B" pixmap = QPixmap("frameshots/videoB%i.jpg" % image) self.labelFrame.setPixmap(pixmap) self.spinBoxFrame.setValue(self.selectedFrame) self.readFramesForPlot(self.selectedFrame) if self.selectedFrame%30==29: if self.toggle=="A": self.toggle="B" else: self.toggle="A" self.selectedFrame=self.selectedFrame+1 else: self.pauseVideo() pixmap = QPixmap("images/logo_chrome.png") self.labelFrame.setPixmap(pixmap) def disableVideo(self): self.frameImage.setEnabled(0) self.labelFrame.setEnabled(0) self.ButtonDisableVideo.setEnabled(0) self.ButtonEnableVideo.setEnabled(1) self.ButtonPlay.setEnabled(0) self.horizontalSlider.setTracking(1) pixmap = QPixmap("images/logo_chrome.png") self.labelFrame.setPixmap(pixmap) def enableVideo(self): if QFile.exists(self.videofile): self.lineEditVideo.setText(self.videofile) self.ButtonEnableVideo.setEnabled(0) self.ButtonDisableVideo.setEnabled(1) self.ButtonPlay.setEnabled(1) self.frameImage.setEnabled(1) self.labelFrame.setEnabled(1) self.showVideoFrame(self.selectedFrame) self.horizontalSlider.setTracking(0) def showVideoFrame(self,frame): """ Shows the corresponding video frame to the selected frame number Needs some time for processing after each new second """ if self.labelFrame.isEnabled() and self.ButtonPlay.isEnabled(): diff = (self.selectedFrame%FPS - self.lastFrame%FPS) * self.sign(self.selectedFrame - self.lastFrame) # Are we moving upwards or downwards? if diff < 0 or abs(self.selectedFrame-self.lastFrame)>FPS-1: import os # Show "processing..." message self.labelFrame.setPixmap(QPixmap()) self.labelFrame.setText(QtGui.QApplication.translate("MainWindow", "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;\"><span style=\" font-size:29pt; font-weight:600; color:#ffa500;\"> Please wait ... processing.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8)) self.repaint() # Process video with ffmpeg argList = ["-an","-i","\"".join(("",self.videofile,"")),"-ss",self.elapsedTime,"-t","00:00:01","-r","30","-y","-s","640x480","frameshots/video%d.jpg"] os.waitpid(os.spawnv(os.P_NOWAIT,FFMPEG, argList), 0) # Display image (frame) image = (self.selectedFrame % FPS) + 1 pixmap = QPixmap("frameshots/video%i.jpg" % image) self.labelFrame.setPixmap(pixmap) self.lastFrame=self.selectedFrame def readFrame(self,frame): """ Reads a single dataset out of the .dat file and displays it on the form """ self.selectedFrame=frame self.fh.seek(frame*DATASET) tmp = struct.unpack(containerFormat,self.fh.read(DATASET)) # See http://docs.python.org/lib/module-struct.html #CHANGE_IF_NEW_CAN_MESSAGE_ADDED, below # ESP if tmp[3]: self.checkBoxESP.setCheckState(Qt.Checked) else: self.checkBoxESP.setCheckState(Qt.Unchecked) # Suspension deflection self.Front.setText(str(tmp[4])) self.Rear.setText(str(tmp[5])) # Clutch self.ClutchStiffness.setText(str(tmp[6])) self.ClutchValue.setText(str(tmp[7])) # Motor Current self.MotorCurrent.setText(str(tmp[8])) # Wheelspeed self.speed_car.setText(str(round(tmp[9],3))) self.speed_FL.setText(str(round(tmp[10],3))) self.speed_FR.setText(str(round(tmp[11],3))) self.speed_RL.setText(str(round(tmp[12],3))) self.speed_RR.setText(str(round(tmp[13],3))) # Brake and ESP self.lateral.setText(str(round(tmp[14],3))) self.brake.setText(str(round(tmp[15],3))) self.yaw.setText(str(round(tmp[16],3))) # Steering self.Torque.setText(str(round(tmp[17],3))) self.Angle.setText(str(round(tmp[18],3))) # Demanded steering torque self.SteeringTorque.setText(str(round(tmp[19],3))) # Engine self.IntTorque.setText(str(round(tmp[20],3))) self.TorqueLoss.setText(str(round(tmp[21],3))) # Timestamp self.diffBox.setText(str(abs(tmp[22]-int(self.timestampBox.displayText())))) self.timestampBox.setText(str(tmp[22])) # Stanford 0x501 self.model_version.setText(str(tmp[23])) tmp_str = '_'.join([str(tmp[24]),str(tmp[25]),str(tmp[26]),str(tmp[27])]) tmp_str = ':'.join([tmp_str,str(tmp[28]),str(tmp[29])]) self.save_date.setText(tmp_str) self.ddl_timestamp.setText(str(round(tmp[30],3))) # Stanford 0x502 self.yawAngle.setText(str(round(tmp[31],3))) self.yawRate.setText(str(round(tmp[32],3))) self.rollAngle.setText(str(round(tmp[33],3))) self.rollRate.setText(str(round(tmp[34],3))) # Stanford 0x503 self.vx.setText(str(round(tmp[35],3))) self.axCG.setText(str(round(tmp[36],3))) self.vyCG.setText(str(round(tmp[37],3))) self.ayCG.setText(str(round(tmp[38],3))) # Stanford 0x504 self.PosE.setText(str(round(tmp[39],3))) self.PosN.setText(str(round(tmp[40],3))) # Stanford 0x505 self.sideslip.setText(str(round(tmp[41],3))) self.rawIpitch.setText(str(round(tmp[42],3))) self.rawIaz.setText(str(round(tmp[43],3))) # Stanford 0x506 self.LRDuration.setText(str(round(tmp[44],3))) self.RRDuration.setText(str(round(tmp[45],3))) self.LFDuration.setText(str(round(tmp[46],3))) self.RFDuration.setText(str(round(tmp[47],3))) self.LeftTieRod.setText(str(round(tmp[48],3))) self.RightTieRod.setText(str(round(tmp[49],3))) # Stanford 0x507 self.led_status.setText(str(tmp[50])) def readFramesForPlot(self, startFrame): """ Reading data out of the .dat file and painting it to the plot """ import struct # Special cases for the beginning and the end of the plot (dataset) centerFrame=startFrame if startFrame < 250: centerFrame = 250 elif startFrame >= (self.maxFrames-250): centerFrame = self.maxFrames-251 # Read data (-250..startFrame..+250 = 501 values) for i in range(501): self.fh.seek((i+centerFrame-250)*DATASET+2*4) #this is to find the frame count, currently offseting dummy + version variables, 2*4 bytes (frameCount is 3rd variable), CHANGE_IF_NEW_CAN_MESSAGE_ADDED tmp = struct.unpack("i",self.fh.read(4)) self.plot.x[i] = float(tmp[0]) self.fh.seek((i+centerFrame-250)*DATASET + self.offset) if self.selectedSlot <= 5: #first 6 variables are integers, all others are floats, CHANGE_IF_NEW_CAN_MESSAGE_ADDED tmp = struct.unpack("i",self.fh.read(4)) else: tmp = struct.unpack("f",self.fh.read(4)) self.plot.y[i] = tmp[0] # Set the label showing the data value # -> special cases for the beginning and the end of the dataset label = self.plot.marker.label() if startFrame < 250: label.setText('%.3f' % self.plot.y[startFrame]) print self.plot.x[startFrame] elif startFrame >= (self.maxFrames-250): label.setText('%.3f' % self.plot.y[501-self.maxFrames+startFrame]) print self.plot.x[501-self.maxFrames+startFrame] else: label.setText('%.3f' % self.plot.y[250]) print self.plot.x[250] self.plot.marker.setLabel(label) # Prepare and plot the curve self.plot.curveR.setData(self.plot.x, self.plot.y) self.plot.marker.setValue(self.selectedFrame, 0) self.plot.replot() def selectionChanged(self, slot): """ SLOT for changes in the combo box """ #print "Selected slot: %i" % slot # debug self.selectedSlot=slot #slot, refers to the drop down menu for the plot starting from zero, see UI_Main.ui for organization #drop down list does not contain dummy, version, frameCount, xPC "model" info, timestamp...basically anythign that isn't to be plotted. # Set the offset for reading the dataset # Exlcuding the timestamps, version number and other meta data # Basic powertrain CAN signals if slot in range(0,19): #range is the number of basic powertrain CAN signals, increment appropriately if you add a signal, CHANGE_IF_NEW_CAN_MESSAGE_ADDED self.offset=(slot+3)*4 #ignore the first three variables (dummy, version, and frameCount), used for plotting y-axis, CHANGE_IF_NEW_CAN_MESSAGE_ADDED # Stanford DDL signals elif slot in range(19,38): #range of Stanford DDL signals, increment appropriately if you add a signal, CHANGE_IF_NEW_CAN_MESSAGE_ADDED self.offset=(slot+13)*4 #CHANGE_IF_NEW_CAN_MESSAGE_ADDED self.readFramesForPlot(self.selectedFrame) def selectFile(self): """ Opens a file select dialog and some basic setup """ if self.fh: self.fh.close() filename=unicode(QFileDialog.getOpenFileName(self, "Select File", ".", "CAN data file (*.dat)")) # opens file select dialog self.lineEditFile.setText(filename) self.openFile(filename) import os self.maxFrames = os.stat(filename)[6]/DATASET # get the maximum amount of frames; lastframe = maxFrames - 1 self.spinBoxFrame.setMaximum(self.maxFrames-1) self.horizontalSlider.setMaximum(self.maxFrames-1) self.getTime(0) self.readFrame(0) self.selectionChanged(0) self.frameData.setEnabled(1) self.frameSelect.setEnabled(1) self.framePlot.setEnabled(1) self.groupBoxVideo.setEnabled(1) self.ButtonLoadVideo.setEnabled(1) def openFile(self, filename): """ Opens the file and creates a file handler """ import struct,sys try: self.fh = open(filename, "rb") except IOError, e: print "I/O error: %s" % e else: