Почему таймер повреждает мои данные, когда я отображаю более двух значений? - PullRequest
0 голосов
/ 10 апреля 2019

Я использую таймер для черчения и хранения одновременно.Когда я отображаю 2 значения, нет потери данных с последовательного порта (60 строк в минуту, мое устройство = 1 Гц).Но когда я пытаюсь построить более двух значений, это повредит данные (~ 40 строк в минуту).

1.Мне попробовать thread или queue вместо wx.Timer?

2.Почему wx.Timer повреждает мои данные?или в чем проблема?

3. Должен ли я использовать последовательный порт func.внутри wx.Timer ??

Где я делаю что-то не так и что?Мне нужна ваша помощь.Любая помощь будет оценена.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import wx
import wxmplot
import serial
import serial.tools.list_ports
import numpy as np

is_wxPhoenix = 'phoenix' in wx.PlatformInfo
if is_wxPhoenix:
    PyDeadObjectError = RuntimeError
else:
    from wx._core import PyDeadObjectError



class myframe ( wx.Frame ):          #Panel ###(reading, saving, plotting as a real-time from serial port)

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent )

        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.plotframe = None

        self.toggleBtn17 = wx.ToggleButton( self, wx.ID_ANY, u"GRAPH", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add( self.toggleBtn17, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )

        self.toggleBtn171 = wx.ToggleButton( self, wx.ID_ANY, u"Store", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.toggleBtn171.Hide()
        bSizer1.Add( self.toggleBtn171, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )

        self.toggleBtn4 = wx.ToggleButton( self, wx.ID_ANY, u"Save", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.toggleBtn4.Hide()
        bSizer1.Add( self.toggleBtn4, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )

        self.timer1 = wx.Timer()
        self.timer1.SetOwner( self, 1 )

        self.timer2 = wx.Timer()
        self.timer2.SetOwner( self, 2 )
        self.timer2.Start( 1000 )                           ### running when app begins

        self.timer3 = wx.Timer()
        self.timer3.SetOwner( self, 3 )
        self.timer3.Start( 15000 )       #999               ### running when app begins

        self.Centre( wx.BOTH )
        self.SetSizer( bSizer1 )

        # Connect Events
        self.toggleBtn17.Bind( wx.EVT_TOGGLEBUTTON, self.plot_aio )
        self.Bind( wx.EVT_TIMER, self.timer1_plot, id=1 )

        self.toggleBtn171.Bind( wx.EVT_TOGGLEBUTTON, self.store_f )
        self.Bind( wx.EVT_TIMER, self.timer2_store, id=2 )

        self.toggleBtn4.Bind( wx.EVT_TOGGLEBUTTON, self.save_f )
        self.Bind( wx.EVT_TIMER, self.timer3_save, id=3 )

        self.x1 = np.array([])              # coming data from serial port should list. in wxmplot, numpy array is the best choice for appending data
        self.y1 = np.array([])       
        self.y2 = np.array([])
        self.y3 = np.array([])

        self.store = []
        self.store_tempr = []

        self.ser = serial.Serial('COM9', 9600)

    def ShowPlotFrame(self, do_raise=True, clear=True):   
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = wxmplot.MultiPlotFrame(rows=3, cols=3, panelsize=(350, 275))
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = wxmplot.MultiPlotFrame(rows=3, cols=3, panelsize=(350, 275))
            self.plotframe.Show()
        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            #self.plotframe.reset_config()

    def plot_aio( self, event ):                    ### plot button(timer 1)             
        if self.timer1.IsRunning():
            self.timer1.Stop()
            print("timer1  stopped")
        else:
            print("tgl_timer1  starting...")
            self.ShowPlotFrame()        
            self.timer1.Start( 500 )    

    def store_f( self, event ):                     ### store in the numpy array button but both Timer activated and Button hidden(timer 2)
        event.Skip()
        #=======================================================================
        # if self.timer2.IsRunning():
        #     self.timer2.Stop()
        #     print("saving stopped")
        # else:
        #     print("saving_timer2 is starting...")
        #     self.timer2.Start( 1000 )
        #=======================================================================

    def save_f( self, event ):                       ### del the storing data button for not using more memory (both Timer activated and Button hidden)
        event.Skip()
        #=======================================================================
        # if self.timer3.IsRunning():
        #     self.timer3.Stop()
        #     print("timer 3  stopped")
        # else:
        #     print("tgl_timer 3  starting...")
        #     self.timer3.Start( 10000 )           #501  
        #=======================================================================

    def timer1_plot( self, event ):                 ### PLOT STORED DATA (not button but entegrated with plot_aio func which is button)            
        for line in self.store_tempr:
            data=line.split(b",")
            if data[0] == b"$GNGGA":
                tim2=data[1]
                timm=float(tim2)
                tim=timm+30000                            
                hour = tim//10000
                minute = (tim//100)%100
                second = tim%100
                zaman = hour*3600 + minute*60 + second    
                self.x1 = np.append(self.x1, zaman)  

                latitude=data[2]
                lat=float(latitude)
                lat1=int(lat/100)
                lat2=(lat%100)/60
                lati=lat1+lat2
                self.y2 = np.append(self.y2, lati)

                longitude=data[4]
                lon=float(longitude)
                lon1=int(lon/100)
                lon2=(lon%100)/60
                longi=lon1+lon2
                self.y3 = np.append(self.y3, longi)

                altitude=data[9]
                self.y1 = np.append(self.y1, float(altitude))

                self.ShowPlotFrame()  
                self.plotframe.plot(self.x1, self.y1, panel=(0, 0), labelfontsize=6) 
                self.plotframe.plot(self.x1, self.y3, panel=(0, 1), color='red',  labelfontsize=6)
                self.plotframe.plot(self.y1, self.x1, panel=(1, 0), color='black', labelfontsize=5) 
                self.plotframe.plot(self.y2, self.y3, panel=(1, 1), fullbox=False) 
                self.plotframe.plot(self.x1, self.y1, panel=(0, 2), labelfontsize=6) 
                self.plotframe.plot(self.x1, self.y3, panel=(2, 1), color='red',  labelfontsize=6)
                self.plotframe.plot(self.y1, self.x1, panel=(2, 0), color='black', labelfontsize=5) 
                self.plotframe.plot(self.y2, self.y3, panel=(2, 2), fullbox=False) 


        del self.store_tempr[:]

    def timer2_store( self, event ):                ### STORE and WRITE TO .TXT FILE AND DELETE FROM THE LIST (not button)
        print( "storing and saving")
        for line in self.ser:
            self.store.append(line)
            self.store_tempr.append(line)


    def timer3_save( self, event ):                  ### DELETE STORED DATA IN THE LIST (not button)
        with open("C:\\Users\\Desktop\\4n.txt","a") as f: 
            for line in self.store:            
                f.writelines(str(line)+ "\n")
            del self.store[:]



if __name__ == "__main__":
    app = wx.App(False)
    frame = myframe(None)
    frame.Show(True)
    app.MainLoop()

1 Ответ

1 голос
/ 10 апреля 2019

Я думаю, вам не нужно использовать Threads или Queues вместо wx.Timers.Но я также думаю, что вам на самом деле нужен только 1 wx.Timer, который проверяет и получает данные из последовательного порта (или другого источника данных).Я бы предложил, чтобы обработчик для событий wx.Timer (вероятно, работающих на ~ 2 Гц, если вы ожидаете данные на 1 Гц) должен делать следующее:

  1. проверять новые данные.если нет новых данных, немедленно вернитесь, ожидая следующего события wx.Timer.

  2. , если появятся новые данные, сразу же проанализируйте и выполните расчеты на основе этих данных и добавьте ихк массивам данных в этом обработчике событий.Просто удалите все сохраняемые и последующие удаления временных данных, и вы будете self.x1, self.y1 и т. Д. Обновлены, когда закончится обработчик события данных.Все эти del XXX в вашем коде - тем более, что один обработчик событий удаляет данные, созданные в другом месте, - похоже, что они могут быть проблемой.

  3. , а затем обновлять графики.Если вы считаете, что построение графика будет медленным, вы можете использовать второе событие таймера, которое проверяет, изменилась ли длина self.x1, и переделать график (ы).Но я считаю, что вам не нужно использовать второй таймер, и вы можете просто обновить графики в обработчике событий данных.

Например, как это можно сделать,см. https://github.com/newville/wxmplot/blob/master/examples/stripchart.py, который использует только один wx.Timer, который выбирает новые данные и обновляет график.Обратите внимание, что он использует wxmplot.PlotPanel.update_line(), что намного быстрее при обновлении существующего графика, чем повтор wxmplot.PlotPanel.plot() для каждого нового набора данных.

Функция next_data() в этом примере немного проще и более детерминирована, чемвам нужно сделать, чтобы прочитать данные из последовательного порта.Но вы уже делаете эту часть, и то, что вы делаете, выглядит не слишком сложно и не медленно.

...