Skip to content Skip to sidebar Skip to footer

How Can I Get Data Without Blocking?

I have a serial port external device for getting data. I set two timers. One of them has to be for plotting(0.5sn) and the other for writing to a text file(15sn). Timers shouldn't

Solution 1:

You don't need to use 2 Timers to periodically save data. And you do not need to use Threads either. Just keep a counter variable in your main Frame class (or the class with the Timer and collecting the data -- your example is simple enough that it may not need splitting) and use that to determine when to write data. Also: keep the data read from the serial port in an array in the same class so you can plot it or save it or whatever else you might want:

in MyFrame1.__init__() add

self.last_saved_time = 0self.plotting = Trueself.data = []

Then in MyFrame1.timer1() do

# read and save data
 t1 = next_data()
 self.data.append(t1) # (or do more parsing, convert to numpy arrays, etc# send to plotting if it is enabledifself.plotting:  
      self.plot_data()

 # save if needed
 now = time.time()
 if (now - self.last_saved_time) > 15:
      self.save_data_to_file() 

Again, you do not necessarily need two timers or threads. You could do the plotting or the i/o in a separate thread, but you're going relatively slowly.

It would probably be wiser to eventually split up the code as "data collector" class with its own event loop and then transfer that to the GUI frame to plot as needed. But the example is small enough that such a refactoring is not needed yet.

Solution 2:

For non blocking operations with Gui / wxpython you need to use threads, you can use wx.lib.delayedresult

or you can use "threading" python module which i prefer

also if you need to get text data from a serial port you should decode them in utf-8, example:

ser = serial.Serial('COM9',9600)
try:
    line = ser.readline()
    line = line.decode("utf-8")
except UnicodeDecodeError:
    line = "\ncan't decode from serial, choose different baudrate\n"print(line)  # or do whatever you want with line

also this is an example for reading serial port using threading you can use it as an idea of what you want to do

i added explanation comments in the code

from threading import Thread
from time import sleep

# you can define a class inherited from Thread class or simply use a function classReadData(Thread):
    def__init__(self):
        super().__init__()
        self.running = True# used as signal to kill the thread
        self.ser = serial.Serial('COM9',9600)  # open serialdefrun(self):  # run method need to be defined for threading to workwhile self.running:
            print('running')
            sleep(1)
        self.ser.close()

    defread(self):  # reading data from portif ser.is_open: 
            try:
                line = ser.readline()
                line = line.decode("utf-8")  # decode data except UnicodeDecodeError:
                line = "\ncan't decode from serial, choose different baudrate\n"
                display(line)
                line = ""defkill(self):  # terminate thread safely
        self.running = False

read_data = ReadData()  # define new thread object
read_data.start()  # start the thread

sleep(5)

# in case you want to kill the running threadprint('killing running thread')
read_data.kill()

Edit:

to communicate between your thread and main GUI i.e. you want to pass the serial data safely you should avoid using global variable and use queues instead, you can check this answer for how to use them

Post a Comment for "How Can I Get Data Without Blocking?"