コード例 #1
0
    def start_onClicked(self):
        """
        Start button pressed. Starts the communication between arduino and GUI.
        """
        if self.port_num == 'select port':
            print "Error! Select a port"
        else:
            self.active_reference_x1 = self.active_reference_x[1:]
            print self.active_reference_x1
            print "length: ", len(self.active_reference_x1)
            print "type: ", type(self.active_reference_x[1])
            # Create the instance of the Object
            self.com_monitor = ComProcess(self.active_reference_y, 8,
                                          self.data_q,
                                          self.error_q, self.gain_q,
                                          str(self.port_num), 115200)
            self.com_monitor.start()
            # Connect the timeout signal
            self.timer.timeout.connect(self.on_timer)
            # Start the timer
            self.timer.start(
                30
            )  # TODO: when you will read the Ts to change this '30' (to 2xTs?)

            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
コード例 #2
0
    def start_onClicked(self):

        """
        Start button pressed. Starts the communication between arduino and GUI.
        """
        if self.port_num == 'select port':
            print "Error! Select a port"
        else:
            self.active_reference_x1 = self.active_reference_x[1:]
            print self.active_reference_x1
            print "length: ",len(self.active_reference_x1)
            print "type: ", type(self.active_reference_x[1])
            # Create the instance of the Object
            self.com_monitor = ComProcess(self.active_reference_y, 8,
                                          self.data_q, self.error_q, self.gain_q,
                                          str(self.port_num), 115200)
            self.com_monitor.start()
            # Connect the timeout signal
            self.timer.timeout.connect(self.on_timer)
            # Start the timer
            self.timer.start(30)    # TODO: when you will read the Ts to change this '30' (to 2xTs?)

            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
コード例 #3
0
class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.port_num = 'select port'
        self.r = 0

        self.monitor_active = False
        self.com_monitor = None
        self.com_data_q = None
        self.com_error_q = None
        self.gain_q = multiprocessing.Queue(2)
        self.data_q = multiprocessing.Queue()
        self.error_q = multiprocessing.Queue()

        self.position = list()
        self.time = list()

        self.inputs_list = list()
        self.ports_list = []

        # Timer to create a periodic event and update the plot
        self.timer = QtCore.QTimer()
        # Value and range of each potentiometer - Limits are [value-range, value+range]
        self.p_value = 10
        self.p_range = 10
        self.p_step = 0.1
        # -----------------
        self.i_value = 10
        self.i_range = 10
        self.i_step = 0.1
        # -----------------
        self.d_value = 10
        self.d_range = 10
        self.d_step = 0.1

        self.initUI()

    def initUI(self):

        # Create StatusBar
        statusBar = QtGui.QStatusBar()

        self.input_names = list()

        self.active_reference_x = list()
        self.active_reference_y = list()
        self.active_reference_x1 = list()

        self.xs_list = list()
        self.ys_list = list()

        self.thread = QtCore.QThread()

        # Create frames
        self.plot_frame = QtGui.QFrame(self)
        self.plot_frame.setFrameShape(QtGui.QFrame.StyledPanel)
        self.knobs_frame = QtGui.QFrame(self)
        self.knobs_frame.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame3 = QtGui.QFrame(self)
        self.frame3.setFrameShape(QtGui.QFrame.StyledPanel)

        # Ports Combo Box
        self.port_combo = QtGui.QComboBox(self)
        self.port_combo.setEnabled(False)
        self.port_combo.addItem('Select port')
        # Reference signals Combo box
        self.ref_signals_combo = QtGui.QComboBox(self)
        self.ref_signals_combo.setEnabled(False)
        self.ref_signals_combo.addItem('Choose a Reference Signal')
        self.ref_signals_combo.activated[str].connect(self.on_reference_choice)
        '''--------------- Buttons ----------------'''
        # Start button
        self.start_button = QtGui.QPushButton('Start')
        self.start_button.setEnabled(False)
        self.start_button.clicked.connect(self.start_onClicked)
        #Stop button
        self.stop_button = QtGui.QPushButton('Stop')
        self.stop_button.setEnabled(False)
        self.stop_button.clicked.connect(self.stop_onClicked)
        # Scan Button
        self.scan_button = QtGui.QPushButton('Scan')
        self.scan_button.setEnabled(True)
        self.scan_button.clicked.connect(self.scan_onClicked)
        ''' ----------- FIGURE LAYOUT ------------'''
        # a figure instance to plot on
        self.figure = plt.figure()  #figsize=(3.0,2.0)

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        self.ax = self.figure.add_subplot(1, 1, 1)
        self.ax.set_xlabel('time (sec)')
        self.ax.set_ylabel('angle (deg)')
        self.ax.axis([0, 5, -20, 20])
        self.ax.grid()

        self.active_reference = Line2D([0, 5], [0, 0],
                                       linewidth=1.0,
                                       color='red')
        self.ax.add_line(self.active_reference)

        self.position_line = Line2D([0, 0], [0, 0],
                                    linewidth=1.0,
                                    color='black')

        # Figure with frame
        self.topLeft = QtGui.QHBoxLayout()
        self.topLeft.addWidget(self.canvas)
        self.plot_frame.setLayout(self.topLeft)
        ''' ----------- KNOBS LAYOUT ------------'''
        # Knobs
        self.knob1 = self.create_knob('P')
        self.knob2 = self.create_knob('I')
        self.knob3 = self.create_knob('D')

        # Input P
        self.textP = QtGui.QLineEdit()
        self.textP.setMaxLength(5)
        self.textP.setText(str(self.knob1.value()))
        self.labelP = QtGui.QLabel('P Gain:')

        # Input I
        self.textI = QtGui.QLineEdit()
        self.textI.setMaxLength(5)
        self.textI.setText(str(self.knob2.value()))
        self.labelI = QtGui.QLabel('I Gain:')

        # Input D
        self.textD = QtGui.QLineEdit()
        self.textD.setMaxLength(5)
        self.textD.setText(str(self.knob3.value()))
        self.labelD = QtGui.QLabel('D Gain:')

        # P/I/D Gain Layouts
        self.p_layout = self.create_knob_layout('P')
        self.i_layout = self.create_knob_layout('I')
        self.d_layout = self.create_knob_layout('D')

        # Final knobs layout
        self.knobs_layout = QtGui.QHBoxLayout()
        self.knobs_layout.addLayout(self.p_layout)
        self.knobs_layout.addLayout(self.i_layout)
        self.knobs_layout.addLayout(self.d_layout)
        self.knobs_frame.setLayout(self.knobs_layout)

        # Add LineEdit signals
        self.textP.returnPressed.connect(lambda: self.on_entered_pressed('P'))
        self.textI.returnPressed.connect(lambda: self.on_entered_pressed('I'))
        self.textD.returnPressed.connect(lambda: self.on_entered_pressed('D'))
        ''' ----------- Buttons/Combos LAYOUT ------------'''

        # port_combo plus start/stop buttons
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.start_button)
        hbox.addWidget(self.stop_button)

        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.scan_button)

        grid3 = QtGui.QGridLayout()
        grid3.addWidget(self.port_combo, 3, 0)
        grid3.addWidget(self.ref_signals_combo, 4, 0)
        grid3.addLayout(vbox, 5, 0)
        self.frame3.setLayout(grid3)
        ''' ----------- FINAL LAYOUT ------------'''
        grid = QtGui.QGridLayout()
        grid.addWidget(self.plot_frame, 0, 0, 3, 2)
        grid.addWidget(self.knobs_frame, 3, 0, 2, 2)
        grid.addWidget(self.frame3, 0, 3, 5, 1)
        ''' ----------- CENTRAL WIDGET ----------'''
        self.main_frame = QtGui.QWidget()
        self.main_frame.setLayout(grid)
        self.setCentralWidget(self.main_frame)

        self.create_menu()

        self.setGeometry(1000, 300, 700, 450)
        self.setWindowTitle('ServoTune')
        self.show()

    def create_knob(self, letter):

        self.knob = Qwt.QwtKnob(self)
        self.knob.setRange(0, 20, 0, 0.1)
        self.knob.setScaleMaxMajor(10)
        self.knob.setKnobWidth(40)
        self.knob.setValue(self.p_value)
        self.knob.setStep(self.p_step)
        self.knob.valueChanged.connect(lambda: self.on_slider_moved(letter))
        return self.knob

    def create_knob_layout(self, letter):
        layout = QtGui.QVBoxLayout()
        dummy_layout = QtGui.QHBoxLayout()

        if letter == 'P':
            layout.addWidget(self.knob1)
            dummy_layout.addWidget(self.labelP)
            dummy_layout.addWidget(self.textP)
        elif letter == 'I':
            layout.addWidget(self.knob2)
            dummy_layout.addWidget(self.labelI)
            dummy_layout.addWidget(self.textI)
        elif letter == 'D':
            layout.addWidget(self.knob3)
            dummy_layout.addWidget(self.labelD)
            dummy_layout.addWidget(self.textD)

        layout.addLayout(dummy_layout)
        return layout

    def scan_onClicked(self):
        # Search for connected Devices
        ports = glob.glob('/dev/tty[A-Za-z]*')
        for port in ports:
            try:
                s = serial.Serial(port)
                s.close()
                self.ports_list.append(port)
            except (OSError, serial.SerialException):
                pass

        self.port_combo.clear()  # Clear the combo list
        if len(self.ports_list) == 0:
            self.port_combo.addItem('No devices detected')
        else:
            self.port_combo.addItem('Select port')
            self.port_combo.setEnabled(True)

        for i in range(0, len(self.ports_list)):
            self.port_combo.addItem(str(self.ports_list[i]))
        # Signal
        self.port_combo.activated[str].connect(self.on_port_combo_Activated)

    def on_port_combo_Activated(self, text):

        self.port_num = text
        if text != 'select port':
            print 'You selected', self.port_num
            self.port_combo.setEnabled(False)
        if not self.port_combo.currentText() == "Select port" and not \
                        self.ref_signals_combo.currentText() == "Choose a Reference Signal":
            self.start_button.setEnabled(True)

    def start_onClicked(self):
        """
        Start button pressed. Starts the communication between arduino and GUI.
        """
        if self.port_num == 'select port':
            print "Error! Select a port"
        else:
            self.active_reference_x1 = self.active_reference_x[1:]
            print self.active_reference_x1
            print "length: ", len(self.active_reference_x1)
            print "type: ", type(self.active_reference_x[1])
            # Create the instance of the Object
            self.com_monitor = ComProcess(self.active_reference_y, 8,
                                          self.data_q,
                                          self.error_q, self.gain_q,
                                          str(self.port_num), 115200)
            self.com_monitor.start()
            # Connect the timeout signal
            self.timer.timeout.connect(self.on_timer)
            # Start the timer
            self.timer.start(
                30
            )  # TODO: when you will read the Ts to change this '30' (to 2xTs?)

            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)

    def on_timer(self):
        """Reads every 30 ms the data queue and updates the response Line2D."""

        qdata = list(self.get_all_from_Queue(self.data_q))
        for i in range(0, len(qdata)):
            # Get time and position from the Queue
            self.time.append(qdata[i][0])
            self.position.append(qdata[i][1])
            # Add them to the response Line2D
            self.position_line.set_data(self.time, self.position)
        # Add the response Line2D to the canvas and draw
        self.ax.add_line(self.position_line)
        self.canvas.draw()
        # Stop the timer after the reference signal is all sent
        if len(self.time) >= len(self.active_reference_x1):
            self.timer.stop()
            print "Sent all"

    def stop_onClicked(self):
        """
        Stop button clicked. Kills the process.
        """

        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.port_combo.setEnabled(True)
        # Kill the COM process
        self.com_monitor.join(0.01)

    def on_entered_pressed(self, letter):
        """
        Chane of value of knob by pressing enter.
            - Put the slider in the given value and set the limits to +/- range.
        """

        if letter == 'P':
            self.p_value = float(self.textP.text())
            self.knob1.setRange(self.p_value - self.p_range,
                                self.p_value + self.p_range, 0, 1)
            self.knob1.setStep(self.p_step)
            self.knob1.setValue(self.p_value)
        elif letter == 'I':
            self.i_value = float(self.textI.text())
            self.knob2.setRange(self.i_value - self.i_range,
                                self.i_value + self.i_range, 0, 1)
            self.knob2.setStep(self.i_step)
            self.knob2.setValue(self.i_value)
        elif letter == 'D':
            self.d_value = float(self.textD.text())
            self.knob3.setRange(self.d_value - self.d_range,
                                self.d_value + self.d_range, 0, 1)
            self.knob3.setStep(self.d_step)
            self.knob3.setValue(self.d_value)

    def on_slider_moved(self, letter):
        """
        On knob change:
            - update the according text line.
            - Clear the 'gain_q' Queue and update it.
        """

        if letter == 'P':
            val = self.knob1.value()
            self.textP.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('P')
            self.gain_q.put(val)
        elif letter == 'I':
            val = self.knob2.value()
            self.textI.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('I')
            self.gain_q.put(val)
        elif letter == 'D':
            val = self.knob3.value()
            self.textD.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('D')
            self.gain_q.put(val)

    def create_menu(self):
        # create Action (for now manually - later with method)
        exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit Application')
        exitAction.triggered.connect(QtGui.qApp.quit)
        # <Tools>
        p_knob = QtGui.QAction('&Knob(P)', self)
        p_knob.setShortcut('Ctrl+P')
        i_knob = QtGui.QAction('&Knob(I)', self)
        i_knob.setShortcut('Ctrl+I')
        d_knob = QtGui.QAction('&Knob(D)', self)
        d_knob.setShortcut('Ctrl+D')
        # Connect the signals/slots
        p_knob.triggered.connect(lambda: self.show_knobs_dialog('P'))
        i_knob.triggered.connect(lambda: self.show_knobs_dialog('I'))
        d_knob.triggered.connect(lambda: self.show_knobs_dialog('D'))
        # Input Signal creation - actions
        create_input = QtGui.QAction('&New Reference Signal', self)
        create_input.triggered.connect(self.create_new_signal)
        # Periodic Signal creation - actions
        create_periodic_input = QtGui.QAction('&New Periodic Reference Signal',
                                              self)
        create_periodic_input.triggered.connect(
            self.create_new_periodic_signal)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAction)
        toolsMenu = menubar.addMenu('&Tools')
        toolsMenu.addAction(p_knob)
        toolsMenu.addAction(i_knob)
        toolsMenu.addAction(d_knob)
        input_signal_menu = menubar.addMenu('&Signal')
        input_signal_menu.addAction(create_input)
        input_signal_menu.addAction(create_periodic_input)
        # fileMenu.addAction(toolsAction)

    def show_knobs_dialog(self, let):
        '''
        Opens the dialog to reconfigure the knob's range and/or variance
        '''
        #TODO fix this "bad" name
        self.knob_config = knobDialog.knobDialog(self, let)
        self.knob_config.show(
        )  # with show it is modeless dialog (doesn't block the mainWindow)
        self.knob_config.ok_button.clicked.connect(
            lambda: self.update_knob(let))

    def update_knob(self, let):
        if let == 'P':
            # print 'ep'
            self.p_range = float(self.knob_config.range_line.text())
            self.p_step = float(self.knob_config.variance_line.text())
            self.knob1.setRange(self.p_value - self.p_range,
                                self.p_value + self.p_range, 0, 1)
            self.knob1.setStep(self.p_step)
            self.knob1.setValue(self.knob1.value())
            # print rng, var
        elif let == 'I':
            self.i_range = float(self.knob_config.range_line.text())
            self.i_step = float(self.knob_config.variance_line.text())
            self.knob2.setRange(self.i_value - self.i_range,
                                self.i_value + self.i_range, 0, 1)
            self.knob2.setStep(self.i_step)
            self.knob2.setValue(self.knob2.value())
        elif let == 'D':
            self.d_range = float(self.knob_config.range_line.text())
            self.d_step = float(self.knob_config.variance_line.text())
            self.knob3.setRange(self.d_value - self.d_range,
                                self.d_value + self.d_range, 0, 1)
            self.knob3.setStep(self.d_step)
            self.knob3.setValue(self.knob3.value())

    def create_new_signal(self):
        self.input_config = inputDialog.new_inputDialog(self.inputs_list)
        self.input_config.show()
        self.input_config.ok_button.clicked.connect(self.get_input_data)

    def create_new_periodic_signal(self):
        self.input_periodic_config = inputDialog.new_periodic_dialog(
            self.inputs_list)
        self.input_periodic_config.show()
        self.input_periodic_config.ok_button.clicked.connect(
            self.get_input_periodic_data)

    def get_input_data(self):
        """
        Get from the new input dialog class, the x_data and the y_data
        """

        xs = self.input_config.xs
        ys = self.input_config.ys

        self.xs_list.append(xs)
        self.ys_list.append(ys)

        self.inputs_list = self.input_config.list
        self.ref_signals_combo.addItem(self.inputs_list[-1])

        # Enable the reference combo box
        if not self.ref_signals_combo.isEnabled():
            self.ref_signals_combo.setEnabled(True)

    def get_input_periodic_data(self):

        xs = self.input_periodic_config.xs
        ys = self.input_periodic_config.ys

        self.xs_list.append(xs)
        self.ys_list.append(ys)

        self.inputs_list = self.input_periodic_config.list
        self.ref_signals_combo.addItem(self.inputs_list[-1])

        # Enable the reference combo box
        if not self.ref_signals_combo.isEnabled():
            self.ref_signals_combo.setEnabled(True)

    def on_reference_choice(self, text):

        for i in range(len(self.inputs_list)):
            if self.inputs_list[i] == text:
                self.active_reference_x = self.xs_list[i]
                self.active_reference_y = self.ys_list[i]
                # Final signal to be sent to arduino
                self.active_reference.set_data(self.active_reference_x,
                                               self.active_reference_y)
                # Change the limits of the axis
                xmax = max(self.active_reference_x)
                ymax = max(self.active_reference_y)
                ymin = min(self.active_reference_y)
                self.ax.axis([0, xmax, ymin - 10, ymax + 10])
                self.canvas.draw()
                # Debugging
                print self.active_reference_x
                print "Length of reference to be sent: ", len(
                    self.active_reference_x)
        if not self.port_combo.currentText() == "Select port" and not \
                        self.ref_signals_combo.currentText() == "Choose a Reference Signal":
            self.start_button.setEnabled(True)

    def clear_queue(self, q):
        # if q.qsize()
        while q.qsize() > 0:
            trash = q.get()

    def get_all_from_Queue(self, Q):
        try:
            while True:
                yield Q.get_nowait()
        except Queue.Empty:
            raise StopIteration
コード例 #4
0
class MainWindow(QtGui.QMainWindow):

    def __init__(self):
        super(MainWindow,self).__init__()

        self.port_num = 'select port'
        self.r = 0

        self.monitor_active = False
        self.com_monitor = None
        self.com_data_q = None
        self.com_error_q = None
        self.gain_q = multiprocessing.Queue(2)
        self.data_q = multiprocessing.Queue()
        self.error_q = multiprocessing.Queue()

        self.position = list()
        self.time = list()

        self.inputs_list = list()
        self.ports_list = []


        # Timer to create a periodic event and update the plot
        self.timer = QtCore.QTimer()
        # Value and range of each potentiometer - Limits are [value-range, value+range]
        self.p_value = 10
        self.p_range = 10
        self.p_step = 0.1
        # -----------------
        self.i_value = 10
        self.i_range = 10
        self.i_step = 0.1
        # -----------------
        self.d_value = 10
        self.d_range = 10
        self.d_step = 0.1

        self.initUI()


    def initUI(self):

        # Create StatusBar
        statusBar = QtGui.QStatusBar()
        
        self.input_names = list()

        self.active_reference_x = list()
        self.active_reference_y = list()
        self.active_reference_x1 = list()


        self.xs_list = list()
        self.ys_list = list()

        self.thread = QtCore.QThread()

        # Create frames
        self.plot_frame = QtGui.QFrame(self)
        self.plot_frame.setFrameShape(QtGui.QFrame.StyledPanel)
        self.knobs_frame = QtGui.QFrame(self)
        self.knobs_frame.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame3 = QtGui.QFrame(self)
        self.frame3.setFrameShape(QtGui.QFrame.StyledPanel)

        # Ports Combo Box
        self.port_combo = QtGui.QComboBox(self)
        self.port_combo.setEnabled(False)
        self.port_combo.addItem('Select port')
        # Reference signals Combo box
        self.ref_signals_combo = QtGui.QComboBox(self)
        self.ref_signals_combo.setEnabled(False)
        self.ref_signals_combo.addItem('Choose a Reference Signal')
        self.ref_signals_combo.activated[str].connect(self.on_reference_choice)

        '''--------------- Buttons ----------------'''
        # Start button
        self.start_button = QtGui.QPushButton('Start')
        self.start_button.setEnabled(False)
        self.start_button.clicked.connect(self.start_onClicked)
        #Stop button
        self.stop_button = QtGui.QPushButton('Stop')
        self.stop_button.setEnabled(False)
        self.stop_button.clicked.connect(self.stop_onClicked)
        # Scan Button
        self.scan_button = QtGui.QPushButton('Scan')
        self.scan_button.setEnabled(True)
        self.scan_button.clicked.connect(self.scan_onClicked)

        ''' ----------- FIGURE LAYOUT ------------'''
        # a figure instance to plot on
        self.figure = plt.figure() #figsize=(3.0,2.0)

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        self.ax = self.figure.add_subplot(1,1,1)
        self.ax.set_xlabel('time (sec)')
        self.ax.set_ylabel('angle (deg)')
        self.ax.axis([0,5,-20,20])
        self.ax.grid()

        self.active_reference = Line2D([0,5],[0,0], linewidth=1.0, color='red')
        self.ax.add_line(self.active_reference)

        self.position_line = Line2D([0,0],[0,0],linewidth=1.0, color='black')

        # Figure with frame
        self.topLeft = QtGui.QHBoxLayout()
        self.topLeft.addWidget(self.canvas)
        self.plot_frame.setLayout(self.topLeft)

        ''' ----------- KNOBS LAYOUT ------------'''
        # Knobs
        self.knob1 = self.create_knob('P')
        self.knob2 = self.create_knob('I')
        self.knob3 = self.create_knob('D')

        # Input P
        self.textP = QtGui.QLineEdit()
        self.textP.setMaxLength(5)
        self.textP.setText(str(self.knob1.value()))
        self.labelP = QtGui.QLabel('P Gain:')

        # Input I
        self.textI = QtGui.QLineEdit()
        self.textI.setMaxLength(5)
        self.textI.setText(str(self.knob2.value()))
        self.labelI = QtGui.QLabel('I Gain:')

        # Input D
        self.textD = QtGui.QLineEdit()
        self.textD.setMaxLength(5)
        self.textD.setText(str(self.knob3.value()))
        self.labelD = QtGui.QLabel('D Gain:')

        # P/I/D Gain Layouts
        self.p_layout = self.create_knob_layout('P')
        self.i_layout = self.create_knob_layout('I')
        self.d_layout = self.create_knob_layout('D')

        # Final knobs layout
        self.knobs_layout = QtGui.QHBoxLayout()
        self.knobs_layout.addLayout(self.p_layout)
        self.knobs_layout.addLayout(self.i_layout)
        self.knobs_layout.addLayout(self.d_layout)
        self.knobs_frame.setLayout(self.knobs_layout)

        # Add LineEdit signals
        self.textP.returnPressed.connect(lambda: self.on_entered_pressed('P'))
        self.textI.returnPressed.connect(lambda: self.on_entered_pressed('I'))
        self.textD.returnPressed.connect(lambda: self.on_entered_pressed('D'))

        ''' ----------- Buttons/Combos LAYOUT ------------'''

        # port_combo plus start/stop buttons
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.start_button)
        hbox.addWidget(self.stop_button)

        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.scan_button)

        grid3 = QtGui.QGridLayout()
        grid3.addWidget(self.port_combo, 3, 0)
        grid3.addWidget(self.ref_signals_combo, 4, 0)
        grid3.addLayout(vbox, 5, 0)
        self.frame3.setLayout(grid3)

        ''' ----------- FINAL LAYOUT ------------'''
        grid = QtGui.QGridLayout()
        grid.addWidget(self.plot_frame,0,0,3,2)
        grid.addWidget(self.knobs_frame,3,0,2,2)
        grid.addWidget(self.frame3,0,3,5,1)

        ''' ----------- CENTRAL WIDGET ----------'''
        self.main_frame = QtGui.QWidget()
        self.main_frame.setLayout(grid)
        self.setCentralWidget(self.main_frame)

        self.create_menu()

        self.setGeometry(1000,300,700,450)
        self.setWindowTitle('ServoTune')
        self.show()


    def create_knob(self,letter):

        self.knob = Qwt.QwtKnob(self)
        self.knob.setRange(0, 20, 0, 0.1)
        self.knob.setScaleMaxMajor(10)
        self.knob.setKnobWidth(40)
        self.knob.setValue(self.p_value)
        self.knob.setStep(self.p_step)
        self.knob.valueChanged.connect(lambda: self.on_slider_moved(letter))
        return self.knob

    def create_knob_layout(self,letter):
        layout = QtGui.QVBoxLayout()
        dummy_layout = QtGui.QHBoxLayout()

        if letter == 'P':
            layout.addWidget(self.knob1)
            dummy_layout.addWidget(self.labelP)
            dummy_layout.addWidget(self.textP)
        elif letter == 'I':
            layout.addWidget(self.knob2)
            dummy_layout.addWidget(self.labelI)
            dummy_layout.addWidget(self.textI)
        elif letter == 'D':
            layout.addWidget(self.knob3)
            dummy_layout.addWidget(self.labelD)
            dummy_layout.addWidget(self.textD)

        layout.addLayout(dummy_layout)
        return layout

    def scan_onClicked(self):
        # Search for connected Devices
        ports = glob.glob('/dev/tty[A-Za-z]*')
        for port in ports:
            try:
                s = serial.Serial(port)
                s.close()
                self.ports_list.append(port)
            except (OSError, serial.SerialException):
                pass

        self.port_combo.clear() # Clear the combo list
        if len(self.ports_list) == 0:
            self.port_combo.addItem('No devices detected')
        else:
            self.port_combo.addItem('Select port')
            self.port_combo.setEnabled(True)

        for i in range(0,len(self.ports_list)):
            self.port_combo.addItem(str(self.ports_list[i]))
        # Signal
        self.port_combo.activated[str].connect(self.on_port_combo_Activated)

    def on_port_combo_Activated(self, text):

        self.port_num = text
        if text != 'select port':
            print 'You selected' , self.port_num
            self.port_combo.setEnabled(False)
        if not self.port_combo.currentText() == "Select port" and not \
                        self.ref_signals_combo.currentText() == "Choose a Reference Signal":
            self.start_button.setEnabled(True)

    def start_onClicked(self):

        """
        Start button pressed. Starts the communication between arduino and GUI.
        """
        if self.port_num == 'select port':
            print "Error! Select a port"
        else:
            self.active_reference_x1 = self.active_reference_x[1:]
            print self.active_reference_x1
            print "length: ",len(self.active_reference_x1)
            print "type: ", type(self.active_reference_x[1])
            # Create the instance of the Object
            self.com_monitor = ComProcess(self.active_reference_y, 8,
                                          self.data_q, self.error_q, self.gain_q,
                                          str(self.port_num), 115200)
            self.com_monitor.start()
            # Connect the timeout signal
            self.timer.timeout.connect(self.on_timer)
            # Start the timer
            self.timer.start(30)    # TODO: when you will read the Ts to change this '30' (to 2xTs?)

            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)

    def on_timer(self):

        """Reads every 30 ms the data queue and updates the response Line2D."""

        qdata = list(self.get_all_from_Queue(self.data_q))
        for i in range(0, len(qdata)):
            # Get time and position from the Queue
            self.time.append(qdata[i][0])
            self.position.append(qdata[i][1])
            # Add them to the response Line2D
            self.position_line.set_data(self.time, self.position)
        # Add the response Line2D to the canvas and draw
        self.ax.add_line(self.position_line)
        self.canvas.draw()
        # Stop the timer after the reference signal is all sent
        if len(self.time) >= len(self.active_reference_x1):
            self.timer.stop()
            print "Sent all"


    def stop_onClicked(self):
        """
        Stop button clicked. Kills the process.
        """

        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.port_combo.setEnabled(True)
        # Kill the COM process
        self.com_monitor.join(0.01)

    def on_entered_pressed(self, letter):

        """
        Chane of value of knob by pressing enter.
            - Put the slider in the given value and set the limits to +/- range.
        """

        if letter == 'P':
            self.p_value = float(self.textP.text())
            self.knob1.setRange(self.p_value-self.p_range, self.p_value+self.p_range, 0, 1)
            self.knob1.setStep(self.p_step)
            self.knob1.setValue(self.p_value)
        elif letter == 'I':
            self.i_value = float(self.textI.text())
            self.knob2.setRange(self.i_value-self.i_range, self.i_value+self.i_range, 0, 1)
            self.knob2.setStep(self.i_step)
            self.knob2.setValue(self.i_value)
        elif letter == 'D':
            self.d_value = float(self.textD.text())
            self.knob3.setRange(self.d_value-self.d_range, self.d_value+self.d_range, 0, 1)
            self.knob3.setStep(self.d_step)
            self.knob3.setValue(self.d_value)

    def on_slider_moved(self, letter):
        """
        On knob change:
            - update the according text line.
            - Clear the 'gain_q' Queue and update it.
        """

        if letter == 'P':
            val = self.knob1.value()
            self.textP.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('P')
            self.gain_q.put(val)
        elif letter == 'I':
            val = self.knob2.value()
            self.textI.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('I')
            self.gain_q.put(val)
        elif letter == 'D':
            val = self.knob3.value()
            self.textD.setText(str(val))
            # clear the gain queue
            self.clear_queue(self.gain_q)
            # Add let + value
            self.gain_q.put('D')
            self.gain_q.put(val)

    def create_menu(self):
        # create Action (for now manually - later with method)
        exitAction = QtGui.QAction(QtGui.QIcon('exit.png'),'&Exit',self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit Application')
        exitAction.triggered.connect(QtGui.qApp.quit)
        # <Tools>
        p_knob = QtGui.QAction('&Knob(P)', self)
        p_knob.setShortcut('Ctrl+P')
        i_knob = QtGui.QAction('&Knob(I)', self)
        i_knob.setShortcut('Ctrl+I')
        d_knob = QtGui.QAction('&Knob(D)', self)
        d_knob.setShortcut('Ctrl+D')
        # Connect the signals/slots
        p_knob.triggered.connect(lambda: self.show_knobs_dialog('P'))
        i_knob.triggered.connect(lambda: self.show_knobs_dialog('I'))
        d_knob.triggered.connect(lambda: self.show_knobs_dialog('D'))
        # Input Signal creation - actions
        create_input = QtGui.QAction('&New Reference Signal',self)
        create_input.triggered.connect(self.create_new_signal)
        # Periodic Signal creation - actions
        create_periodic_input = QtGui.QAction('&New Periodic Reference Signal', self)
        create_periodic_input.triggered.connect(self.create_new_periodic_signal)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAction)
        toolsMenu = menubar.addMenu('&Tools')
        toolsMenu.addAction(p_knob)
        toolsMenu.addAction(i_knob)
        toolsMenu.addAction(d_knob)
        input_signal_menu = menubar.addMenu('&Signal')
        input_signal_menu.addAction(create_input)
        input_signal_menu.addAction(create_periodic_input)
        # fileMenu.addAction(toolsAction)

    def show_knobs_dialog(self,let):
        '''
        Opens the dialog to reconfigure the knob's range and/or variance
        '''
        #TODO fix this "bad" name
        self.knob_config = knobDialog.knobDialog(self,let)
        self.knob_config.show()  # with show it is modeless dialog (doesn't block the mainWindow)
        self.knob_config.ok_button.clicked.connect(lambda: self.update_knob(let))

    def update_knob(self, let):
        if let == 'P':
            # print 'ep'
            self.p_range = float(self.knob_config.range_line.text())
            self.p_step = float(self.knob_config.variance_line.text())
            self.knob1.setRange(self.p_value-self.p_range, self.p_value+self.p_range, 0, 1)
            self.knob1.setStep(self.p_step)
            self.knob1.setValue(self.knob1.value())
            # print rng, var
        elif let == 'I':
            self.i_range = float(self.knob_config.range_line.text())
            self.i_step = float(self.knob_config.variance_line.text())
            self.knob2.setRange(self.i_value-self.i_range, self.i_value+self.i_range, 0, 1)
            self.knob2.setStep(self.i_step)
            self.knob2.setValue(self.knob2.value())
        elif let == 'D':
            self.d_range = float(self.knob_config.range_line.text())
            self.d_step = float(self.knob_config.variance_line.text())
            self.knob3.setRange(self.d_value-self.d_range, self.d_value+self.d_range, 0, 1)
            self.knob3.setStep(self.d_step)
            self.knob3.setValue(self.knob3.value())

    def create_new_signal(self):
        self.input_config = inputDialog.new_inputDialog(self.inputs_list)
        self.input_config.show()
        self.input_config.ok_button.clicked.connect(self.get_input_data)

    def create_new_periodic_signal(self):
        self.input_periodic_config = inputDialog.new_periodic_dialog(self.inputs_list)
        self.input_periodic_config.show()
        self.input_periodic_config.ok_button.clicked.connect(self.get_input_periodic_data)

    def get_input_data(self):
        """
        Get from the new input dialog class, the x_data and the y_data
        """

        xs = self.input_config.xs
        ys = self.input_config.ys

        self.xs_list.append(xs)
        self.ys_list.append(ys)

        self.inputs_list = self.input_config.list
        self.ref_signals_combo.addItem(self.inputs_list[-1])

        # Enable the reference combo box
        if not self.ref_signals_combo.isEnabled():
            self.ref_signals_combo.setEnabled(True)

    def get_input_periodic_data(self):

        xs = self.input_periodic_config.xs
        ys = self.input_periodic_config.ys

        self.xs_list.append(xs)
        self.ys_list.append(ys)

        self.inputs_list = self.input_periodic_config.list
        self.ref_signals_combo.addItem(self.inputs_list[-1])

        # Enable the reference combo box
        if not self.ref_signals_combo.isEnabled():
            self.ref_signals_combo.setEnabled(True)

    def on_reference_choice(self, text):

        for i in range(len(self.inputs_list)):
            if self.inputs_list[i] == text:
                self.active_reference_x = self.xs_list[i]
                self.active_reference_y = self.ys_list[i]
                # Final signal to be sent to arduino
                self.active_reference.set_data(self.active_reference_x,self.active_reference_y)
                # Change the limits of the axis
                xmax = max(self.active_reference_x)
                ymax = max(self.active_reference_y)
                ymin = min(self.active_reference_y)
                self.ax.axis([0, xmax, ymin-10, ymax+10])
                self.canvas.draw()
                # Debugging
                print self.active_reference_x
                print "Length of reference to be sent: ", len(self.active_reference_x)
        if not self.port_combo.currentText() == "Select port" and not \
                        self.ref_signals_combo.currentText() == "Choose a Reference Signal":
            self.start_button.setEnabled(True)


    def clear_queue(self, q):
        # if q.qsize()
        while q.qsize()>0:
            trash = q.get()

    def get_all_from_Queue(self, Q):
        try:
            while True:
                yield Q.get_nowait()
        except Queue.Empty:
            raise StopIteration