Exemplo n.º 1
0
 def setupRealTimePlot(self):
     self.realTimePlot = CustomFigCanvas()
     self.LAYOUT_A.addWidget(self.realTimePlot,
                             *(0,
                               0))  # put the preview window in the layout
     self.btn_zoom.clicked.connect(
         self.realTimePlot.zoom)  # connect qt signal to zoom funcion
Exemplo n.º 2
0
class GUI(QMainWindow,Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self,None,Qt.WindowStaysOnTopHint)
        Ui_MainWindow.__init__(self)
        self.updateRate = 15 # (ms) update rate of the GUI, vision, plot
        self.setupUi(self)
        self.setupTimer()
        try:
            joystick
        except NameError:
            self.setupSubThread(field,vision,vision2)
        else:
            self.setupSubThread(field,vision,joystick)
        self.setupRealTimePlot() # comment ou this line if you don't want a preview window
        self.connectSignals()
        self.linkWidgets()

    #=====================================================
    # [override] terminate the subThread and clear currents when closing the window
    #=====================================================
    def closeEvent(self,event):
        self.thrd.stop()
        self.timer.stop()
        vision.closeCamera()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.closeCamera()
        try:
            joystick
        except NameError:
            pass
        else:
            joystick.quit()
        self.clearField()
        event.accept()

    #=====================================================
    # QTimer handles updates of the GUI, run at 60Hz
    #=====================================================
    def setupTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(self.updateRate) # msec

    def update(self):
        vision.updateFrame()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.updateFrame()
        try:
            self.realTimePlot
        except AttributeError:
            pass
        else:
            self.updatePlot()
        try:
            joystick
        except NameError:
            pass
        else:
            joystick.update()



    #=====================================================
    # Connect buttons etc. of the GUI to callback functions
    #=====================================================
    def connectSignals(self):
        # General Control Tab
        self.dsb_x.valueChanged.connect(self.setFieldXYZ)
        self.dsb_y.valueChanged.connect(self.setFieldXYZ)
        self.dsb_z.valueChanged.connect(self.setFieldXYZ)
        self.btn_clearCurrent.clicked.connect(self.clearField)
        self.dsb_xGradient.valueChanged.connect(self.setFieldXYZGradient)
        self.dsb_yGradient.valueChanged.connect(self.setFieldXYZGradient)
        self.dsb_zGradient.valueChanged.connect(self.setFieldXYZGradient)
        # Vision Tab
        self.highlighter = syntax.Highlighter(self.editor_vision.document())
        self.chb_bypassFilters.toggled.connect(self.on_chb_bypassFilters)
        self.btn_refreshFilterRouting.clicked.connect(self.on_btn_refreshFilterRouting)
        self.btn_snapshot.clicked.connect(self.on_btn_snapshot)
        # object detection
        self.chb_objectDetection.toggled.connect(self.on_chb_objectDetection)
        # Subthread Tab
        self.cbb_subThread.currentTextChanged.connect(self.on_cbb_subThread)
        self.cbb_subThread.currentTextChanged.connect(self.on_chb_changeSubthread)
        self.cbb_subThread.currentTextChanged.connect(self.on_chb_switchSubthread)
        self.chb_startStopSubthread.toggled.connect(self.on_chb_startStopSubthread)
        self.dsb_subThreadParam0.valueChanged.connect(self.thrd.setParam0)
        self.dsb_subThreadParam1.valueChanged.connect(self.thrd.setParam1)
        self.dsb_subThreadParam2.valueChanged.connect(self.thrd.setParam2)
        self.dsb_subThreadParam3.valueChanged.connect(self.thrd.setParam3)
        self.dsb_subThreadParam4.valueChanged.connect(self.thrd.setParam4)
        self.dsb_desiredSeparation.valueChanged.connect(self.setDesiredSeparation)


    #=====================================================
    # Link GUI elements
    #=====================================================
    def linkWidgets(self):
        # link slider to doubleSpinBox
        self.dsb_x.valueChanged.connect(lambda value: self.hsld_x.setValue(int(value*100)))
        self.dsb_y.valueChanged.connect(lambda value: self.hsld_y.setValue(int(value*100)))
        self.dsb_z.valueChanged.connect(lambda value: self.hsld_z.setValue(int(value*100)))
        self.hsld_x.valueChanged.connect(lambda value: self.dsb_x.setValue(float(value/100)))
        self.hsld_y.valueChanged.connect(lambda value: self.dsb_y.setValue(float(value/100)))
        self.hsld_z.valueChanged.connect(lambda value: self.dsb_z.setValue(float(value/100)))

        self.dsb_xGradient.valueChanged.connect(lambda value: self.hsld_xGradient.setValue(int(value*100)))
        self.dsb_yGradient.valueChanged.connect(lambda value: self.hsld_yGradient.setValue(int(value*100)))
        self.dsb_zGradient.valueChanged.connect(lambda value: self.hsld_zGradient.setValue(int(value*100)))
        self.hsld_xGradient.valueChanged.connect(lambda value: self.dsb_xGradient.setValue(float(value/100)))
        self.hsld_yGradient.valueChanged.connect(lambda value: self.dsb_yGradient.setValue(float(value/100)))
        self.hsld_zGradient.valueChanged.connect(lambda value: self.dsb_zGradient.setValue(float(value/100)))
    #=====================================================
    # Thread Example
    #=====================================================
    def setupSubThread(self,field,vision,vision2,joystick=None):
        if joystick:
            self.thrd = SubThread(field,vision,vision2,joystick)
        else:
            self.thrd = SubThread(field,vision,vision2)
        self.thrd.statusSignal.connect(self.updateSubThreadStatus)
        self.thrd.finished.connect(self.finishSubThreadProcess)

    # updating GUI according to the status of the subthread
    @pyqtSlot(str)
    def updateSubThreadStatus(self, receivedStr):
        print('Received message from subthread: ',receivedStr)
        # show something on GUI

    # run when the subthread is termianted
    @pyqtSlot()
    def finishSubThreadProcess(self):
        print('Subthread is terminated.')

        vision.clearDrawingRouting()
        self.clearField()
        # disable some buttons etc.

    #=====================================================
    # Real time plot
    # This is showing actual coil current that is stored in field.x, field.y, field.z
    # Note: the figure is updating at the speed of self.updateRate defined in _init_
    #=====================================================
    def setupRealTimePlot(self):
        self.realTimePlot = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.realTimePlot, *(0,0)) # put the preview window in the layout
        self.btn_zoom.clicked.connect(self.realTimePlot.zoom) # connect qt signal to zoom funcion

    def updatePlot(self):
        #print(field.y)
        self.realTimePlot.addDataX(field.x)
        self.realTimePlot.addDataY(field.y)
        self.realTimePlot.addDataZ(field.z)

    #=====================================================
    # Callback Functions
    #=====================================================
    # General control tab
    def setFieldXYZ(self):
        field.setX(self.dsb_x.value())
        field.setY(self.dsb_y.value())
        field.setZ(self.dsb_z.value())
        field.setMagnitude(round(sqrt(pow(self.dsb_x.value(),2)+pow(self.dsb_y.value(),2)+pow(self.dsb_z.value(),2)),2))

    def clearField(self):
        self.dsb_x.setValue(0)
        self.dsb_y.setValue(0)
        self.dsb_z.setValue(0)
        self.dsb_xGradient.setValue(0)
        self.dsb_yGradient.setValue(0)
        self.dsb_zGradient.setValue(0)
        field.setXYZ(0,0,0)

    def setFieldXYZGradient(self):
        field.setXGradient(10,self.dsb_xGradient.value())
        field.setYGradient(10,self.dsb_yGradient.value())
        field.setZGradient(10,self.dsb_zGradient.value())
        field.setMagnitude(0)

    # vision tab
    def on_chb_bypassFilters(self,state):
        vision.setStateFiltersBypassed(state)
        vision2.setStateFiltersBypassed(state)

    def on_btn_refreshFilterRouting(self):
        vision.createFilterRouting(self.editor_vision.toPlainText().splitlines())
        vision2.createFilterRouting(self.editor_vision.toPlainText().splitlines())

    def on_btn_snapshot(self):
        vision.setStateSnapshotEnabled(True)
        vision2.setStateSnapshotEnabled(True)

    def on_chb_objectDetection(self,state):
        algorithm = self.cbb_objectDetectionAlgorithm.currentText()
        vision.setStateObjectDetection(state,algorithm)
        vision2.setStateObjectDetection(state,algorithm)
        self.cbb_objectDetectionAlgorithm.setEnabled(not state)
        vision.clearAgentDrawing(state)
        vision2.clearAgentDrawing(state)

    # subthread
    def on_cbb_subThread(self,subThreadName):
        # an array that stores the name for params. Return param0, param1, ... if not defined.
        labelNames = self.thrd.labelOnGui.get(subThreadName,self.thrd.labelOnGui['default'])
        minVals = self.thrd.minOnGui.get(subThreadName,self.thrd.minOnGui['default'])
        maxVals = self.thrd.maxOnGui.get(subThreadName,self.thrd.maxOnGui['default'])
        defaultVals = self.thrd.defaultValOnGui.get(subThreadName,self.thrd.defaultValOnGui['default'])
        for i in range(5):
            targetLabel = 'lbl_subThreadParam' + str(i)
            targetSpinbox = 'dsb_subThreadParam' + str(i)
            getattr(self,targetLabel).setText(labelNames[i])
            getattr(self,targetSpinbox).setMinimum(minVals[i])
            getattr(self,targetSpinbox).setMaximum(maxVals[i])
            getattr(self,targetSpinbox).setValue(defaultVals[i])


    def on_chb_startStopSubthread(self,state):
        subThreadName = self.cbb_subThread.currentText()
        if state:
            self.cbb_subThread.setEnabled(True)
            self.thrd.setup(subThreadName)
            self.thrd.start()
            print('Subthread "{}" starts.'.format(subThreadName))
        else:
            self.cbb_subThread.setEnabled(True)
            field.setFrequency(0)
            field.setMagnitude(0)
            vision.setOrientation(None)
            vision.setSeparation(None)
            self.thrd.stop()

    def on_chb_changeSubthread(self): #use this fcn to stop current subthread
        subThreadName = self.cbb_subThread.currentText()
        if self.chb_startStopSubthread.isChecked() == True:
            self.thrd.stop()
            #print('Subthread "{}" starts.'.format(subThreadName))

    def on_chb_switchSubthread(self): #use this fcn to start new subthread
        subThreadName = self.cbb_subThread.currentText()
        if self.chb_startStopSubthread.isChecked() == True:
            time.sleep(0.1) #use time lag to achieve stop -> restart in order
            self.thrd.setup(subThreadName)
            self.thrd.start()
            print('Subthread "{}" starts.'.format(subThreadName))

    def setDesiredSeparation(self,val):
        vision.setSeparation(val)
Exemplo n.º 3
0
class GUI(QMainWindow, Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self, None, Qt.WindowStaysOnTopHint)
        Ui_MainWindow.__init__(self)
        self.updateRate = 15  # (ms) update rate of the GUI, vision, plot
        self.setupUi(self)
        self.setupTimer()
        try:
            joystick
        except NameError:
            self.setupSubThread(field, vision)
        else:
            self.setupSubThread(field, vision, joystick)
        # comment ou this line if you don't want a preview window
        self.setupRealTimePlot()
        self.connectSignals()
        self.linkWidgets()
        self.initDataBuffers()

    #=====================================================
    # [override] terminate the subThread and clear currents when closing the
    # window
    #=====================================================
    def closeEvent(self, event):
        self.thrd.stop()
        self.timer.stop()
        vision.closeCamera()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.closeCamera()
        try:
            joystick
        except NameError:
            pass
        else:
            joystick.quit()
        self.clearField()
        event.accept()

    #=====================================================
    # QTimer handles updates of the GUI, run at 60Hz
    #=====================================================
    def setupTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(self.updateRate)  # msec

    def update(self):
        vision.updateFrame()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.updateFrame()
        try:
            self.realTimePlot
        except AttributeError:
            pass
        else:
            self.updatePlot()
        try:
            joystick
        except NameError:
            pass
        else:
            joystick.update()

    #=====================================================
    # Connect buttons etc. of the GUI to callback functions
    #=====================================================
    def connectSignals(self):
        # General Control Tab
        self.dsb_x.valueChanged.connect(self.setFieldXYZ)
        self.dsb_y.valueChanged.connect(self.setFieldXYZ)
        self.dsb_z.valueChanged.connect(self.setFieldXYZ)
        self.btn_clearCurrent.clicked.connect(self.clearField)
        self.dsb_xGradient.valueChanged.connect(self.setFieldXYZGradient)
        self.dsb_yGradient.valueChanged.connect(self.setFieldXYZGradient)
        self.dsb_zGradient.valueChanged.connect(self.setFieldXYZGradient)
        # Vision Tab
        self.highlighter = syntax.Highlighter(self.editor_vision.document())
        self.chb_bypassFilters.toggled.connect(self.on_chb_bypassFilters)
        self.btn_refreshFilterRouting.clicked.connect(
            self.on_btn_refreshFilterRouting)
        self.btn_snapshot.clicked.connect(self.on_btn_snapshot)
        # object detection
        self.chb_objectDetection.toggled.connect(self.on_chb_objectDetection)
        # Subthread Tab
        self.cbb_subThread.currentTextChanged.connect(self.on_cbb_subThread)
        self.chb_startStopSubthread.toggled.connect(
            self.on_chb_startStopSubthread)
        self.dsb_subThreadParam0.valueChanged.connect(self.thrd.setParam0)
        self.dsb_subThreadParam1.valueChanged.connect(self.thrd.setParam1)
        self.dsb_subThreadParam2.valueChanged.connect(self.thrd.setParam2)
        self.dsb_subThreadParam3.valueChanged.connect(self.thrd.setParam3)
        self.dsb_subThreadParam4.valueChanged.connect(self.thrd.setParam4)

    #=====================================================
    # Link GUI elements
    #=====================================================
    def linkWidgets(self):
        # link slider to doubleSpinBox
        self.dsb_x.valueChanged.connect(
            lambda value: self.hsld_x.setValue(int(value * 100)))
        self.dsb_y.valueChanged.connect(
            lambda value: self.hsld_y.setValue(int(value * 100)))
        self.dsb_z.valueChanged.connect(
            lambda value: self.hsld_z.setValue(int(value * 100)))
        self.hsld_x.valueChanged.connect(
            lambda value: self.dsb_x.setValue(float(value / 100)))
        self.hsld_y.valueChanged.connect(
            lambda value: self.dsb_y.setValue(float(value / 100)))
        self.hsld_z.valueChanged.connect(
            lambda value: self.dsb_z.setValue(float(value / 100)))

        self.dsb_xGradient.valueChanged.connect(
            lambda value: self.hsld_xGradient.setValue(int(value * 100)))
        self.dsb_yGradient.valueChanged.connect(
            lambda value: self.hsld_yGradient.setValue(int(value * 100)))
        self.dsb_zGradient.valueChanged.connect(
            lambda value: self.hsld_zGradient.setValue(int(value * 100)))
        self.hsld_xGradient.valueChanged.connect(
            lambda value: self.dsb_xGradient.setValue(float(value / 100)))
        self.hsld_yGradient.valueChanged.connect(
            lambda value: self.dsb_yGradient.setValue(float(value / 100)))
        self.hsld_zGradient.valueChanged.connect(
            lambda value: self.dsb_zGradient.setValue(float(value / 100)))

    #=====================================================
    # Thread Example
    #=====================================================
    def setupSubThread(self, field, vision, joystick=None):
        if joystick:
            self.thrd = SubThread(field, vision, joystick)
        else:
            self.thrd = SubThread(field, vision)
        self.thrd.statusSignal.connect(self.updateSubThreadStatus)
        self.thrd.finished.connect(self.finishSubThreadProcess)

    # updating GUI according to the status of the subthread
    @pyqtSlot(str)
    def updateSubThreadStatus(self, receivedStr):
        print('Received message from subthread: ', receivedStr)
        # show something on GUI

    # run when the subthread is termianted
    @pyqtSlot()
    def finishSubThreadProcess(self):
        print('Subthread is terminated.')

        vision.clearDrawingRouting()
        self.clearField()
        # disable some buttons etc.

    #=====================================================
    # Real time plot
    # This is showing requested flux density that is stored in
    # field.bxSetpoint, field.bySetpoint, field.bzSetpoint
    # Note: the figure is updating at the speed of self.updateRate defined in
    # __init__.
    #=====================================================
    def setupRealTimePlot(self):
        self.realTimePlot = CustomFigCanvas()
        # put the preview window in the layout
        self.LAYOUT_A.addWidget(self.realTimePlot, *(0, 0))
        # connect qt signal to zoom funcion
        self.btn_zoom.clicked.connect(self.realTimePlot.zoom)

    def updatePlot(self):
        # Update the measured coil currents and estimated field values
        field.getXYZ()
        # Update the values on the plot
        self.realTimePlot.addDataX(field.bxEstimate)
        self.realTimePlot.addDataY(field.byEstimate)
        self.realTimePlot.addDataZ(field.bzEstimate)
        # Filter the monitor values for easier viewing
        self.ix1Buf[0] = field.ix1
        self.ix1Buf = np.roll(self.ix1Buf, 1)
        self.ix2Buf[0] = field.ix2
        self.ix2Buf = np.roll(self.ix2Buf, 1)
        self.iy1Buf[0] = field.iy1
        self.iy1Buf = np.roll(self.iy1Buf, 1)
        self.iy2Buf[0] = field.iy2
        self.iy2Buf = np.roll(self.iy2Buf, 1)
        self.iz1Buf[0] = field.iz1
        self.iz1Buf = np.roll(self.iz1Buf, 1)
        self.iz2Buf[0] = field.iz2
        self.iz2Buf = np.roll(self.iz2Buf, 1)
        self.bxEstBuf[0] = field.bxEstimate
        self.bxEstBuf = np.roll(self.bxEstBuf, 1)
        self.byEstBuf[0] = field.byEstimate
        self.byEstBuf = np.roll(self.byEstBuf, 1)
        self.bzEstBuf[0] = field.bzEstimate
        self.bzEstBuf = np.roll(self.bzEstBuf, 1)
        # Update the monitor values for the currents and fields
        self.label_x1.setText('{0:0.1f}'.format(np.mean(self.ix1Buf)))
        self.label_x2.setText('{0:0.1f}'.format(np.mean(self.ix2Buf)))
        self.label_xBreq.setText('{0:0.1f}'.format(field.bxSetpoint))
        self.label_xBact.setText('{0:0.1f}'.format(np.mean(self.bxEstBuf)))
        self.label_y1.setText('{0:0.1f}'.format(np.mean(self.iy1Buf)))
        self.label_y2.setText('{0:0.1f}'.format(np.mean(self.iy2Buf)))
        self.label_yBreq.setText('{0:0.1f}'.format(field.bySetpoint))
        self.label_yBact.setText('{0:0.1f}'.format(np.mean(self.byEstBuf)))
        self.label_z1.setText('{0:0.1f}'.format(np.mean(self.iz1Buf)))
        self.label_z2.setText('{0:0.1f}'.format(np.mean(self.iz2Buf)))
        self.label_zBreq.setText('{0:0.1f}'.format(field.bzSetpoint))
        self.label_zBact.setText('{0:0.1f}'.format(np.mean(self.bzEstBuf)))

    #=====================================================
    # Callback Functions
    #=====================================================
    # General control tab
    def setFieldXYZ(self):
        field.setX(self.dsb_x.value())
        field.setY(self.dsb_y.value())
        field.setZ(self.dsb_z.value())

    def clearField(self):
        self.dsb_x.setValue(0)
        self.dsb_y.setValue(0)
        self.dsb_z.setValue(0)
        self.dsb_xGradient.setValue(0)
        self.dsb_yGradient.setValue(0)
        self.dsb_zGradient.setValue(0)
        field.setXYZ(0, 0, 0)

    def setFieldXYZGradient(self):
        field.setXGradient(self.dsb_xGradient.value())
        field.setYGradient(self.dsb_yGradient.value())
        field.setZGradient(self.dsb_zGradient.value())

    # vision tab
    def on_chb_bypassFilters(self, state):
        vision.setStateFiltersBypassed(state)

    def on_btn_refreshFilterRouting(self):
        vision.createFilterRouting(
            self.editor_vision.toPlainText().splitlines())

    def on_btn_snapshot(self):
        vision.setStateSnapshotEnabled(True)

    def on_chb_objectDetection(self, state):
        algorithm = self.cbb_objectDetectionAlgorithm.currentText()
        vision.setStateObjectDetection(state, algorithm)
        self.cbb_objectDetectionAlgorithm.setEnabled(not state)

    # subthread
    def on_cbb_subThread(self, subThreadName):
        # an array that stores the name for params. Return param0, param1, ...
        # if not defined.
        labelNames = self.thrd.labelOnGui.get(subThreadName,
                                              self.thrd.labelOnGui['default'])
        minVals = self.thrd.minOnGui.get(subThreadName,
                                         self.thrd.minOnGui['default'])
        maxVals = self.thrd.maxOnGui.get(subThreadName,
                                         self.thrd.maxOnGui['default'])
        defaultVals = self.thrd.defaultValOnGui.get(
            subThreadName, self.thrd.defaultValOnGui['default'])
        for i in range(5):
            targetLabel = 'lbl_subThreadParam' + str(i)
            targetSpinbox = 'dsb_subThreadParam' + str(i)
            getattr(self, targetLabel).setText(labelNames[i])
            getattr(self, targetSpinbox).setMinimum(minVals[i])
            getattr(self, targetSpinbox).setMaximum(maxVals[i])
            getattr(self, targetSpinbox).setValue(defaultVals[i])

    def on_chb_startStopSubthread(self, state):
        subThreadName = self.cbb_subThread.currentText()
        if state:
            self.cbb_subThread.setEnabled(False)
            self.thrd.setup(subThreadName)
            self.thrd.start()
            print('Subthread "{}" starts.'.format(subThreadName))
        else:
            self.cbb_subThread.setEnabled(True)
            self.thrd.stop()

    def initDataBuffers(self):
        bufLength = 15
        self.ix1Buf = np.zeros(bufLength)
        self.ix2Buf = np.zeros(bufLength)
        self.iy1Buf = np.zeros(bufLength)
        self.iy2Buf = np.zeros(bufLength)
        self.iz1Buf = np.zeros(bufLength)
        self.iz2Buf = np.zeros(bufLength)
        self.bxEstBuf = np.zeros(bufLength)
        self.byEstBuf = np.zeros(bufLength)
        self.bzEstBuf = np.zeros(bufLength)
class GUI(QMainWindow, Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self, None, Qt.WindowStaysOnTopHint)
        Ui_MainWindow.__init__(self)
        self.updateRate = 15  # (ms) update rate of the GUI, vision, plot
        self.setupUi(self)
        self.setupTimer()
        self.setupSubThread(field, vision)
        self.setupRealTimePlot(
        )  # comment ou this line if you don't want a preview window
        self.connectSignals()
        self.linkWidgets()

    #=====================================================
    # [override] terminate the subThread and clear currents when closing the window
    #=====================================================
    def closeEvent(self, event):
        self.thrd.stop()
        self.timer.stop()
        vision.cam.stop_video()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.cam.stop_video()
        self.clearField()
        event.accept()

    #=====================================================
    # QTimer handles updates of the GUI, run at 60Hz
    #=====================================================
    def setupTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(self.updateRate)  # msec

    def update(self):
        vision.updateFrame()
        try:
            vision2
        except NameError:
            pass
        else:
            vision2.updateFrame()
        try:
            self.realTimePlot
        except AttributeError:
            pass
        else:
            self.updatePlot()

    #=====================================================
    # Connect buttons etc. of the GUI to callback functions
    #=====================================================
    def connectSignals(self):
        # XYZ Mode Tab
        self.dsb_x.valueChanged.connect(self.setField)
        self.dsb_y.valueChanged.connect(self.setField)
        self.dsb_z.valueChanged.connect(self.setField)
        self.dsb_pxpx.valueChanged.connect(self.setField)
        self.dsb_pxpy.valueChanged.connect(self.setField)
        self.dsb_pxpz.valueChanged.connect(self.setField)
        self.dsb_pypy.valueChanged.connect(self.setField)
        self.dsb_pypz.valueChanged.connect(self.setField)
        self.btn_clearCurrent.clicked.connect(self.clearField)
        # Angle Mode Tab
        self.dsb_mag.valueChanged.connect(self.setFieldByAngle)
        self.dsb_azimuth.valueChanged.connect(self.setFieldByAngle)
        self.dsb_polar.valueChanged.connect(self.setFieldByAngle)
        # Vision Tab
        self.highlighter = syntax.Highlighter(self.editor_vision.document())
        self.chb_bypassFilters.toggled.connect(self.on_chb_bypassFilters)
        self.chb_startPauseCapture.toggled.connect(
            self.on_chb_startPauseCapture)
        self.btn_refreshFilterRouting.clicked.connect(
            self.on_btn_refreshFilterRouting)
        # object detection
        self.chb_objectDetection.toggled.connect(self.on_chb_objectDetection)
        # Subthread Tab
        self.cbb_subThread.currentTextChanged.connect(self.on_cbb_subThread)
        self.chb_startStopSubthread.toggled.connect(
            self.on_chb_startStopSubthread)
        self.dsb_subThreadParam0.valueChanged.connect(self.thrd.setParam0)
        self.dsb_subThreadParam1.valueChanged.connect(self.thrd.setParam1)
        self.dsb_subThreadParam2.valueChanged.connect(self.thrd.setParam2)
        self.dsb_subThreadParam3.valueChanged.connect(self.thrd.setParam3)
        self.dsb_subThreadParam4.valueChanged.connect(self.thrd.setParam4)

    #=====================================================
    # Link GUI elements
    #=====================================================
    def linkWidgets(self):
        # XYZ Mode
        self.dsb_x.valueChanged.connect(
            lambda value: self.hsld_x.setValue(int(value * 100)))
        self.dsb_y.valueChanged.connect(
            lambda value: self.hsld_y.setValue(int(value * 100)))
        self.dsb_z.valueChanged.connect(
            lambda value: self.hsld_z.setValue(int(value * 100)))
        self.hsld_x.valueChanged.connect(
            lambda value: self.dsb_x.setValue(float(value / 100)))
        self.hsld_y.valueChanged.connect(
            lambda value: self.dsb_y.setValue(float(value / 100)))
        self.hsld_z.valueChanged.connect(
            lambda value: self.dsb_z.setValue(float(value / 100)))

        # Angle Mode
        self.dsb_mag.valueChanged.connect(
            lambda value: self.hsld_mag.setValue(int(value * 100)))
        self.dsb_azimuth.valueChanged.connect(
            lambda value: self.hsld_azimuth.setValue(int(value * 10)))
        self.dsb_polar.valueChanged.connect(
            lambda value: self.hsld_polar.setValue(int(value * 10)))
        self.hsld_mag.valueChanged.connect(
            lambda value: self.dsb_mag.setValue(float(value / 100)))
        self.hsld_azimuth.valueChanged.connect(
            lambda value: self.dsb_azimuth.setValue(float(value / 10)))
        self.hsld_polar.valueChanged.connect(
            lambda value: self.dsb_polar.setValue(float(value / 10)))

    #=====================================================
    # Thread Example
    #=====================================================
    def setupSubThread(self, field, vision):
        self.thrd = SubThread(field, vision)
        self.thrd.statusSignal.connect(self.updateSubThreadStatus)
        self.thrd.finished.connect(self.finishSubThreadProcess)

    # updating GUI according to the status of the subthread
    @pyqtSlot(str)
    def updateSubThreadStatus(self, receivedStr):
        print('Received message from subthread: ', receivedStr)
        # show something on GUI

    # run when the subthread is termianted
    @pyqtSlot()
    def finishSubThreadProcess(self):
        print('Subthread is terminated.')
        self.clearField()
        # disable some buttons etc.

    #=====================================================
    # Real time plot
    # This is showing actual coil current that is stored in field.x, field.y, field.z
    # Note: the figure is updating at the speed of self.updateRate defined in _init_
    #=====================================================
    def setupRealTimePlot(self):
        self.realTimePlot = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.realTimePlot,
                                *(0,
                                  0))  # put the preview window in the layout
        self.btn_zoom.clicked.connect(
            self.realTimePlot.zoom)  # connect qt signal to zoom funcion

    def updatePlot(self):
        self.realTimePlot.addDataX(field.vecField[0])
        self.realTimePlot.addDataY(field.vecField[1])
        self.realTimePlot.addDataZ(field.vecField[2])

    #=====================================================
    # Callback Functions
    #=====================================================
    # general field Control
    def setField(self):
        ''' XYZ Mode '''
        field.setField([
            self.dsb_x.value(),
            self.dsb_y.value(),
            self.dsb_z.value(),
            self.dsb_pxpx.value(),
            self.dsb_pxpy.value(),
            self.dsb_pxpz.value(),
            self.dsb_pypy.value(),
            self.dsb_pypz.value()
        ])

    def setFieldByAngle(self):
        ''' Angle Mode. No gradient. '''
        magnitude = self.dsb_mag.value()
        azimuth = self.dsb_azimuth.value()
        polar = self.dsb_polar.value()
        fieldX = magnitude * cosd(polar) * cosd(azimuth)
        fieldY = magnitude * cosd(polar) * sind(azimuth)
        fieldZ = magnitude * sind(polar)
        print(fieldX, fieldY, fieldZ)
        field.setField([fieldX, fieldY, fieldZ, 0, 0, 0, 0, 0])

    def clearField(self):
        field.setField([0, 0, 0, 0, 0, 0, 0, 0])
        self.dsb_x.setValue(0)
        self.dsb_y.setValue(0)
        self.dsb_z.setValue(0)
        self.dsb_pxpx.setValue(0)
        self.dsb_pxpy.setValue(0)
        self.dsb_pxpz.setValue(0)
        self.dsb_pypy.setValue(0)
        self.dsb_pypz.setValue(0)
        self.dsb_mag.setValue(0)
        self.dsb_azimuth.setValue(0)
        self.dsb_polar.setValue(0)

    # vision tab
    def on_chb_bypassFilters(self, state):
        vision.setStateFiltersBypassed(state)

    def on_chb_startPauseCapture(self, state):
        vision.setStateUpdate(state)

    def on_btn_refreshFilterRouting(self):
        vision.createFilterRouting(
            self.editor_vision.toPlainText().splitlines())

    def on_chb_objectDetection(self, state):
        algorithm = self.cbb_objectDetectionAlgorithm.currentText()
        vision.setStateObjectDetection(state, algorithm)
        self.cbb_objectDetectionAlgorithm.setEnabled(not state)

    # subthread
    def on_cbb_subThread(self, subThreadName):
        # an array that stores the name for params. Return param0, param1, ... if not defined.
        labelNames = self.thrd.labelOnGui.get(subThreadName,
                                              self.thrd.labelOnGui['default'])
        minVals = self.thrd.minOnGui.get(subThreadName,
                                         self.thrd.minOnGui['default'])
        maxVals = self.thrd.maxOnGui.get(subThreadName,
                                         self.thrd.maxOnGui['default'])
        defaultVals = self.thrd.defaultValOnGui.get(
            subThreadName, self.thrd.defaultValOnGui['default'])
        for i in range(5):
            targetLabel = 'lbl_subThreadParam' + str(i)
            targetSpinbox = 'dsb_subThreadParam' + str(i)
            getattr(self, targetLabel).setText(labelNames[i])
            getattr(self, targetSpinbox).setMinimum(minVals[i])
            getattr(self, targetSpinbox).setMaximum(maxVals[i])
            getattr(self, targetSpinbox).setValue(defaultVals[i])

    def on_chb_startStopSubthread(self, state):
        subThreadName = self.cbb_subThread.currentText()
        if state:
            self.cbb_subThread.setEnabled(False)
            self.thrd.setup(subThreadName)
            self.thrd.start()
            print('Subthread "{}" starts.'.format(subThreadName))
        else:
            self.cbb_subThread.setEnabled(True)
            self.thrd.stop()