2011-05-26 19 views
8

He estado tratando de trabajar con el módulo de GPS (gps.py) estándar en python 2.6. Se supone que esto debe actuar como un cliente y leer datos GPS de gpsd que se ejecutan en Ubuntu.Módulo de GPS de Python: leyendo los últimos datos de GPS

De acuerdo con la documentación de la página web de GPSD en el diseño del cliente (GPSD Client Howto), podré usar el siguiente código (ligeramente modificado del ejemplo) para obtener las últimas lecturas de GPS (en latitud es lo que más me interesa)

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 

Si utilizo repetidamente la siguiente, y no la lectura() me da valores de búfer de la parte inferior de la cola (desde que se inició la sesión) GPS más recientes. ¿Hay alguna manera de obtener valores más recientes usando esta biblioteca? En cierto modo, busca el flujo a los últimos valores?

¿Alguien ha obtenido un ejemplo de código usando esta biblioteca para sondear los gps y obtener el valor que estoy buscando?

Aquí es lo que estoy tratando de hacer:

  1. iniciar la sesión
  2. Espere usuario llamar al método gps_poll() en mi código
  3. Dentro de este método de leer el último TPV (Tiempo Posición velocidad) informe y volver lat largo
  4. volver a la espera de usuario llamar gps_poll()

Respuesta

16

Lo que necesita hacer regularmente es sondear 'session.next()' - el problema aquí es que está tratando con una interfaz en serie - obtiene resultados en el orden en que fueron recibidos. Depende de usted mantener un 'valor_actual' que tenga el último valor recuperado.

Si no sondea el objeto de la sesión, eventualmente su UART FIFO se llenará y de todos modos no obtendrá ningún valor nuevo.

Considere usar un hilo para esto, no espere a que el usuario llame a gps_poll(), debe sondear y cuando el usuario desee un nuevo valor, use 'get_current_value()' que devuelve current_value.

De la parte superior de mi cabeza que podría ser algo tan simple como esto:

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

La respuesta es buena, pero la suspensión (0.2) no es necesaria. session.next() bloqueará, por lo que tenerlo en el while True loop no sobrecargará tu CPU de todos modos. –

+1

son 'get_current_value()' y 'session.next()' atomic? Necesitas un candado o algún mecanismo de sincronización si no es así. – devin

+0

Leer/reemplazar una sola variable de instancia es una operación de seguridad de subprocesos automáticamente con Python. – synthesizerpatel

2

Adición de mis dos centavos.

Por alguna razón, mi raspberry pi continuaría ejecutando un hilo y tendría que restablecer el pi.

Así que he combinado sysnthesizerpatel y una respuesta que encontré en el blog de Dan Mandel here.

Mi clase gps_poller se parece a esto:

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 

Y el código en uso es el siguiente:

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." 

También puede encontrar el código aquí: Here y Here

+1

¡Mejor de lo que sugerí! – synthesizerpatel

+0

Este código es malo. 'current_value' se escribe cada vez que gpsd envía datos. Con el 'time.sleep (.5)', el bucle 'while True' se las arregla para perder el informe' epx' * cada * vez, por lo que no imprime ningún dato de GPS en absoluto. Tenga en cuenta que esto depende mucho del tiempo, para algunas personas puede * funcionar * cada vez. Esto se solucionará si la comprobación de 'epx' se mueve a la clase' GpsPoller'. Incluso entonces, se necesita agregar bloqueo. –

0

El las respuestas anteriores son muy ineficientes y demasiado complejas para cualquiera que use las versiones modernas de gpsd y necesite datos solo en momentos específicos, en lugar de transmitir.

La mayoría de los GPS envían su información de posición al menos una vez por segundo. Presumiblemente debido a que muchas aplicaciones basadas en GPS desean actualizaciones en tiempo real, la gran mayoría de los ejemplos de clientes gpsd que he visto utilizan el método anterior para ver una transmisión de gpsd y recibir actualizaciones en tiempo real (más o menos tan a menudo como los gps) .

Sin embargo, si (como en el caso de la OP) no lo hace necesidad transmisión de información, sino que sólo tiene la reportada última posición cada vez que se solicita (la interacción del usuario es decir, a través de o algún otro evento), hay una mucho más eficiente y método más simple: permita a gpsd almacenar en caché la última información de posición y consultarla cuando sea necesario.

El gpsd JSON protocol tiene una solicitud ?POLL;, que devuelve la información de GPS más reciente que gpsd ha visto. En lugar de tener que iterar sobre la acumulación de mensajes gps y leer continuamente nuevos mensajes para evitar búferes completos, puede enviar un mensaje ?WATCH={"enable":true} al comienzo de la sesión gpsd y luego consultar la última información de posición siempre que lo necesite con ?POLL;. La respuesta es un objeto JSON único que contiene la información más reciente que gpsd ha visto desde el GPS.

Si está utilizando Python3, la forma más fácil que he encontrado es usar el paquete gpsd-py3 disponible en pypi. Para conectarse a gpsd, obtener la última información de la posición, e imprimir la posición actual:

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

puede repetir el gpsd.get_current() llamada en cualquier momento nueva información de la posición, y detrás de las escenas el paquete gpsd ejecutará la llamada ?POLL; a gpsd y devuelve un objeto que representa la respuesta.

Hacer esto con la no incorporada gps módulo es terriblemente sencillo, pero hay una serie de otros clientes Python disponibles, y también es bastante trivial que ver con cualquier cosa que pueda realizar una comunicación de zócalo, incluyendo este ejemplo utilizando 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}]}]}