Bitte helfen Sie mit Python!

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Guten Abend,

Ich brauche bitte Hilfe mit Python!
Entschuldigung aber mein Deutsch ist leider nicht gut genug, also ich muss in Englisch schreiben...

A hardware device programmed by me follows the enquiries of the computer program, made in Python. It is connected to the computer creating a virtual COM point via USB. The communications, configurations and buttons function correctly, I only have the problem when I want to graphic the data which the hardware device sends, when I put it in the “Automatic” mode, and the device sends the data periodically every second and the PC program gets stuck.
Nevertheless, when I put the the “Manual” mode, it does function correctly, it graphics the data (random data). The manual mode only makes a lecture when you click on the button “Start Ultrasonic Measurement”. I attach 2 screenshots, in the manual mode (OK) and the automatic (PC stuck).
Everything is in the ZIP GUI5.zip which is attached. The program and a txt.file which is called “valores de test” with some random data in order to be able to do a test.
It seems there is some internal "fight" between the 2 flows of data. I can´t attach the files, so if someone who wants to help me can please send me an e-mail to: isdan24@hotmail.com.
Here under I have copied the part of the Python code where the error probably is:

Code: Alles auswählen

## start the aquisition
    #
    
    def startAcquisition(self):
        
        if self.com_serie.isOpen() == True:
        
            message = str()
            message_data = str()
              
            ##
            ## we send here the configuration to the system
            if self.automatic_mode.isChecked() == True:

            
                timeToWait = self.box_burst_time.value()
                self.btn_stop_acquisition.setEnabled(True)    #Activamos el botÛn de stop de adquisiciÛn en modo auto
                                
                print "pulse_burst_period"
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#pulse_burst_period" + str(int(timeToWait)) + "%"

                self.com_serie.write(message)
                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)

                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
               
                
                print "auto"
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#mode_auto%"
                self.com_serie.write(message)

                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)

                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
                    
            else:

                print "manu"
                #timeToWait = 1 #0
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#mode_manual%"

                self.com_serie.write(message)
                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)

                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
                
            ## now we get the data

            message = "#start%"
            self.com_serie.write(message)
            time.sleep(1)
            listCharacter = ["a"] #to avoid that the list is empty

            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
                                
            #############################

            ## Get the data
            #############################
            self.get_data()
               
            #############################
            ## Plot them

            #############################  
            print "Ploting..."
            self.update_plot()
                               
  
    def automatic_get_data(self): 

        print "auto get data!"
        self.get_data()        
        self.update_plot()
    
    def get_data(self):
        self.dataStr = []
        self.data = []

        self.datafilter = []
                
        message_data = self.getMessageCom()
                   
        print "Estos son los datos  " + message_data  #debug

        message_data = message_data [:len(message_data)-1]   
        self.dataStr = message_data.split(";")
                
        for data in self.dataStr:
            data = int(data)

            data = (data * 3300.0) / 4095.0
            print data   #debug
            self.data.append(data)
            self.datafilter.append(self.filtre.newInputFilter(data))


    
               
    def update_plot(self):
        
        self.fenetre.setCurrentIndex(1)   #Cambia de pestaÒa y muestra gr·fica
        
        

        if self.automatic_mode.isChecked() == False:
            print "Manual mode"
            self.figRaw.axes.clear()
            self.figRaw.axes.plot(self.data)
            self.figRaw.axes.set_title("Raw data")
            self.figRaw.axes.set_xlabel("Time")
            self.figRaw.axes.set_ylabel("Voltage")
            self.figRaw.draw()

        
            self.figFilter.axes.clear()
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.axes.set_title("Filtered data")
            self.figFilter.axes.set_xlabel("Time")

            self.figFilter.axes.set_ylabel("Voltage")
            self.figFilter.draw()
        else:
            print "Automatic mode"
            self.figRaw.axes.plot(self.data)

            self.figRaw.draw()
            
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.draw()
            
            self.automatic_get_data()  # imprimir de forma contÌnua



        
        #hl.set_xdata(numpy.append(hl.get_xdata(), new_data))
        #hl.set_ydata(numpy.append(hl.get_ydata(), new_data))
        #plt.draw()
    

    def stopAcquisition(self):
        message = "#stop%"
        self.com_serie.write(message)
        time.sleep(1)
        listCharacter = ["a"] #to avoid that the list is empty

        while(listCharacter[len(listCharacter)-1] != '%'):
            listCharacter.append(self.com_serie.read())
        message = "".join(listCharacter)
        message = message[message.find("#"):message.find("%") + 1]

        print "recu " + message

Vielen Dank!

MFG, Bernhard.
Zuletzt geändert von Anonymous am Dienstag 18. Februar 2014, 08:37, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@Mickeymouse: I guess the problem you are experiencing is a „freezing” GUI when you have a long running callback function or method. Callback functions, i.e. functions called from the GUI main loop triggered by events like a user pushing a button should not run long or even ”endless” because while they are running the GUI cannot be updated. Only after those functions return to the main loop, the user interface is responsible again. To have long running tasks alongside the GUI you'll have to execute them in their own thread. Take care the GUI isn't manipulated by code running in such a thread because Qt, like most other toolkits, is not thread safe here. Firing signals is okay though. Depending on the problem it might make sense to use Qt's classes for concurrent programming instead of the `threading` module in the Python standard library.
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Vielen Dank Blackjack!

Ist est vielleicht möglich für Ihnen um mir ein E-mail zu schicken?

Wenn ich Ihnen die Anlagen zu schicken könnte dann ist alles denke ich deutlicher.

Meine Adresse ist: isdan24@hotmail.com.

Hier ist est nicht möglich um Anlagen zu schicken doch?

MFG,

Mickey.
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Mickeymouse hat geschrieben:Vielen Dank Blackjack!

Ist est vielleicht möglich für Ihnen um mir ein E-mail zu schicken?

Wenn ich Ihnen die Anlagen zu schicken könnte dann ist alles denke ich deutlicher.

Meine Adresse ist: isdan24@hotmail.com.

Hier ist est nicht möglich um Anlagen zu schicken doch?

MFG,

Mickey.
BlackJack

@Mickeymouse: Some remarks about the source code:

Don't compare explicitly against literal truth values. The result will be again a truth value, either the same you had in the first place in case of ``== True`` or the opposite in case of ``== False``. In the first case you can simply use the value you compared and in the second case negate it with ``not``.

In `startAcquisition()` the name `message_data` is bound to an empty string but never used anywhere. The value of the assignment above to `message` is also not used anywhere. Both lines can be deleted. `str()` is also an uncommon way to express the empty string.

Sometimes lines and assignments that are not related are interleaved in the code. For instance `timeToWait` is assigned and the some completely unrelated lines are executed before `timeToWait` is actually used. That is unnecessary confusing. Try to keep definitions and usage more close to each other.

Concatenating literal strings and values with ``+`` and `str()` is more BASIC than idiomatic Python. Python has string formatting for this.

The same code to send a command and receive a response over the serial connection is repeated over and over again. This should be factored out into an own method. Preferreably into an own data type representing the connection to the specific connected hardware. You are currently mixing program logic with GUI programming.

The list with the 'a' when receiving an answer is an ugly hack which can be avoided by rearranging the order in which things are done.

``while`` is not a function and therefore should not be written as it where one. The parenthesis around the condition are unnecessary anyway.

``sequence[len(sequence) - 1]`` is an overcomplicated way of writing ``sequence[-1]``.

Instead of `find()` one should use `index()` to search for an index because if the element is not found the `find()` method returns a valid but most probably wrong value if used for indexing or slicing.

When slicing the response from the serial connection there is no need to search for the '%' character because as this is the stopping condition for the receiving loop, so we already know it must be the last character.

Comments are meant for information that is apparent from reading the code. For instance commenting ``# Get the data`` before calling a method called `get_data()` has no additional value for the reader.

`self.dataStr` in `get_data()` is bound to an empty list which never is used before the attribute gets reassigned. I also have doubts if this actually have to be an attribute at all. Even a local name is not needed if the method is rewritten with much more compact list comprehensions and the `map()` function.

Between `automatic_get_date()` and `update_plot()` there is an endless recursion which is a very bad idea because a) this is where your GUI freezes and b) it will eventuelly lead to an ``RuntimeError: maximum recursion depth exceeded``.

Some of the above considered it may look like this (untested):

Code: Alles auswählen

# ...

class SomeBetterNameForThisConnection(object):
    def __init__(self):
        self.connection = Serial()

    def send_command(self, command, delay=0):
        self.connection.write('#{0}%'.format(command))
        time.sleep(delay)
        characters = list()
        while True:
            character = self.connection.read()
            if character == '%':
                break
            characters.append(character)

        result = ''.join(characters)
        # 
        # TODO Is searching the '#' necessary at all when we don't start with
        #   a list containing the unnecessary 'a' character?
        # 
        return result[result.index('#'):]


class IDontKnowTheName(object):

    # ...

    def startAcquisition(self):

        if self.com_serie.isOpen():
            #
            # We send here the configuration to the system
            # 
            if self.automatic_mode.isChecked():
                # 
                # Activamos el botÛn de stop de adquisiciÛn en modo auto
                # 
                self.btn_stop_acquisition.setEnabled(True)
                               
                print 'pulse_burst_period'
                delay = self.box_burst_time.value()
                response = self.com_serie.send_command(
                    'pulse_burst_period{0:d}'.format(delay)
                )
                print 'recu', response
                print 'auto'
                print 'recu', self.com_serie.send_command('mode_auto')
            else:
                print 'manu'
                print 'recu', self.com_serie.send_command('mode_manual')
            #          
            # Now we get the data.
            # 
            print 'recu', self.com_serie.send_command('start', 1)
                               
            self.automatically_get_data()
 
    def automatically_get_data(self):
        print 'auto get data!'
        self.receive_data()        
        self.update_plot()
   
    def receive_data(self):
        # 
        # TODO Most certaintly the UI code contains program logic. → Refactor.
        # 
        message = self.getMessageCom()
        print 'Estos son los datos', message
        self.data = [
            (int(value) * 3300.0) / 4095.0 for value in message[:-1].split(';')
        ]
        self.datafilter = map(self.filtre.newInputFilter, self.data)
                   
    def update_plot(self):
        self.fenetre.setCurrentIndex(1)  # Cambia de pestaÒa y muestra gr·fica.

        if not self.automatic_mode.isChecked():
            print 'Manual mode'
            self.figRaw.axes.clear()
            self.figRaw.axes.plot(self.data)
            self.figRaw.axes.set_title('Raw data')
            self.figRaw.axes.set_xlabel('Time')
            self.figRaw.axes.set_ylabel('Voltage')
            self.figRaw.draw()
       
            self.figFilter.axes.clear()
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.axes.set_title('Filtered data')
            self.figFilter.axes.set_xlabel('Time')
 
            self.figFilter.axes.set_ylabel('Voltage')
            self.figFilter.draw()
        else:
            print 'Automatic mode'
            self.figRaw.axes.plot(self.data)
 
            self.figRaw.draw()
           
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.draw()
            # 
            # TODO Don't do an endless recursion here.  Either use a separate
            #   thread or if possible a `QTimer` to repeatedly read values and
            #   update the plot.
            # 
            #self.automatically_get_data()  # imprimir de forma contÌnua
 
    def stopAcquisition(self):
        print 'recu', self.com_serie.send_command('stop')
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@BlackJack: Wenn ich nichts übersehe, lässt sich dieser Teil:

Code: Alles auswählen

        characters = list()
        while True:
            character = self.connection.read()
            if character == '%':
                break
            characters.append(character)
 
        result = ''.join(characters)
...doch deutlich kürzer (und mutmaßlich performanter) schreiben mittels:

Code: Alles auswählen

result = ''.join(iter(self.connection.read, '%'))
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Vielen Dank Snofu und Blackjack!!!

Ich hoffe das ich jetzt weiterkommen kann!!

MFG, Mickeymouse ;-)
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Gutenmorgen Blackjack und Snafu :-)

You have been of great help to me. I am just a beginner with Python.

The code I sent and you corrected is the part wherein I think the error is.

However, I think there might be some more to change and to correct. I would be very grateful if you could have a look at the whole code and tell me what I should change.

I really did my best but now I see, there is much to improve.... Part of the code here under is what you already saw and I am correcting that part now. I think it is a good

idea that you see the complete code. Thank you very much!!!

Code: Alles auswählen

import sys
from PyQt4 import QtGui, QtCore
import signal #to close the windows with ctrl+C
import serial

import matplotlibwidget
import filtre
import time
import math


class MainWindows(QtGui.QMainWindow):

# Global variables
    continu = True

    def __init__(self):
        
        super(MainWindows, self).__init__()
        self.initGUI()
        
    ## init all the GUI windows
    # 
     
    def initGUI(self):
        
        ###
        ##define filtre
        self.filtre = filtre.filtreIIR2(0.29289322, 0.58578644, 0.29289322, 0, 0.17157288)
        
        ##
        ## define the GUI
        zoneCentrale = QtGui.QWidget()

        windowsIcon = QtGui.QIcon("esiLogo.PNG")
        self.setWindowIcon(windowsIcon)
        
        self.greenPalette = QtGui.QPalette()
        self.greenPalette.setColor(QtGui.QPalette.Button, QtGui.QColor(0, 255, 0, 127))

        self.redPalette = QtGui.QPalette()
        self.redPalette.setColor(QtGui.QPalette.Button, QtGui.QColor(255, 0, 0, 127))

        ##
        ##Boxs to port series connect
        gridbox_com_connection = QtGui.QGridLayout()
        name_com_connection = QtGui.QLabel("Ultrasonic board connection:")
        name_numero_com = QtGui.QLabel("Serial COM Port connection")
        name_baud_rate = QtGui.QLabel("Baud Rate")
        
        self.box_numero_com = QtGui.QComboBox()
        self.box_baude_rate = QtGui.QComboBox()
        
        liste_baud_rate = ["110", "150", "300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"]
        
        for baude_rate in liste_baud_rate:
            self.box_baude_rate.addItem(baude_rate)

        liste_port_com = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "28"]
        
        for port_com in liste_port_com:
            self.box_numero_com.addItem(port_com)

        self.liste_com = [self.box_numero_com, self.box_baude_rate]

        self.btn_connect = QtGui.QPushButton("Connect")
        
        gridbox_com_connection.addWidget(name_com_connection, 0, 0, 1, 2)
        gridbox_com_connection.addWidget(name_numero_com, 1,0)
        gridbox_com_connection.addWidget(self.box_numero_com, 1, 1)
        gridbox_com_connection.addWidget(name_baud_rate, 2, 0)
        gridbox_com_connection.addWidget(self.box_baude_rate, 2, 1)
        gridbox_com_connection.addWidget(self.btn_connect, 3, 1)
        
        self.com_serie = serial.Serial()

        self.connect(self.btn_connect, QtCore.SIGNAL("clicked()"), self.comConnect)

        ##
        ##Boxs to send pulses
        gridbox_send_pulsos = QtGui.QGridLayout()
        name_pulsos = QtGui.QLabel("Ultrasonic Burst Emission:")
        name_frequencia = QtGui.QLabel("Frequency (in Hz)")
        name_num_pulsos = QtGui.QLabel("Number of pulses")
        #name_duty_cycle = QtGui.QLabel("Duty_cycle")

        self.box_frequencia = QtGui.QDoubleSpinBox()
        self.box_num_pulsos = QtGui.QDoubleSpinBox()
        #self.box_duty_cycle = QtGui.QDoubleSpinBox()

        self.liste_pulsos = [self.box_frequencia, self.box_num_pulsos] #, self.box_duty_cycle]
        for spinBox in self.liste_pulsos:
            spinBox.setSingleStep(1)
            spinBox.setRange(0,500000)
            spinBox.setDecimals(0)

        self.btn_send_pulsos = QtGui.QPushButton("Send Ultrasonic Burst Configuration")

        gridbox_send_pulsos.addWidget(name_pulsos, 0, 0, 1, 2)
        gridbox_send_pulsos.addWidget(name_frequencia, 1, 0)
        gridbox_send_pulsos.addWidget(self.box_frequencia, 1, 1)
        gridbox_send_pulsos.addWidget(name_num_pulsos, 2, 0)
        gridbox_send_pulsos.addWidget(self.box_num_pulsos, 2, 1)
        #gridbox_send_pulsos.addWidget(name_duty_cycle, 3, 0)
        #gridbox_send_pulsos.addWidget(self.box_duty_cycle, 3, 1)
        gridbox_send_pulsos.addWidget(self.btn_send_pulsos, 4, 1)
        
        self.connect(self.btn_send_pulsos, QtCore.SIGNAL("clicked()"), self.sendPulsos)

        ##
        ##Box to send acquisition parameter
        gridbox_send_acquisition = QtGui.QGridLayout()
        name_acquisition = QtGui.QLabel("Acquisition Parameter Configuration :")
        name_number_point = QtGui.QLabel("Number of Points at 2,4MHz Sampling freq.")
        name_time_before_acquisition = QtGui.QLabel("Delay Time Before Acquisition (in ms)")

        self.box_number_point = QtGui.QDoubleSpinBox()
        self.box_time_before_acquisition = QtGui.QDoubleSpinBox()

        self.liste_acquisition = [self.box_number_point, self.box_time_before_acquisition]
        for spinBox in self.liste_acquisition:
            spinBox.setSingleStep(1)
            spinBox.setRange(0,8000)
            spinBox.setDecimals(0)

        self.btn_send_acquisition = QtGui.QPushButton("Send Acquisition Parameter Configuration")

        gridbox_send_acquisition.addWidget(name_acquisition, 0, 0, 1, 2)
        gridbox_send_acquisition.addWidget(name_number_point, 1, 0)
        gridbox_send_acquisition.addWidget(self.box_number_point, 1, 1)
        gridbox_send_acquisition.addWidget(name_time_before_acquisition, 2, 0)
        gridbox_send_acquisition.addWidget(self.box_time_before_acquisition, 2, 1)
        gridbox_send_acquisition.addWidget(self.btn_send_acquisition, 3, 1)
        
        self.connect(self.btn_send_acquisition, QtCore.SIGNAL("clicked()"), self.sendAcquisitionParameter)

        ##
        ##Box to send filter parameter
        gridbox_send_filter = QtGui.QGridLayout()
        name_filter = QtGui.QLabel("Filter Parameters :")
        name_b00 = QtGui.QLabel("b00")
        name_b01 = QtGui.QLabel("b01")
        name_b02 = QtGui.QLabel("b02")

        self.box_b00 = QtGui.QDoubleSpinBox()
        self.box_b01 = QtGui.QDoubleSpinBox()
        self.box_b02 = QtGui.QDoubleSpinBox()

        self.liste_filter = [self.box_b00, self.box_b01, self.box_b02]
        for spinBox in self.liste_filter:
            spinBox.setSingleStep(0.0001)
            spinBox.setRange(0,500)
            spinBox.setDecimals(4)
            
# Este botón ahora tiene sentido?? No, habría que hacer el cálculo con las varibles b00, b01 y b02. El filtrado se hace en el PC y no en el uC.
        self.btn_send_filter = QtGui.QPushButton("Send Filter Parameters")
        
        gridbox_send_filter.addWidget(name_filter, 0, 0, 1, 2)
        gridbox_send_filter.addWidget(name_b00, 1, 0)
        gridbox_send_filter.addWidget(self.box_b00, 1, 1)
        gridbox_send_filter.addWidget(name_b01, 2, 0)
        gridbox_send_filter.addWidget(self.box_b01, 2, 1)
        gridbox_send_filter.addWidget(name_b02, 3, 0)
        gridbox_send_filter.addWidget(self.box_b02, 3, 1)
        gridbox_send_filter.addWidget(self.btn_send_filter, 4, 1)
        
        self.connect(self.btn_send_filter, QtCore.SIGNAL("clicked()"), self.sendFilterParameter)

        ##
        ##button to start a test       
        name_start_test = QtGui.QLabel("Ultrasonic Measurements :")
        
        self.manual_mode = QtGui.QRadioButton("Manual")
        self.automatic_mode = QtGui.QRadioButton("Automatic")
        
        self.box_burst_time = QtGui.QDoubleSpinBox()
        
        self.box_burst_time.setSingleStep(3)
        self.box_burst_time.setRange(1,60)
        self.box_burst_time.setDecimals(0)
        
        gridbox_start_acquisition = QtGui.QGridLayout()
        self.btn_start_acquisition = QtGui.QPushButton("Start Ultrasonic Measurement")
        self.btn_stop_acquisition = QtGui.QPushButton("Stop Ultrasonic Measurement")
        
        gridbox_start_acquisition.addWidget(name_start_test, 0, 0)
        gridbox_start_acquisition.addWidget(self.manual_mode, 1, 0)
        gridbox_start_acquisition.addWidget(self.automatic_mode, 2, 0)
        gridbox_start_acquisition.addWidget(self.box_burst_time, 3, 1)
        gridbox_start_acquisition.addWidget(self.btn_start_acquisition, 4, 0, 1, 2)
        gridbox_start_acquisition.addWidget(self.btn_stop_acquisition, 5, 0, 1, 2)
        
        self.connect(self.btn_start_acquisition, QtCore.SIGNAL("clicked()"), self.startAcquisition)
        self.connect(self.btn_stop_acquisition, QtCore.SIGNAL("clicked()"), self.stopAcquisition)
        
        ##
        ##init graph
        gridbox_graph = QtGui.QGridLayout()
        
        name_graph = QtGui.QLabel("Result :")
        
        self.figRaw = matplotlibwidget.MatplotlibWidget(parent=self, title="Raw data", xlabel="Time", ylabel="Voltage")
        self.figFilter = matplotlibwidget.MatplotlibWidget(parent=self, title="Filtered data", xlabel="Time",ylabel="Voltage")
        
        gridbox_graph.addWidget(self.figRaw, 1, 0)
        gridbox_graph.addWidget(self.figFilter, 1, 1)
        gridbox_graph.addWidget(name_graph, 0, 0, 1, 2)
        
        self.catch = False
        
        self.figRaw.mpl_connect('scroll_event', self.OnScrollEvt)
        self.figFilter.mpl_connect('scroll_event', self.OnScrollEvt)
        
        self.figRaw.mpl_connect('button_press_event', self.OnPress)
        self.figRaw.mpl_connect('button_release_event', self.OnRelease)
        self.figRaw.mpl_connect('motion_notify_event', self.OnMotion)
        
        self.figFilter.mpl_connect('button_press_event', self.OnPress)
        self.figFilter.mpl_connect('button_release_event', self.OnRelease)
        self.figFilter.mpl_connect('motion_notify_event', self.OnMotion)
        
        ##
        ##initialise the color of each button
        
        self.btn_connect.setPalette(self.greenPalette)
        self.btn_connect.setAutoFillBackground(True)
        self.btn_connect.setFlat(True)
        self.btn_send_pulsos.setPalette(self.redPalette)
        self.btn_send_pulsos.setAutoFillBackground(True)
        self.btn_send_pulsos.setFlat(True)
        self.btn_send_filter.setPalette(self.redPalette)
        self.btn_send_filter.setAutoFillBackground(True)
        self.btn_send_filter.setFlat(True)
        self.btn_send_acquisition.setPalette(self.redPalette)
        self.btn_send_acquisition.setAutoFillBackground(True)
        self.btn_send_acquisition.setFlat(True)
        self.btn_send_pulsos.setEnabled(False)
        self.btn_send_filter.setEnabled(False)
        self.btn_send_acquisition.setEnabled(False)
        self.btn_start_acquisition.setEnabled(False)
        self.btn_stop_acquisition.setEnabled(False)
        
        ##
        ##save file
        
        name_save = QtGui.QLabel("Save Measurement :")
        
        gridbox_save_file = QtGui.QGridLayout()
        
        self.btn_save_file = QtGui.QPushButton("Save")
        self.btn_browse = QtGui.QPushButton("Browse")
        
        self.connect(self.btn_save_file, QtCore.SIGNAL("clicked()"), self.saveFile)
        self.connect(self.btn_browse, QtCore.SIGNAL("clicked()"), self.Browse)
        
        self.path = QtGui.QLineEdit()
        
        gridbox_save_file.addWidget(name_save, 0, 0, 1, 2)
        gridbox_save_file.addWidget(self.path, 1, 0, 1, 2)
        gridbox_save_file.addWidget(self.btn_browse, 2, 0)
        gridbox_save_file.addWidget(self.btn_save_file, 2, 1)
        
        ##
        ##Window
        self.setGeometry(100, 100, 1000, 600)
        self.setWindowTitle('Ultrasonic Prototipe System')
        self.setCentralWidget(zoneCentrale)
        
        self.vline = QtGui.QFrame()
        self.vline.setFrameShape(QtGui.QFrame.VLine)
        self.vline.setFrameShadow(QtGui.QFrame.Sunken)
        
        self.hline = QtGui.QFrame()
        self.hline.setFrameShape(QtGui.QFrame.HLine)
        self.hline.setFrameShadow(QtGui.QFrame.Sunken)

        self.hline2 = QtGui.QFrame()
        self.hline2.setFrameShape(QtGui.QFrame.HLine)
        self.hline2.setFrameShadow(QtGui.QFrame.Sunken)
        
        self.hline4 = QtGui.QFrame()
        self.hline4.setFrameShape(QtGui.QFrame.HLine)
        self.hline4.setFrameShadow(QtGui.QFrame.Sunken)
        
        self.hline5 = QtGui.QFrame()
        self.hline5.setFrameShape(QtGui.QFrame.HLine)
        self.hline5.setFrameShadow(QtGui.QFrame.Sunken)
        
        gridLayout = QtGui.QGridLayout()
        gridLayout2 = QtGui.QGridLayout()
        
        gridLayout.addLayout(gridbox_com_connection, 0, 2, 3, 1)
        gridLayout.addWidget(self.vline, 0, 1, 5, 1)
        gridLayout.addLayout(gridbox_send_pulsos, 0, 0)
        gridLayout.addWidget(self.hline, 1, 0)
        gridLayout.addLayout(gridbox_send_acquisition, 2, 0)
        gridLayout.addWidget(self.hline2, 3, 0)
        gridLayout.addLayout(gridbox_send_filter, 4, 0)
        gridLayout.addWidget(self.hline4, 3, 2)
        gridLayout.addLayout(gridbox_start_acquisition, 4, 2)
        
        gridLayout2.addLayout(gridbox_graph, 0, 0)
        gridLayout2.addLayout(gridbox_save_file, 2, 0)
        gridLayout2.addWidget(self.hline5, 1, 0)
        
        wid1 = QtGui.QWidget()
        wid2 = QtGui.QWidget()
        
        wid1.setLayout(gridLayout)
        wid2.setLayout(gridLayout2)
        
        self.fenetre = QtGui.QTabWidget(zoneCentrale)
        self.fenetre.setGeometry(0, 0, 1000, 600)
        self.fenetre.addTab(wid1, "Configuration")
        self.fenetre.addTab(wid2, "Graph Analysis")

        self.show()

    ## Connect the application to the port serial given by the user
    #

    def comConnect(self):
        portConnection, success = self.box_numero_com.currentText().toInt()
        baudeRate, success2 = self.box_baude_rate.currentText().toInt()

        if success != True and success2 != True:
            QtGui.QMessageBox.warning(self, "Warning", "fail to convert the number from the box", QtGui.QMessageBox.Ok)
        else:
            if self.com_serie.isOpen() == True: #if there is alredy a connection, we close it
                self.com_serie.close()
            
            self.com_serie.baudrate = baudeRate
            self.com_serie.port = portConnection - 1
            self.com_serie.timeout = 2 #we put two seconde of timeout
            
            try:
                self.com_serie.open()
                print "Success to open connection" 
                
                ## we put all the button in green to show that you can use it
                self.btn_connect.setPalette(self.greenPalette)
                self.btn_connect.setAutoFillBackground(True)
                self.btn_connect.setFlat(True)
                self.btn_send_pulsos.setPalette(self.greenPalette)
                self.btn_send_pulsos.setAutoFillBackground(True)
                self.btn_send_pulsos.setFlat(True)
                self.btn_send_filter.setPalette(self.greenPalette)
                self.btn_send_filter.setAutoFillBackground(True)
                self.btn_send_filter.setFlat(True)
                self.btn_send_acquisition.setPalette(self.greenPalette)
                self.btn_send_acquisition.setAutoFillBackground(True)
                self.btn_send_acquisition.setFlat(True)
                self.btn_send_pulsos.setEnabled(True)
                self.btn_send_filter.setEnabled(True)
                self.btn_send_acquisition.setEnabled(True)
                self.btn_start_acquisition.setEnabled(True)
                
            except:
                QtGui.QMessageBox.warning(self, "Warning", "fail to open the connection", QtGui.QMessageBox.Ok)
                self.btn_send_pulsos.setPalette(self.redPalette)
                self.btn_send_pulsos.setAutoFillBackground(True)
                self.btn_send_pulsos.setFlat(True)
                self.btn_send_filter.setPalette(self.redPalette)
                self.btn_send_filter.setAutoFillBackground(True)
                self.btn_send_filter.setFlat(True)
                self.btn_send_acquisition.setPalette(self.redPalette)
                self.btn_send_acquisition.setAutoFillBackground(True)
                self.btn_send_acquisition.setFlat(True)
                self.btn_send_pulsos.setEnabled(False)
                self.btn_send_filter.setEnabled(False)
                self.btn_send_acquisition.setEnabled(False)
                self.btn_start_acquisition.setEnabled(False)

    ## Send all the parameter for the pulses. nbPulse, frequency, duty_cycle
    #
    def sendPulsos(self):
    
        if self.com_serie.isOpen() == True:
        
            self.btn_send_pulsos.setPalette(self.redPalette)
            self.btn_send_pulsos.setAutoFillBackground(True)
            self.btn_send_pulsos.setFlat(True)

            message = str()
            
            listCharacter = ["a"] #to avoid that the list is empty
            message = "#pulse_freq" + str(int(self.box_frequencia.value())) + "%"
            self.com_serie.write(message)
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
            
            listCharacter = ["a"]#to avoid that the list is empty
            message = "#pulse_num" + str(int(self.box_num_pulsos.value())) + "%"
            self.com_serie.write(message)
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
            
            # listCharacter = ["a"]#to avoid that the list is empty
            # message = "#pulse_duty_cycle" + str(int(self.box_duty_cycle.value())) + "%"
            # self.com_serie.write(message)
            # while(listCharacter[len(listCharacter)-1] != '%'):
                # listCharacter.append(self.com_serie.read())
            # message = "".join(listCharacter)
            # message = message[message.find("#"):message.find("%") + 1]
            # print "recu " + message
            
            self.btn_send_pulsos.setPalette(self.greenPalette)
            self.btn_send_pulsos.setAutoFillBackground(True)
            self.btn_send_pulsos.setFlat(True)
        
        else:
        
            QtGui.QMessageBox.warning(self, "Warning", "The port serial have not been open", QtGui.QMessageBox.Ok)
        
 
    ## Send all the parameter for the Acquisition, nbPoint and the time before making acquisition
    #
    def sendAcquisitionParameter(self):
    
        if self.com_serie.isOpen() == True:
        
            self.btn_send_acquisition.setPalette(self.redPalette)
            self.btn_send_acquisition.setAutoFillBackground(True)
            self.btn_send_acquisition.setFlat(True)
            
            message = str()
            
            listCharacter = ["a"] #to avoid that the list is empty
            message = "#adq_n_points" + str(int(self.box_number_point.value())) + "%"
            self.com_serie.write(message)
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
            
            listCharacter = ["a"] #to avoid that the list is empty
            message = "#adq_delay_time" + str(int(self.box_time_before_acquisition.value())) + "%"
            self.com_serie.write(message)
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
            
            self.btn_send_acquisition.setPalette(self.greenPalette)
            self.btn_send_acquisition.setAutoFillBackground(True)
            self.btn_send_acquisition.setFlat(True)

        else:
         
            QtGui.QMessageBox.warning(self, "Warning", "The port serial have not been open", QtGui.QMessageBox.Ok)
   
   
    ## Send all the parameter for the filter
    #

    def sendFilterParameter(self):
    
        if self.com_serie.isOpen() == True:
        
            self.btn_send_filter.setPalette(self.redPalette)
            self.btn_send_filter.setAutoFillBackground(True)
            self.btn_send_filter.setFlat(True)
            
            self.btn_send_filter.setPalette(self.greenPalette)
            self.btn_send_filter.setAutoFillBackground(True)
            self.btn_send_filter.setFlat(True)
        else:
            
            QtGui.QMessageBox.warning(self, "Warning", "The port serial have not been open", QtGui.QMessageBox.Ok)
            
    ## save the data in the file given by the Line Edit widget
    #
        
    def saveFile(self):
    
        filename = self.path.text()
        
        file = QtCore.QFile(filename)
        file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text)
        
        ################
        ### how do we store them
        #################
        
        for data in self.data:
            file.write(str(data))
            file.write('\n')

        file.write("filtered data\n")
        
        for data in self.datafilter:
            file.write(str(data))
            file.write('\n')

        file.close()
        
    ## Allow the user to give a path where to store the data. This path is then display in the line edit widget
    #
        
    def Browse(self):
        
        filename = QtGui.QFileDialog.getSaveFileName(self, "Save file", "", ".txt")
        self.path.setText(filename)

    ## start the aquisition
    #
    
    def startAcquisition(self):
        
        if self.com_serie.isOpen() == True:
        
            message = str()
            message_data = str()
              
            ##
            ## we send here the configuration to the system
            if self.automatic_mode.isChecked() == True:
            
                timeToWait = self.box_burst_time.value()
                self.btn_stop_acquisition.setEnabled(True)    #Activamos el botón de stop de adquisición en modo auto
                                
                print "pulse_burst_period"
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#pulse_burst_period" + str(int(timeToWait)) + "%"
                self.com_serie.write(message)
                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)
                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
               
                
                print "auto"
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#mode_auto%"
                self.com_serie.write(message)
                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)
                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
                    
            else:
                print "manu"
                #timeToWait = 1 #0
                listCharacter = ["a"] #to avoid that the list is empty
                message = "#mode_manual%"
                self.com_serie.write(message)
                while(listCharacter[len(listCharacter)-1] != '%'):
                    listCharacter.append(self.com_serie.read())
                message = "".join(listCharacter)
                message = message[message.find("#"):message.find("%") + 1]
                print "recu " + message
                
            ## now we get the data
            message = "#start%"
            self.com_serie.write(message)
            time.sleep(1)
            listCharacter = ["a"] #to avoid that the list is empty
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
                                
            #############################
            ## Get the data
            #############################
            self.get_data()
               
            #############################
            ## Plot them
            #############################  
            print "Ploting..."
            self.update_plot()
                               
  
    def automatic_get_data(self): 
        print "auto get data!"
        self.get_data()        
        self.update_plot()
    
    def get_data(self):
        self.dataStr = []
        self.data = []
        self.datafilter = []
                
        message_data = self.getMessageCom()
                   
        print "Estos son los datos  " + message_data  #debug
        message_data = message_data [:len(message_data)-1]   
        self.dataStr = message_data.split(";")
                
        for data in self.dataStr:
            data = int(data)
            data = (data * 3300.0) / 4095.0
            print data   #debug
            self.data.append(data)
            self.datafilter.append(self.filtre.newInputFilter(data))

    
               
    def update_plot(self):
        
        self.fenetre.setCurrentIndex(1)   #Cambia de pestaña y muestra gráfica
        
        
        if self.automatic_mode.isChecked() == False:
            print "Manual mode"
            self.figRaw.axes.clear()
            self.figRaw.axes.plot(self.data)
            self.figRaw.axes.set_title("Raw data")
            self.figRaw.axes.set_xlabel("Time")
            self.figRaw.axes.set_ylabel("Voltage")
            self.figRaw.draw()
        
            self.figFilter.axes.clear()
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.axes.set_title("Filtered data")
            self.figFilter.axes.set_xlabel("Time")
            self.figFilter.axes.set_ylabel("Voltage")
            self.figFilter.draw()
        else:
            print "Automatic mode"
            self.figRaw.axes.plot(self.data)
            self.figRaw.draw()
            
            self.figFilter.axes.plot(self.datafilter)
            self.figFilter.draw()
            
            self.automatic_get_data()  # imprimir de forma contínua

        
        #hl.set_xdata(numpy.append(hl.get_xdata(), new_data))
        #hl.set_ydata(numpy.append(hl.get_ydata(), new_data))
        #plt.draw()
    
    def stopAcquisition(self):
        message = "#stop%"
        self.com_serie.write(message)
        time.sleep(1)
        listCharacter = ["a"] #to avoid that the list is empty
        while(listCharacter[len(listCharacter)-1] != '%'):
            listCharacter.append(self.com_serie.read())
        message = "".join(listCharacter)
        message = message[message.find("#"):message.find("%") + 1]
        print "recu " + message
            
        
    def OnScrollEvt(self, event):
    
        xmin, xmax = event.canvas.axes.get_xlim()
        xmoy = (xmax + xmin)/2.0
        event.canvas.axes.set_xlim(xmoy - (xmoy - xmin)*math.pow(1.1, event.step), (xmax - xmoy)*math.pow(1.1, event.step) + xmoy)
        event.canvas.draw()

    def OnPress(self, event):
    
        self.catch = True
        self.x0 = event.x
        self.y0 = event.y
    
    def OnMotion(self, event):
    
        if self.catch == True:
            ymin, ymax = event.canvas.axes.get_ylim()
            xmin, xmax = event.canvas.axes.get_xlim()
            dx = (event.x - float(self.x0))*(xmax-xmin)/100.0
            dy = (event.y - float(self.y0))*(ymax-ymin)/100.0
            self.x0 = event.x
            self.y0 = event.y
            event.canvas.axes.set_ylim(ymin - dy, ymax - dy)
            event.canvas.axes.set_xlim(xmin - dx, xmax - dx)
            event.canvas.draw()
    
    def OnRelease(self, event):
    
        self.catch = False
    
    def getMessageCom(self):
        listCharacter = ["a"] #to avoid that the list is empty
        
        while(listCharacter[len(listCharacter)-1] != '%'):
            listCharacter.append(self.com_serie.read())
        message = "".join(listCharacter)
        message = message[message.find("#")+1:message.find("%")]
       # print "mensaje: " + message #debug
        return message
    
if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    mainWindows = MainWindows()
    sys.exit(app.exec_())



MFG, Mickeymouse :-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Please put such long Code Snippets not directly into a posting, but instead use a pastebin like the one integrated in this board (check menu bar at the top of the page ;-) ) or just use gist.github.com. It is much easier to read your comment this way, if there are not dozens of code lines :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Hello Hyperion,


Sorry but thank you, I did not know about that option.

I am trying to put some attachments in the pastebin, they are normal Word documents but it is impossible.

Just 2 screenshots of the manual mode: OK and the automatic mode: program stuck.

It is not 100% necessary but I wanted you to see what happens when I use the automatic mode.

Now that you have the complete code, I hope you can help me to improve it and solve the problem!

One part is already done by Blackjack.

Best regards, Mickey :-)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Codeteile wie dieser hier:

Code: Alles auswählen

            listCharacter = ["a"] #to avoid that the list is empty
            message = "#adq_delay_time" + str(int(self.box_time_before_acquisition.value())) + "%"
            self.com_serie.write(message)
            while(listCharacter[len(listCharacter)-1] != '%'):
                listCharacter.append(self.com_serie.read())
            message = "".join(listCharacter)
            message = message[message.find("#"):message.find("%") + 1]
            print "recu " + message
...sollten definitiv in eine Funktion ausgelagert werden.

Mögliche Implementierung (ungetestet):

Code: Alles auswählen

def send(self, command, delay=0):
    self.com_serie.write('#{}%'.format(command))
    time.sleep(delay)
    response = ''.join(iter(self.com_serie.read, '%'))
    start_pos = response.index('#') + 1
    return response[start_pos:]
Dies würde die Antwort ohne die Steuerzeichen "#" und "%" ausgeben. Auch beim Senden muss hier der reine Nachrichtentext (auch wieder ohne "#" und '"%") angegeben werden.

Anwendungsbeispiel:

Code: Alles auswählen

response = self.send('start', 1)
EDIT: Eigentlich hat BlackJack das ja weiter oben schon geschrieben...
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Hallo Snafu,


Vielen Dank!

Ja, ich weiss es, aber ich habe noch fast kein Erfahrung mit Python und habe versucht mich das selbst an zu lernen.

Es ist das erste mahl, das ich wirklich etwas mit Python gemacht habe.

Ich möchte gerne wenn Sie die Möglichkeit haben das Sie oder Blackjack in dieser Kode die Korrekzionen (?) (Mein Deutsch ist auch nicht fabelhaft ;-) geben können.

Ich bin zu unsicher von meine Sache, und brauche für dieses erste Mahl ein bisschen wie ein Lerner die meine Arbeit korrigiert : - )

MFG, Mickeymouse : - )
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mickeymouse hat geschrieben:Ich bin zu unsicher von meine Sache, und brauche für dieses erste Mahl ein bisschen wie ein Lerner die meine Arbeit korrigiert : - )
Kein Problem. Aber ein bißchen was selber tun musst du ja schon... ;)
BlackJack

@Mickeymouse: Overall this class does way too much. Even if program logic independent from the user interface is factored out, there is still too much of the GUI (all of it) crammed into this one class. Try to divide the GUI into smaller widgets implemented in their own classes. For instance the contents of the two tabs can be factored into own widgets.

The setting of absolute sizes for the window should not be necessary. Usually the size of a window should be determined by the space the containing widgets need. You create most widgets in the opposite order one would normally create them and you seem to never set the parent of any Qt object.
Mickeymouse
User
Beiträge: 8
Registriert: Montag 17. Februar 2014, 21:38

Thank you Blackjack,

Can you please show me how it would look like?

Just as you did before, putting instructions inside the code, so I know what to do.

I know it takes some time but if you could do this it would be great, it might sound stupid but I have been struggling for over a month and the only place I am getting some

help is here.

Best regards,

Mickey

If you need any translations from German or English to Spanish, do not hesitate to ask me! : - )
Antworten