4

次のpythonスクリプトがあります:

#! /usr/bin/python

import os
from gps import *
from time import *
import time
import threading
import sys

gpsd = None #seting the global variable

class GpsPoller(threading.Thread):
   def __init__(self):
      threading.Thread.__init__(self)
      global gpsd #bring it in scope
      gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
      self.current_value = None
      self.running = True #setting the thread running to true

   def run(self):
      global gpsd
      while gpsp.running:
         gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer

if __name__ == '__main__':
   gpsp = GpsPoller() # create the thread
   try:
      gpsp.start() # start it up
      while True:

         print gpsd.fix.speed

         time.sleep(1) ## <<<< THIS LINE HERE

   except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
      print "\nKilling Thread..."
      gpsp.running = False
      gpsp.join() # wait for the thread to finish what it's doing
   print "Done.\nExiting."

残念ながら、私はPythonがあまり得意ではありません。スクリプトは何らかの形でマルチスレッド化する必要があります(ただし、この質問の範囲ではおそらく問題になりません)。

私を当惑させるのはgpsd.next()ラインです。正しく理解できれば、新しい GPS データが取得され、読み取る準備ができていることをスクリプトに伝えることになっていました。

ただし、 でwhile True1 秒の一時停止を伴う無限ループを使用してデータを読み取りますtime.sleep(1)

ただし、これにより、同じデータが 2 回エコーされることがあります (センサーは最後の 1 秒間でデータを更新していません)。どういうわけかセンサーデータもスキップすると思います。

スクリプトを変更して、毎秒ではなく、センサーが新しいデータを報告するたびに現在の速度を出力することはできますか? データシートによると、毎秒 (1 Hz センサー) である必要がありますが、明らかに正確に 1 秒ではなく、ミリ秒単位で変化します。

4

2 に答える 2

2

一般的な設計規則として、入力チャネルごとに 1 つのスレッド、または「ブロッキング呼び出しのループ」ごとに、より一般的なスレッドを作成する必要があります。ブロッキングとは、データが到着するまで実行がその呼び出しで停止することを意味します。たとえばgpsd.next()、そのような呼び出しです。

複数の入力チャネルを同期するには、Queueと 1 つの余分なスレッドを使用します。各入力スレッドは、その「イベント」を (同じ) キューに入れる必要があります。余分なスレッドがループしqueue.get()、適切に反応します。

この観点からすると、入力チャネルは 1 つしかないため、つまりgpsd.next()ループであるため、スクリプトをマルチスレッド化する必要はありません。

コード例:

from gps import *

class GpsPoller(object):
   def __init__(self, action):
      self.gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
      self.action=action

   def run(self):
      while True:
         self.gpsd.next()
         self.action(self.gpsd)

def myaction(gpsd):
    print gpsd.fix.speed

if __name__ == '__main__':
   gpsp = GpsPoller(myaction)
   gpsp.run() # runs until killed by Ctrl-C

actionコールバックを使用すると、配管がデータ評価からどのように分離されるかに注意してください。

他のことを行う (つまり、他のスレッドも処理する) スクリプトにポーラーを埋め込むには、キュー アプローチを使用します。GpsPollerクラスに基づいたコード例:

from threading import Thread
from Queue import Queue

class GpsThread(object):
    def __init__(self, valuefunc, queue):
        self.valuefunc = valuefunc
        self.queue = queue
        self.poller = GpsPoller(self.on_value)

    def start(self):
        self.t = Thread(target=self.poller.run)
        self.t.daemon = True  # kill thread when main thread exits
        self.t.start()

    def on_value(self, gpsd):
        # note that we extract the value right here.
        # Otherwise it could change while the event is in the queue.
        self.queue.put(('gps', self.valuefunc(gpsd)))


def main():
    q = Queue()
    gt = GpsThread(
            valuefunc=lambda gpsd: gpsd.fix.speed,
            queue = q
            )
    print 'press Ctrl-C to stop.'
    gt.start()
    while True:
        # blocks while q is empty.
        source, data = q.get()
        if source == 'gps':
            print data

GpsPoller に与える「アクション」は、「valuefunc で値を計算し、それをキューに入れる」と言います。メインループは、値が飛び出すまでそこに留まり、それを出力して続行します。

他のスレッドのイベントをキューに入れ、適切な処理コードを追加することも簡単です。

于 2016-08-09T09:43:19.747 に答える