class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.monitor_active = False self.com_monitor = None self.livefeed = LiveDataFeed() self.temperature_samples = [] self.timer = QTimer() # menu # self.file_menu = self.menuBar().addMenu("&File") selectport_action = QAction('Select TTY &Port...', self) selectport_action.triggered.connect(self.on_select_port) self.file_menu.addAction(selectport_action) self.start_action = QAction('&Start monitor') self.start_action.triggered.connect(self.on_start) self.start_action.setEnabled(False) self.file_menu.addAction(self.start_action) self.stop_action = QAction('&Stop monitor') self.stop_action.triggered.connect(self.on_stop) # main widget # # port portname_label = QLabel('tty port:') self.portname = QLineEdit() self.portname.setEnabled(False) self.portname.setFrame(False) portname_layout = QHBoxLayout() portname_layout.addWidget(portname_label) portname_layout.addWidget(self.portname, 0) portname_layout.addStretch(1) portname_groupbox = QGroupBox('Port') portname_groupbox.setLayout(portname_layout) # plot widget self.plot = qwt.QwtPlot(self) self.plot.setCanvasBackground(Qt.black) self.plot.setAxisTitle(qwt.QwtPlot.xBottom, 'Time') self.plot.setAxisScale(qwt.QwtPlot.xBottom, 0, 10, 1) self.plot.setAxisTitle(qwt.QwtPlot.yLeft, 'Temperature') self.plot.setAxisScale(qwt.QwtPlot.yLeft, 0, 250, 40) self.plot.replot() # curve widget self.curve = qwt.QwtPlotCurve('') self.curve.setRenderHint(qwt.QwtPlotItem.RenderAntialiased) pen = QPen(QColor('limegreen')) pen.setWidth(2) self.curve.setPen(pen) self.curve.attach(self.plot) # dial # self.dial = QDial() self.dial.setNotchesVisible(True) self.dial.setRange(0, 20) self.dial.setValue(10) self.dial.valueChanged.connect(self.on_dial_change) self.dial_label = QLabel('Update speed = %s (Hz)' % self.dial.value()) self.dial_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter) dial_layout = QVBoxLayout() dial_layout.addWidget(self.dial) dial_layout.addWidget(self.dial_label) # plot layout plot_layout = QVBoxLayout() plot_layout.addWidget(self.plot) plot_layout.addLayout(dial_layout) plot_groupbox = QGroupBox('Temperature') plot_groupbox.setLayout(plot_layout) # main self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(portname_groupbox) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) # status # self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) def set_actions_enable_state(self): if self.portname.text() == '': start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) def read_serial_data(self): '''Called periodically be the update timer to read data from the serial port. ''' qdata = list(get_all_from_queue(self.data_q)) if len(qdata) > 0: # print(len(qdata)) data = dict(timestamp=qdata[-1][1], temperature=ord(qdata[-1][0])) # print(data) self.livefeed.add_data(data) else: print('no data') def update_monitor(self): '''Updates the state of the monitor window with new data. The livefeed is used to dind out whether new data was received since last update. If not, nothing is updated. ''' if self.livefeed.has_new_data: data = self.livefeed.read_data() # print(data) self.temperature_samples.append( (data['timestamp'], data['temperature'])) if len(self.temperature_samples) > 100: self.temperature_samples.pop(0) xdata = [s[0] for s in self.temperature_samples] ydata = [s[1] for s in self.temperature_samples] avg = sum(ydata) / float(len(ydata)) self.plot.setAxisScale(qwt.QwtPlot.xBottom, xdata[0], max(20, xdata[-1])) self.curve.setData(xdata, ydata) self.plot.replot() # slots def on_select_port(self): text, ok = QInputDialog.getText(self, 'Port Name', 'Enter tty:') if ok: self.portname.setText(str(text)) self.set_actions_enable_state() def on_start(self): '''Start the monitor: com_monitor thread and the update timer''' if self.com_monitor is not None or self.portname.text() == '': return self.data_q = Queue() self.error_q = Queue() self.com_monitor = ComMonitorThread(self.data_q, self.error_q, self.portname.text(), 38400) self.com_monitor.start() com_error = None try: com_error = self.error_q.get(True, 0.01) except Empty: pass if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.set_actions_enable_state() self.timer = QTimer() self.timer.timeout.connect(self.on_timer) update_freq = self.dial.value() if update_freq > 0: self.timer.start(1000 / update_freq) self.status_text.setText('Monitor running') def on_stop(self): '''Stop the monitor''' if self.com_monitor is not None: self.com_monitor.join(0.01) self.com_monitor = None self.monitor_actibe = False self.timer.stop() self.set_actions_enable_state() self.status_text.setText('Monitor idle') def on_timer(self): '''Executed periodically when the monitor update timer is fired.''' self.read_serial_data() self.update_monitor() def on_dial_change(self): '''When the dial is rotated, it sets the update interval of the timer''' update_freq = self.dial.value() self.dial_label.setText('Update speed = %s (Hz)' % self.dial.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000 / update_freq)
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.setWindowTitle('ADXL345 Realtime Monitor') self.resize(800, 600) self.port = "" self.baudrate = 9600 self.monitor_active = False # on/off monitor state self.com_monitor = None # monitor reception thread self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.timer = QTimer() self.g_samples = [[], [], []] self.curve = [None]*3 self.gcurveOn = [1]*3 # by default all curve are plotted self.csvdata = [] self.create_menu() self.create_main_frame() self.create_status_bar() # Activate start-stop button connections self.connect(self.button_Connect, SIGNAL("clicked()"), self.OnStart) self.connect(self.button_Disconnect, SIGNAL("clicked()"), self.OnStop) #---------------------------------------------------------- def create_com_box(self): """ Purpose: create the serial com groupbox Return: return a layout of the serial com """ self.com_box = QGroupBox("COM Configuration") com_layout = QGridLayout() self.radio115200 = QRadioButton("115200") self.radio115200.setChecked(1) self.radio19200 = QRadioButton("19200") self.radio9600 = QRadioButton("9600") self.Com_ComboBox = QComboBox() com_layout.addWidget(self.Com_ComboBox,0,0,1,3) com_layout.addWidget(self.radio115200,1,0) com_layout.addWidget(self.radio19200,1,1) com_layout.addWidget(self.radio9600,1,2) self.fill_ports_combobox() self.button_Connect = QPushButton("Start") self.button_Disconnect = QPushButton("Stop") self.button_Disconnect.setEnabled(False) com_layout.addWidget(self.button_Connect,0,3) com_layout.addWidget(self.button_Disconnect,1,3) return com_layout #--------------------------------------------------------------------- def create_plot(self): """ Purpose: create the pyqwt plot Return: return a list containing the plot and the list of the curves """ plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time') plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Acceleration') plot.setAxisScale(Qwt.QwtPlot.yLeft, YMIN, YMAX, (YMAX-YMIN)/10) plot.replot() curve = [None]*3 pen = [QPen(QColor('limegreen')), QPen(QColor('red')) ,QPen(QColor('yellow')) ] for i in range(3): curve[i] = Qwt.QwtPlotCurve('') curve[i].setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen[i].setWidth(2) curve[i].setPen(pen[i]) curve[i].attach(plot) return plot, curve #--------------------------------------------------- def create_knob(self): """ Purpose: create a knob Return: return a the knob widget """ knob = Qwt.QwtKnob(self) knob.setRange(0, 180, 0, 1) knob.setScaleMaxMajor(10) knob.setKnobWidth(50) knob.setValue(180) return knob #--------------------------------------------------- def create_status_bar(self): self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) #--------------------------------------------------- def create_checkbox(self, label, color, connect_fn, connect_param): """ Purpose: create a personalized checkbox Input: the label, color, activated function and the transmitted parameter Return: return a checkbox widget """ checkBox = QCheckBox(label) checkBox.setChecked(1) checkBox.setFont( QFont("Arial", pointSize=12, weight=QFont.Bold ) ) green = QPalette() green.setColor(QPalette.Foreground, color) checkBox.setPalette(green) self.connect(checkBox, SIGNAL("clicked()"), partial(connect_fn,connect_param)) return checkBox #--------------------------------------------------- def create_main_frame(self): """ Purpose: create the main frame Qt widget """ # Serial communication combo box portname_layout = self.create_com_box() self.com_box.setLayout(portname_layout) # Update speed knob self.updatespeed_knob = self.create_knob() self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'), self.on_knob_change) self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value()) self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter) # Create the plot and curves self.plot, self.curve = self.create_plot() # Create the configuration horizontal panel self.max_spin = QSpinBox() self.max_spin.setMaximum(10000) self.max_spin.setValue(10000) spins_hbox = QHBoxLayout() spins_hbox.addWidget(QLabel('Save every')) spins_hbox.addWidget(self.max_spin) spins_hbox.addWidget( QLabel('Lines')) #spins_hbox.addStretch(1) self.gCheckBox = [ self.create_checkbox("Acceleration(x)", Qt.green, self.activate_curve, 0), self.create_checkbox("Acceleration(y)", Qt.red, self.activate_curve, 1), self.create_checkbox("Acceleration(z)", Qt.yellow, self.activate_curve, 2) ] self.button_clear = QPushButton("Clear screen") self.connect(self.button_clear, SIGNAL("clicked()"), self.clear_screen) # Place the horizontal panel widget plot_layout = QGridLayout() plot_layout.addWidget(self.plot,0,0,8,7) plot_layout.addWidget(self.gCheckBox[0],0,8) plot_layout.addWidget(self.gCheckBox[1],1,8) plot_layout.addWidget(self.gCheckBox[2],2,8) plot_layout.addWidget(self.button_clear,3,8) plot_layout.addLayout(spins_hbox,4,8) plot_layout.addWidget(self.updatespeed_knob,5,8) plot_layout.addWidget(self.knob_l,6,8) plot_groupbox = QGroupBox('Acceleration') plot_groupbox.setLayout(plot_layout) # Place the main frame and layout self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(self.com_box) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) #---------------------------------------------------------------------- def clear_screen(self): self.g_samples = [[], [], []] self.plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10) for i in range(3): self.curve[i].setData([], []) self.plot.replot() #----------------------------- def activate_curve(self, axe): if self.gCheckBox[axe].isChecked(): self.gcurveOn[axe] = 1 else: self.gcurveOn[axe] = 0 #--------------------------------------- def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") selectport_action = self.create_action("Select COM &Port...", shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port") self.start_action = self.create_action("&Start monitor", shortcut="Ctrl+M", slot=self.OnStart, tip="Start the data monitor") self.stop_action = self.create_action("&Stop monitor", shortcut="Ctrl+T", slot=self.OnStop, tip="Stop the data monitor") exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.start_action.setEnabled(False) self.stop_action.setEnabled(False) self.add_actions(self.file_menu, ( selectport_action, self.start_action, self.stop_action, None, exit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the monitor') self.add_actions(self.help_menu, (about_action,)) #---------------------------------------------------------------------- def set_actions_enable_state(self): if self.portname.text() == '': start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) #----------------------------------------------- def on_about(self): msg = __doc__ QMessageBox.about(self, "About the demo", msg.strip()) #----------------------------------------------- def on_select_port(self): ports = enumerate_serial_ports() if len(ports) == 0: QMessageBox.critical(self, 'No ports', 'No serial ports found') return item, ok = QInputDialog.getItem(self, 'Select a port', 'Serial port:', ports, 0, False) if ok and not item.isEmpty(): self.portname.setText(item) self.set_actions_enable_state() #----------------------------------------------- def fill_ports_combobox(self): """ Purpose: rescan the serial port com and update the combobox """ vNbCombo = "" self.Com_ComboBox.clear() self.AvailablePorts = enumerate_serial_ports() for value in self.AvailablePorts: self.Com_ComboBox.addItem(value) vNbCombo += value + " - " vNbCombo = vNbCombo[:-3] debug(("--> Les ports series disponibles sont: %s " % (vNbCombo))) #---------------------------------------------------------------------- def OnStart(self): """ Start the monitor: com_monitor thread and the update timer """ if self.radio115200.isChecked(): self.baudrate = 115200 print "--> baudrate is 115200 bps" if self.radio19200.isChecked(): self.baudrate = 19200 print "--> baudrate is 19200 bps" if self.radio9600.isChecked(): self.baudrate = 9600 print "--> baudrate is 9600 bps" vNbCombo = self.Com_ComboBox.currentIndex() self.port = self.AvailablePorts[vNbCombo] self.button_Connect.setEnabled(False) self.button_Disconnect.setEnabled(True) self.Com_ComboBox.setEnabled(False) self.data_q = Queue.Queue() self.error_q = Queue.Queue() self.com_monitor = ComMonitorThread( self.data_q, self.error_q, self.port, self.baudrate) self.com_monitor.start() com_error = get_item_from_queue(self.error_q) if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) update_freq = self.updatespeed_knob.value() if update_freq > 0: self.timer.start(1000.0 / update_freq) self.status_text.setText('Monitor running') debug('--> Monitor running') #------------------------------------------------------------ def OnStop(self): """ Stop the monitor """ if self.com_monitor is not None: self.com_monitor.join(1000) self.com_monitor = None self.monitor_active = False self.button_Connect.setEnabled(True) self.button_Disconnect.setEnabled(False) self.Com_ComboBox.setEnabled(True) self.timer.stop() self.status_text.setText('Monitor idle') debug('--> Monitor idle') #----------------------------------------------- def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.read_serial_data() self.update_monitor() #----------------------------------------------- def on_knob_change(self): """ When the knob is rotated, it sets the update interval of the timer. """ update_freq = self.updatespeed_knob.value() self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000.0 / update_freq) #----------------------------------------------- def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() self.csvdata.append([data['timestamp'], data['gx'], data['gy'], data['gz']] ) if len(self.csvdata) > self.max_spin.value(): f = open(time.strftime("%H%M%S")+".csv", 'wt') try: writer = csv.writer(f) for i in range(self.max_spin.value()): writer.writerow( self.csvdata[i] ) print 'transfer data to csv after 10000 samples' finally: f.close() self.csvdata = [] self.g_samples[0].append( (data['timestamp'], data['gx'])) if len(self.g_samples[0]) > 1000: self.g_samples[0].pop(0) self.g_samples[1].append( (data['timestamp'], data['gy'])) if len(self.g_samples[1]) > 1000: self.g_samples[1].pop(0) self.g_samples[2].append( (data['timestamp'], data['gz'])) if len(self.g_samples[2]) > 1000: self.g_samples[2].pop(0) tdata = [s[0] for s in self.g_samples[2]] for i in range(3): data[i] = [s[1] for s in self.g_samples[i]] if self.gcurveOn[i]: self.curve[i].setData(tdata, data[i]) """ debug("xdata", data[0]) debug("ydata", data[1]) debug("tdata", data[2]) """ #self.plot.setAxisScale(Qwt.QwtPlot.xBottom, tdata[0], max(10, tdata[-1]) ) self.plot.replot() #----------------------------------------------- def read_serial_data(self): """ Called periodically by the update timer to read data from the serial port. """ qdata = list(get_all_from_queue(self.data_q)) # get just the most recent data, others are lost #print "qdata" , qdata if len(qdata) > 0: data = dict(timestamp=qdata[-1][1], gx=qdata[-1][0][0], gy=qdata[-1][0][1], gz=qdata[-1][0][2] ) self.livefeed.add_data(data) #----------------------------------------------- # The following two methods are utilities for simpler creation # and assignment of actions # def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) #----------------------------------------------- def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action
class PlottingDataMonitor(QMainWindow): def __init__(self, parent=None): super(PlottingDataMonitor, self).__init__(parent) self.setWindowTitle('ADXL345 Realtime Monitor') self.resize(800, 600) self.port = "" self.baudrate = 9600 self.monitor_active = False # on/off monitor state self.com_monitor = None # monitor reception thread self.com_data_q = None self.com_error_q = None self.livefeed = LiveDataFeed() self.timer = QTimer() self.g_samples = [[], [], []] self.curve = [None]*3 self.gcurveOn = [1]*3 # by default all curve are plotted self.csvdata = [] self.create_menu() self.create_main_frame() self.create_status_bar() # Activate start-stop button connections self.connect(self.button_Connect, SIGNAL("clicked()"), self.OnStart) self.connect(self.button_Disconnect, SIGNAL("clicked()"), self.OnStop) #---------------------------------------------------------- def create_com_box(self): """ Purpose: create the serial com groupbox Return: return a layout of the serial com """ self.com_box = QGroupBox("COM Configuration") com_layout = QGridLayout() self.radio9600 = QRadioButton("9600") self.radio9600.setChecked(1) self.radio19200 = QRadioButton("19200") self.Com_ComboBox = QComboBox() com_layout.addWidget(self.Com_ComboBox,0,0,1,2) com_layout.addWidget(self.radio9600,1,0) com_layout.addWidget(self.radio19200,1,1) self.fill_ports_combobox() self.button_Connect = QPushButton("Start") self.button_Disconnect = QPushButton("Stop") self.button_Disconnect.setEnabled(False) com_layout.addWidget(self.button_Connect,0,2) com_layout.addWidget(self.button_Disconnect,1,2) return com_layout #--------------------------------------------------------------------- def create_plot(self): """ Purpose: create the pyqwt plot Return: return a list containing the plot and the list of the curves """ plot = Qwt.QwtPlot(self) plot.setCanvasBackground(Qt.black) plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time') plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Acceleration') plot.setAxisScale(Qwt.QwtPlot.yLeft, YMIN, YMAX, (YMAX-YMIN)/10) plot.replot() curve = [None]*3 pen = [QPen(QColor('limegreen')), QPen(QColor('red')) ,QPen(QColor('yellow')) ] for i in range(3): curve[i] = Qwt.QwtPlotCurve('') curve[i].setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) pen[i].setWidth(2) curve[i].setPen(pen[i]) curve[i].attach(plot) return plot, curve #--------------------------------------------------- def create_knob(self): """ Purpose: create a knob Return: return a the knob widget """ knob = Qwt.QwtKnob(self) knob.setRange(0, 180, 0, 1) knob.setScaleMaxMajor(10) knob.setKnobWidth(50) knob.setValue(10) return knob #--------------------------------------------------- def create_status_bar(self): self.status_text = QLabel('Monitor idle') self.statusBar().addWidget(self.status_text, 1) #--------------------------------------------------- def create_checkbox(self, label, color, connect_fn, connect_param): """ Purpose: create a personalized checkbox Input: the label, color, activated function and the transmitted parameter Return: return a checkbox widget """ checkBox = QCheckBox(label) checkBox.setChecked(1) checkBox.setFont( QFont("Arial", pointSize=12, weight=QFont.Bold ) ) green = QPalette() green.setColor(QPalette.Foreground, color) checkBox.setPalette(green) self.connect(checkBox, SIGNAL("clicked()"), partial(connect_fn,connect_param)) return checkBox #--------------------------------------------------- def create_main_frame(self): """ Purpose: create the main frame Qt widget """ # Serial communication combo box portname_layout = self.create_com_box() self.com_box.setLayout(portname_layout) # Update speed knob self.updatespeed_knob = self.create_knob() self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'), self.on_knob_change) self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value()) self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter) # Create the plot and curves self.plot, self.curve = self.create_plot() # Create the configuration horizontal panel self.max_spin = QSpinBox() self.max_spin.setMaximum(1000) self.max_spin.setValue(1000) spins_hbox = QHBoxLayout() spins_hbox.addWidget(QLabel('Save every')) spins_hbox.addWidget(self.max_spin) spins_hbox.addWidget( QLabel('Lines')) #spins_hbox.addStretch(1) self.gCheckBox = [ self.create_checkbox("Acceleration(x)", Qt.green, self.activate_curve, 0), self.create_checkbox("Acceleration(y)", Qt.red, self.activate_curve, 1), self.create_checkbox("Acceleration(z)", Qt.yellow, self.activate_curve, 2) ] self.button_clear = QPushButton("Clear screen") self.connect(self.button_clear, SIGNAL("clicked()"), self.clear_screen) # Place the horizontal panel widget plot_layout = QGridLayout() plot_layout.addWidget(self.plot,0,0,8,7) plot_layout.addWidget(self.gCheckBox[0],0,8) plot_layout.addWidget(self.gCheckBox[1],1,8) plot_layout.addWidget(self.gCheckBox[2],2,8) plot_layout.addWidget(self.button_clear,3,8) plot_layout.addLayout(spins_hbox,4,8) plot_layout.addWidget(self.updatespeed_knob,5,8) plot_layout.addWidget(self.knob_l,6,8) plot_groupbox = QGroupBox('Acceleration') plot_groupbox.setLayout(plot_layout) # Place the main frame and layout self.main_frame = QWidget() main_layout = QVBoxLayout() main_layout.addWidget(self.com_box) main_layout.addWidget(plot_groupbox) main_layout.addStretch(1) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) #---------------------------------------------------------------------- def clear_screen(self): g_samples[0] = [] #----------------------------- def activate_curve(self, axe): if self.gCheckBox[axe].isChecked(): self.gcurveOn[axe] = 1 else: self.gcurveOn[axe] = 0 #--------------------------------------- def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") selectport_action = self.create_action("Select COM &Port...", shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port") self.start_action = self.create_action("&Start monitor", shortcut="Ctrl+M", slot=self.OnStart, tip="Start the data monitor") self.stop_action = self.create_action("&Stop monitor", shortcut="Ctrl+T", slot=self.OnStop, tip="Stop the data monitor") exit_action = self.create_action("E&xit", slot=self.close, shortcut="Ctrl+X", tip="Exit the application") self.start_action.setEnabled(False) self.stop_action.setEnabled(False) self.add_actions(self.file_menu, ( selectport_action, self.start_action, self.stop_action, None, exit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the monitor') self.add_actions(self.help_menu, (about_action,)) #---------------------------------------------------------------------- def set_actions_enable_state(self): if self.portname.text() == '': start_enable = stop_enable = False else: start_enable = not self.monitor_active stop_enable = self.monitor_active self.start_action.setEnabled(start_enable) self.stop_action.setEnabled(stop_enable) #----------------------------------------------- def on_about(self): msg = __doc__ QMessageBox.about(self, "About the demo", msg.strip()) #----------------------------------------------- def on_select_port(self): ports = enumerate_serial_ports() if len(ports) == 0: QMessageBox.critical(self, 'No ports', 'No serial ports found') return item, ok = QInputDialog.getItem(self, 'Select a port', 'Serial port:', ports, 0, False) if ok and not item.isEmpty(): self.portname.setText(item) self.set_actions_enable_state() #----------------------------------------------- def fill_ports_combobox(self): """ Purpose: rescan the serial port com and update the combobox """ vNbCombo = "" self.Com_ComboBox.clear() self.AvailablePorts = enumerate_serial_ports() for value in self.AvailablePorts: self.Com_ComboBox.addItem(value) vNbCombo += value + " - " vNbCombo = vNbCombo[:-3] debug(("--> Les ports series disponibles sont: %s " % (vNbCombo))) #---------------------------------------------------------------------- def OnStart(self): """ Start the monitor: com_monitor thread and the update timer """ if self.radio19200.isChecked(): self.baudrate = 19200 print "--> baudrate is 19200 bps" if self.radio9600.isChecked(): self.baudrate = 9600 print "--> baudrate is 9600 bps" vNbCombo = self.Com_ComboBox.currentIndex() self.port = self.AvailablePorts[vNbCombo] self.button_Connect.setEnabled(False) self.button_Disconnect.setEnabled(True) self.Com_ComboBox.setEnabled(False) self.data_q = Queue.Queue() self.error_q = Queue.Queue() self.com_monitor = ComMonitorThread( self.data_q, self.error_q, self.port, self.baudrate) self.com_monitor.start() com_error = get_item_from_queue(self.error_q) if com_error is not None: QMessageBox.critical(self, 'ComMonitorThread error', com_error) self.com_monitor = None self.monitor_active = True self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) update_freq = self.updatespeed_knob.value() if update_freq > 0: self.timer.start(1000.0 / update_freq) self.status_text.setText('Monitor running') debug('--> Monitor running') #------------------------------------------------------------ def OnStop(self): """ Stop the monitor """ if self.com_monitor is not None: self.com_monitor.join(1000) self.com_monitor = None self.monitor_active = False self.button_Connect.setEnabled(True) self.button_Disconnect.setEnabled(False) self.Com_ComboBox.setEnabled(True) self.timer.stop() self.status_text.setText('Monitor idle') debug('--> Monitor idle') #----------------------------------------------- def on_timer(self): """ Executed periodically when the monitor update timer is fired. """ self.read_serial_data() self.update_monitor() #----------------------------------------------- def on_knob_change(self): """ When the knob is rotated, it sets the update interval of the timer. """ update_freq = self.updatespeed_knob.value() self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value()) if self.timer.isActive(): update_freq = max(0.01, update_freq) self.timer.setInterval(1000.0 / update_freq) #----------------------------------------------- def update_monitor(self): """ Updates the state of the monitor window with new data. The livefeed is used to find out whether new data was received since the last update. If not, nothing is updated. """ if self.livefeed.has_new_data: data = self.livefeed.read_data() self.csvdata.append([data['timestamp'], data['gx'], data['gy'], data['gz']] ) if len(self.csvdata) > self.max_spin.value(): f = open(time.strftime("%H%M%S")+".csv", 'wt') try: writer = csv.writer(f) for i in range(self.max_spin.value()): writer.writerow( self.csvdata[i] ) print 'transfert data to csv after 1000 samples' finally: f.close() self.csvdata = [] self.g_samples[0].append( (data['timestamp'], data['gx'])) if len(self.g_samples[0]) > 100: self.g_samples[0].pop(0) self.g_samples[1].append( (data['timestamp'], data['gy'])) if len(self.g_samples[1]) > 100: self.g_samples[1].pop(0) self.g_samples[2].append( (data['timestamp'], data['gz'])) if len(self.g_samples[2]) > 100: self.g_samples[2].pop(0) tdata = [s[0] for s in self.g_samples[2]] for i in range(3): data[i] = [s[1] for s in self.g_samples[i]] if self.gcurveOn[i]: self.curve[i].setData(tdata, data[i]) """ debug("xdata", data[0]) debug("ydata", data[1]) debug("tdata", data[2]) """ self.plot.setAxisScale(Qwt.QwtPlot.xBottom, tdata[0], max(5, tdata[-1]) ) self.plot.replot() #----------------------------------------------- def read_serial_data(self): """ Called periodically by the update timer to read data from the serial port. """ qdata = list(get_all_from_queue(self.data_q)) # get just the most recent data, others are lost #print "qdata" , qdata if len(qdata) > 0: data = dict(timestamp=qdata[-1][1], gx=qdata[-1][0][0], gy=qdata[-1][0][1], gz=qdata[-1][0][2] ) self.livefeed.add_data(data) #----------------------------------------------- # The following two methods are utilities for simpler creation # and assignment of actions # def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) #----------------------------------------------- def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action