2011-05-26 131 views
8

我一直在尝试使用标准GPS(gps.py)模块在python 2.6中。这应该是作为客户端,并从Ubuntu中运行的gpsd读取GPS数据。Python GPS模块:读取最新的GPS数据

根据客户端设计(GPSD Client Howto)上GPSD网页的文档,我应该能够使用下面的代码(稍微修改该例子)获取最新的GPS读数(lat long是我主要感兴趣的内容)

from gps import * 
session = gps() # assuming gpsd running with default options on port 2947 
session.stream(WATCH_ENABLE|WATCH_NEWSTYLE) 
report = session.next() 
print report 

如果我重复使用下一个()它给了我缓冲值从队列的底部(从当会话开始),而不是最新的GPS读数。有没有办法使用这个库获得更新的值?在某种程度上,寻找流的最新价值?

有没有人有一个代码示例使用这个库来轮询GPS和获得我正在寻找的价值?

这里就是我想要做:

  1. 启动会话
  2. 等待用户调用gps_poll()方法,在我的代码
  3. 在此方法中阅读最新的TPV (时间位置速度)报告并返回拉特长
  4. 回到等待用户调用gps_poll()

回答

16

你需要做的是定期轮询'session.next()' - 这里的问题是你正在处理一个串行接口 - 你会按照收到的顺序得到结果。它取决于您维护具有最新检索值的“current_value”。

如果你不轮询会话对象,最终你的UART FIFO将被填满,你不会得到任何新的值。

考虑使用一个线程为此,不要等待用户调用gps_poll(),你应该轮询,当用户想要一个新值时,他们使用返回current_value的'get_current_value()'。

关闭我的头顶,但也可能是如此简单:

import threading 
import time 
from gps import * 

class GpsPoller(threading.Thread): 

    def __init__(self): 
     threading.Thread.__init__(self) 
     self.session = gps(mode=WATCH_ENABLE) 
     self.current_value = None 

    def get_current_value(self): 
     return self.current_value 

    def run(self): 
     try: 
      while True: 
       self.current_value = self.session.next() 
       time.sleep(0.2) # tune this, you might not get values that quickly 
     except StopIteration: 
      pass 

if __name__ == '__main__': 

    gpsp = GpsPoller() 
    gpsp.start() 
    # gpsp now polls every .2 seconds for new data, storing it in self.current_value 
    while 1: 
     # In the main thread, every 5 seconds print the current value 
     time.sleep(5) 
     print gpsp.get_current_value() 
+2

答案看起来不错,但睡眠(0.2)不是必需的。 session.next()会阻塞,所以在True循环中不会超载你的cpu。 – 2012-01-27 15:12:37

+1

是'get_current_value()'和'session.next()'原子?如果没有,你需要一个锁或一些同步机制。 – devin 2012-04-02 15:38:27

+0

读取/替换单个实例变量是Python自动执行的线程安全操作。 – synthesizerpatel 2012-04-02 23:43:42

2

添加我的两分钱。

无论出于何种原因,我的覆盆子pi会继续执行一个线程,我不得不重置pi。

所以我把sysnthesizerpatel和我在Dan Mandel的博客here上找到的答案结合起来。

我gps_poller类看起来是这样的:

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

class GpsPoller(threading.Thread): 

    def __init__(self): 
     threading.Thread.__init__(self) 
     self.session = gps(mode=WATCH_ENABLE) 
     self.current_value = None 
     self.running = True 

    def get_current_value(self): 
     return self.current_value 

    def run(self): 
     try: 
      while self.running: 
       self.current_value = self.session.next() 
     except StopIteration: 
      pass 

和所使用的代码如下所示:

from gps_poll import * 

if __name__ == '__main__': 
    gpsp = GpsPoller() 
    try: 
     gpsp.start() 
     while True: 
      os.system('clear') 
      report = gpsp.get_current_value() 
      # print report 
      try: 
       if report.keys()[0] == 'epx': 
        print report['lat'] 
        print report['lon']   
       time.sleep(.5) 
      except(AttributeError, KeyError): 
       pass 
      time.sleep(0.5) 

    except(KeyboardInterrupt, SystemExit): 
     print "\nKilling Thread.." 
     gpsp.running = False 
     gpsp.join() 

    print "Done.\nExiting." 

你也可以在这里找到代码:HereHere

+1

比我建议的更好! – synthesizerpatel 2016-09-13 23:35:38

+0

这段代码很糟糕。每次gpsd发送数据时都会写入'current_value'。通过'time.sleep(.5)','while True'循环设法每隔*时间忽略'epx'报告*,因此根本不打印GPS数据。请注意,这是非常依赖时间的 - 对于某些人来说,它可能每次都工作。如果对'epx'的检查移动到'GpsPoller'类,这将被固定。即使如此,锁定需要添加。 – 2016-12-20 12:47:48

0

的以上回答使用的GPSD的现代版本,并需要在只有特定的时间的数据,而不是流是非常低效和任何人过于复杂。

大多数GPSes每秒传送位置信息至少一次。大概是因为许多基于GPS的应用程序的愿望实时更新,绝大多数的GPSD客户端的例子我见过的使用看,从通用产品安全指令流和接收实时更新的上述方法(或多或少尽可能多的GPS将它们发送) 。但是,如果(如在OP的情况下),你不需要需要流信息,但只要需要最后报告的位置(即通过用户交互或其他事件),就需要最后报告的位置,更简单的方法:让gpsd缓存最新的位置信息,并在需要时查询它。

gpsd JSON protocol有一个?POLL;请求,它返回gpsd已经看到的最新GPS信息。而不必遍历的GPS信息的积压,并不断地阅读新邮件,以避免全缓冲的,你可以在GPSD会话开始发送?WATCH={"enable":true}消息,然后查询最新的位置信息,只要你有?POLL;需要它。响应是包含gpsd从GPS中看到的最新信息的单个JSON对象。

如果您使用Python3,我发现最简单的方法是使用PyPI上可用的gpsd-py3包。要连接到GPSD,获取最新的位置信息,并打印当前位置:

import gpsd 
gpsd.connect() 
packet = gpsd.get_current() 
print(packet.position()) 

可以重复,只要你想新的位置信息gpsd.get_current()呼叫,以及幕后的GPSD包将执行?POLL;调用gpsd并返回表示响应的对象。

与内置gps模块不是非常简单的这样做,但也有一些其他的Python客户可用,并且它也是相当琐碎与任何可以进行socket通信,包括使用telnet这个例子做:

$ telnet localhost 2947 
Trying ::1... 
Connected to localhost. 
Escape character is '^]'. 
{"class":"VERSION","release":"3.16","rev":"3.16","proto_major":3,"proto_minor":11} 
?WATCH={"enable":true} 
{"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/pts/10","driver":"SiRF","activated":"2018-03-02T21:14:52.687Z","flags":1,"native":1,"bps":4800,"parity":"N","stopbits":1,"cycle":1.00}]} 
{"class":"WATCH","enable":true,"json":false,"nmea":false,"raw":0,"scaled":false,"timing":false,"split24":false,"pps":false} 
?POLL; 
{"class":"POLL","time":"2018-03-02T21:14:54.873Z","active":1,"tpv":[{"class":"TPV","device":"/dev/pts/10","mode":3,"time":"2005-06-09T14:34:53.280Z","ept":0.005,"lat":46.498332203,"lon":7.567403907,"alt":1343.165,"epx":24.829,"epy":25.326,"epv":78.615,"track":10.3788,"speed":0.091,"climb":-0.085,"eps":50.65,"epc":157.23}],"gst":[{"class":"GST","device":"/dev/pts/10","time":"1970-01-01T00:00:00.000Z","rms":0.000,"major":0.000,"minor":0.000,"orient":0.000,"lat":0.000,"lon":0.000,"alt":0.000}],"sky":[{"class":"SKY","device":"/dev/pts/10","time":"2005-06-09T14:34:53.280Z","xdop":1.66,"ydop":1.69,"vdop":3.42,"tdop":3.05,"hdop":2.40,"gdop":5.15,"pdop":4.16,"satellites":[{"PRN":23,"el":6,"az":84,"ss":0,"used":false},{"PRN":28,"el":7,"az":160,"ss":0,"used":false},{"PRN":8,"el":66,"az":189,"ss":45,"used":true},{"PRN":29,"el":13,"az":273,"ss":0,"used":false},{"PRN":10,"el":51,"az":304,"ss":29,"used":true},{"PRN":4,"el":15,"az":199,"ss":36,"used":true},{"PRN":2,"el":34,"az":241,"ss":41,"used":true},{"PRN":27,"el":71,"az":76,"ss":42,"used":true}]}]} 
?POLL; 
{"class":"POLL","time":"2018-03-02T21:14:58.856Z","active":1,"tpv":[{"class":"TPV","device":"/dev/pts/10","mode":3,"time":"2005-06-09T14:34:53.280Z","ept":0.005,"lat":46.498332203,"lon":7.567403907,"alt":1343.165,"epx":24.829,"epy":25.326,"epv":78.615,"track":10.3788,"speed":0.091,"climb":-0.085,"eps":50.65,"epc":157.23}],"gst":[{"class":"GST","device":"/dev/pts/10","time":"1970-01-01T00:00:00.000Z","rms":0.000,"major":0.000,"minor":0.000,"orient":0.000,"lat":0.000,"lon":0.000,"alt":0.000}],"sky":[{"class":"SKY","device":"/dev/pts/10","time":"2005-06-09T14:34:53.280Z","xdop":1.66,"ydop":1.69,"vdop":3.42,"tdop":3.05,"hdop":2.40,"gdop":5.15,"pdop":4.16,"satellites":[{"PRN":23,"el":6,"az":84,"ss":0,"used":false},{"PRN":28,"el":7,"az":160,"ss":0,"used":false},{"PRN":8,"el":66,"az":189,"ss":45,"used":true},{"PRN":29,"el":13,"az":273,"ss":0,"used":false},{"PRN":10,"el":51,"az":304,"ss":29,"used":true},{"PRN":4,"el":15,"az":199,"ss":36,"used":true},{"PRN":2,"el":34,"az":241,"ss":41,"used":true},{"PRN":27,"el":71,"az":76,"ss":42,"used":true}]}]}