From 3686e84581d86d7d8fc2ee22207915304ea84989 Mon Sep 17 00:00:00 2001 From: Mark Jessop Date: Tue, 28 Aug 2018 22:48:29 +0930 Subject: [PATCH] Add serial GPS support (possibly buggy) --- chasemapper/config.py | 4 ++++ chasemapper/gps.py | 29 ++++++++++++++++++++++++----- horusmapper.cfg.example | 10 +++++++++- horusmapper.py | 11 ++++++++++- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/chasemapper/config.py b/chasemapper/config.py index b6f022d..c61cca3 100644 --- a/chasemapper/config.py +++ b/chasemapper/config.py @@ -56,6 +56,10 @@ def parse_config_file(filename): chase_config['car_gpsd_host'] = config.get('gpsd','gpsd_host') chase_config['car_gpsd_port'] = config.getint('gpsd','gpsd_port') + # Serial GPS Settings + chase_config['car_serial_port'] = config.get('gps_serial', 'gps_port') + chase_config['car_serial_baud'] = config.getint('gps_serial', 'gps_baud') + # Predictor chase_config['pred_enabled'] = config.getboolean('predictor', 'predictor_enabled') chase_config['pred_burst'] = config.getfloat('predictor', 'default_burst') diff --git a/chasemapper/gps.py b/chasemapper/gps.py index 6339a54..e68b987 100644 --- a/chasemapper/gps.py +++ b/chasemapper/gps.py @@ -21,12 +21,14 @@ class SerialGPS(object): serial_port = '/dev/ttyUSB0', serial_baud = 9600, timeout = 5, - callback = None): + callback = None, + uberdebug = False): ''' Initialise a SerialGPS object. This class assumes the serial-connected GPS outputs GPRMC and GPGGA NMEA strings - using 8N1 RS232 framing. + using 8N1 RS232 framing. It also assumes the GPGGA string is send after GPRMC. If this + is not the case, position data may be up to 1 second out. Args: serial_port (str): Serial port (i.e. '/dev/ttyUSB0', or 'COM1') to receive data from. @@ -48,9 +50,11 @@ class SerialGPS(object): self.serial_baud = serial_baud self.timeout = timeout self.callback = callback + self.uberdebug = uberdebug # Current GPS state, in a format which matches the Horus UDP # 'Chase Car Position' message. + # Note that these packets do not contain a timestamp. self.gps_state = { 'type': 'GPS', 'latitude': 0.0, @@ -103,7 +107,7 @@ class SerialGPS(object): while self.ser == None and self.serial_thread_running: try: self.ser = serial.Serial(port=self.serial_port,baudrate=self.serial_baud,timeout=self.timeout) - logging.info("SerialGPS - Connected to serial port.") + logging.info("SerialGPS - Connected to serial port %s" % self.serial_port) except Exception as e: # Continue re-trying until we can connect to the serial port. # This should let the user connect the gps *after* this object if instantiated if required. @@ -126,6 +130,7 @@ class SerialGPS(object): try: self.parse_nmea(data.decode('ascii')) except: + traceback.print_exc() pass # Clean up before exiting thread. @@ -157,6 +162,9 @@ class SerialGPS(object): If we have received a GPGGA string containing a position valid flag, send the data on to the callback function. ''' + if self.uberdebug: + print(data.strip()) + if "$GPRMC" in data: logging.debug("SerialGPS - Got GPRMC.") gprmc = data.split(",") @@ -227,6 +235,17 @@ class SerialGPS(object): logging.error("SerialGPS - Error Passing data to callback - %s" % str(e)) +class GPSDGPS(object): + ''' Read GPS data from a GPSD server ''' + + def __init__(self, + hostname = '127.0.0.1', + port = 2947, + callback = None): + ''' Init ''' + pass + + if __name__ == '__main__': import sys, time logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', level=logging.DEBUG) @@ -236,8 +255,8 @@ if __name__ == '__main__': def print_data(data): print(data) - _gps = SerialGPS(serial_port=_port, serial_baud=_baud, callback=print_data) + _gps = SerialGPS(serial_port=_port, serial_baud=_baud, callback=print_data, uberdebug=True) - time.sleep(20) + time.sleep(100) _gps.close() diff --git a/horusmapper.cfg.example b/horusmapper.cfg.example index 31b65e0..683d232 100644 --- a/horusmapper.cfg.example +++ b/horusmapper.cfg.example @@ -28,6 +28,7 @@ telemetry_source_port = 8942 # Car Position Source # none - No Chase-Car GPS # horus_udp - Read Horus UDP Broadcast 'Car GPS' messages +# serial - Read GPS positions from a serial-connected GPS receiver. # gpsd - Poll GPSD for positions (TO BE IMPLEMENTED) car_source_type = horus_udp # Car position source port (UDP) - only used if horus_udp is selected @@ -46,11 +47,18 @@ car_source_port = 55672 [gpsd] -# GPSD Host/Port - Only used if selected in the telemetry profile +# GPSD Host/Port - Only used if selected in a telemetry profile above. # TO BE IMPLEMENTED gpsd_host = localhost gpsd_port = 2947 +[gps_serial] +# Serial GPS Settings - Only used if selected in a telemetry profile above. +# GPS serial device (i.e. /dev/ttyUSB0, COM1, etc...) +gps_port = /dev/ttyUSB0 +# GPS baud rate +gps_baud = 9600 + # Map Defaults [map] diff --git a/horusmapper.py b/horusmapper.py index a818f18..a6c313a 100644 --- a/horusmapper.py +++ b/horusmapper.py @@ -20,6 +20,7 @@ from dateutil.parser import parse from chasemapper.config import * from chasemapper.earthmaths import * from chasemapper.geometry import * +from chasemapper.gps import SerialGPS, GPSDGPS from chasemapper.atmosphere import time_to_landing from chasemapper.listeners import OziListener, UDPListener from chasemapper.predictor import predictor_spawn_download, model_download_running @@ -588,7 +589,7 @@ def start_listeners(profile): try: _thread.close() except Exception as e: - logging.error("Error closing thread.") + logging.error("Error closing thread - %s" % str(e)) # Reset the listeners array. data_listeners = [] @@ -635,6 +636,14 @@ def start_listeners(profile): # GPSD Car Position Source - TODO logging.info("Starting GPSD Car Position Listener.") + elif profile['car_source_type'] == "serial": + # Serial GPS Source. + logging.info("Starting Serial GPS Listener.") + _serial_gps = SerialGPS(serial_port=chasemapper_config['car_serial_port'], + serial_baud=chasemapper_config['car_serial_baud'], + callback=udp_listener_car_callback) + data_listeners.append(_serial_gps) + else: # No Car position. logging.info("No car position data source.")