Python Forum

Full Version: I have written a program that outputs data based on GPS signal
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi guys, new member here!

Im seeking for some advice regarding my program. What does it do? It reads the output from a USB GPS dongle, and calculate the speed. At the same time it iterates though a list of known "TrafficSafetyCamera" (speeding cameras), and warns when you are within 200 meters of a camera. My program also calculates the bearing you are travelling. Really cool and fun project! It would be cool to compile the code to a arduino or raspberry and have have it mounted in my car, with a small LCD or some other feedback system (but thats another thread lol).

What do i need your help with?
  • I understand if it is hard for you to test the code, if you dont own a GPS USB dongle, or can mimick the output from the GPS. But from my understanding, i have written somewhat of "spaghetti code"? It would be cool to refactor the code so look more professional and maybe consume less resources.
  • On line 173, in the __main__ loop, i was trying to clear the terminal so it would be easier to read the output. But when i have os.system('clear') # Why this doesent work???? uncommented, all i get is a blank terminal - how can clear the screen to just have the latest output?
  • This one is rather tricky: if you look in the json data, all entities contains Bearing. I dont want a warning when i approach a camera that is facing the opposite direction. So i was thinking if i could compare the Bearing for the camera and my own bearing, and if the cardinal is in the same "range" - no warning. But if the cardinal is facing each other - warning. But thinking of that math gives me a headache. Please help :)

"""
Calculate if im moving towards the speed camera, or in the oposite direction?
The camera should have the bearing + a few degrees on left side and + a few degrees on the right side.
If im inside that sphere and moving towards center, send a warning.

Or if "our" (myself and the speed camera) has bearings that are opposite?

https://imgur.com/a/qsKvyK4

Would be cool if it was possible to set the radius depending on the vehicle speed. for example 30-50, 100m. 51-80, 200m. 81-120, 300m.

Reference
https://stackoverflow.com/questions/42686300/how-to-check-if-coordinate-inside-certain-area-python
https://www.egr.msu.edu/classes/ece480/capstone/spring15/group14/uploads/4/2/0/3/42036453/wilsonappnote.pdf
https://github.com/Knio/pynmea2
https://api.trafikinfo.trafikverket.se/
"""

from math import radians, cos, sin, asin, sqrt, atan2, degrees
from turtle import distance
import pynmea2
import serial
import json
import time
import re
import os


data = '{"RESPONSE":{"RESULT":[{"TrafficSafetyCamera":[{"Bearing":90,"Deleted":false,"Geometry":{"WGS84":"POINT (23.512141012281944 65.85875907320121)"},"IconId":"trafficSafetyCamera","Id":"25011020","ModifiedTime":"2022-07-16T01:00:28.773Z","Name":"Sangis östra infarten","RoadNumber":"E4"},{"Bearing":102,"Deleted":false,"Geometry":{"WGS84":"POINT (19.056405807546778 64.39662928870855)"},"IconId":"trafficSafetyCamera","Id":"24011010","ModifiedTime":"2022-07-16T01:00:28.288Z","Name":"Lillsele, västlig riktning","RoadNumber":"E12"},{"Bearing":140,"Deleted":false,"Geometry":{"WGS84":"POINT (12.30632048229635 58.31714553521646)"},"IconId":"trafficSafetyCamera","Id":"14009010","ModifiedTime":"2022-07-16T01:00:06.272Z","Name":"Överby TPL","RoadNumber":"E45"},{"Bearing":100,"Deleted":false,"Geometry":{"WGS84":"POINT (13.067072107941183 56.70782672076204)"},"IconId":"trafficSafetyCamera","Id":"13005040","ModifiedTime":"2022-07-16T01:00:06.319Z","Name":"Skärkered Ö","RoadNumber":"25"},{"Bearing":12,"Deleted":false,"Geometry":{"WGS84":"POINT (13.613975014625842 59.49962007485036)"},"IconId":"trafficSafetyCamera","Id":"17003040","ModifiedTime":"2022-07-16T01:00:31.726Z","Name":"Ökna","RoadNumber":"63"},{"Bearing":184,"Deleted":false,"Geometry":{"WGS84":"POINT (13.617570709661589 59.52313500039571)"},"IconId":"trafficSafetyCamera","Id":"17003050","ModifiedTime":"2022-07-16T01:00:31.726Z","Name":"Svedenäs","RoadNumber":"63"},{"Bearing":14,"Deleted":false,"Geometry":{"WGS84":"POINT (13.618532535235428 59.534192009528454)"},"IconId":"trafficSafetyCamera","Id":"17003060","ModifiedTime":"2022-07-16T01:00:31.726Z","Name":"Hasselbol","RoadNumber":"63"},{"Bearing":162,"Deleted":false,"Geometry":{"WGS84":"POINT (18.44183792545111 57.52301130472474)"},"IconId":"trafficSafetyCamera","Id":"09001020","ModifiedTime":"2022-07-16T01:00:06.351Z","Name":"Roma norrgående körfält","RoadNumber":"143"},{"Bearing":218,"Deleted":false,"Geometry":{"WGS84":"POINT (13.65297532183969 59.54845383986109)"},"IconId":"trafficSafetyCamera","Id":"17003070","ModifiedTime":"2022-07-16T01:00:31.726Z","Name":"Strand","RoadNumber":"63"},{"Bearing":350,"Deleted":false,"Geometry":{"WGS84":"POINT (18.44217434520964 57.521617721193515)"},"IconId":"trafficSafetyCamera","Id":"09001010","ModifiedTime":"2022-07-16T01:00:06.366Z","Name":"Roma södergående körfält","RoadNumber":"143"},{"Bearing":344,"Deleted":false,"Geometry":{"WGS84":"POINT (17.01189040432663 59.49294222471462)"},"IconId":"trafficSafetyCamera","Id":"04001060","ModifiedTime":"2022-07-16T01:00:06.429Z","Name":"Säby","RoadNumber":"55"},{"Bearing":174,"Deleted":false,"Geometry":{"WGS84":"POINT (17.01207008841139 59.49299335496056)"},"IconId":"trafficSafetyCamera","Id":"04001050","ModifiedTime":"2022-07-16T01:00:06.429Z","Name":"Säby","RoadNumber":"55"},{"Bearing":73,"Deleted":false,"Geometry":{"WGS84":"POINT (15.431850074330953 59.15232847147721)"},"IconId":"trafficSafetyCamera","Id":"18008020","ModifiedTime":"2022-07-16T01:00:06.460Z","Name":"Askersby","RoadNumber":"52"},{"Bearing":269,"Deleted":false,"Geometry":{"WGS84":"POINT (15.445158464307017 59.15395393742257)"},"IconId":"trafficSafetyCamera","Id":"18008030","ModifiedTime":"2022-07-16T01:00:06.444Z","Name":"Tybble","RoadNumber":"52"},{"Bearing":220,"Deleted":false,"Geometry":{"WGS84":"POINT (15.402092808949154 59.14480847501118)"},"IconId":"trafficSafetyCamera","Id":"18008010","ModifiedTime":"2022-07-16T01:00:06.460Z","Name":"Norrbyås","RoadNumber":"52"},{"Bearing":106,"Deleted":false,"Geometry":{"WGS84":"POINT (15.52521062939519 59.154588974075914)"},"IconId":"trafficSafetyCamera","Id":"18008050","ModifiedTime":"2022-07-16T01:00:06.491Z","Name":"Odensbacken","RoadNumber":"52"}]}]}}'

#f = open('trafikkameror.json')
#y = json.load(f)

y = json.loads(data)

"""
Convert the ['Geometry']['WGS84'] to readable text
"""


def lattify(string):
    x = re.search("\(([^\)]+)\)", string)

    x = x[0].replace('(', '').replace(')', '').split(' ')

    return float(x[1]), float(x[0])
    # x[1] N lat
    # x[0] E long


"""
Calculate the distance with haversine
"""


def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a))
    r = 6371  # Radius of earth in kilometers. Use 3956 for miles
    return c * r


"""
TESTING THE HAVERSINE CODE BELOW.
"""


def heading(location):
    # TESTING TO ITERATE THE JSON DATA
    # Grabbing speedcamera position
    for i in y['RESPONSE']['RESULT']:
        for b in i['TrafficSafetyCamera']:
            # print(b['Name'])
            # print(b['Bearing'])
            # print(coordinates[0], coordinates[1])
            # print('')
            coordinates = lattify(b['Geometry']['WGS84'])

            # "MY" POSITION
            posasdad = location.split(' ')
            my_location = [
                {'lat': float(posasdad[0]), 'lng': float(posasdad[1])}]

            # The static speed camera position
            speed_camera_center_point = [
                {'lat': coordinates[0], 'lng': coordinates[1]}]

            lat1 = speed_camera_center_point[0]['lat']
            lon1 = speed_camera_center_point[0]['lng']
            lat2 = my_location[0]['lat']
            lon2 = my_location[0]['lng']

            radius = 0.2  # in kilometer

            a = haversine(lon1, lat1, lon2, lat2)

            # print('Distance (km) : ', a)
            if a <= radius:
                # print(b['Name'])
                # print('Inside the area')
                return True


"""
The GPS functionhere... Should be called inside of __main__
"""


def gps_function():
    ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=5)

    prev_data = None

    while 1:
        ### Wrpped the readline() in a try. Got a decode error sometimes.
        try:
            line = ser.readline().decode('UTF-8')
        except UnicodeDecodeError as e:
            print(e)
            continue
        splitline = line.split(',')

        if splitline[0] == '$GPGGA':
            msg = line
            data = pynmea2.parse(msg)
            if prev_data is not None:
                distance = haversine(
                    data.longitude, data.latitude, prev_data.longitude, prev_data.latitude)

                ###
                #bearing = atan2(sin(prev_data.longitude-data.longitude)*cos(prev_data.latitude), cos(data.latitude)*sin(prev_data.latitude)-sin(data.latitude)*cos(prev_data.latitude)*cos(prev_data.longitude-data.longitude))
                bearing = atan2(sin(prev_data.longitude-data.longitude)*cos(data.latitude), cos(prev_data.latitude)*sin(
                    prev_data.latitude)-sin(prev_data.latitude)*cos(data.latitude)*cos(prev_data.longitude-data.longitude))
                bearing = degrees(bearing)
                bearing = (bearing + 360) % 360

                speed = round(distance*3600, 2)
                lat = data.longitude
                lng = data.latitude

                return distance, speed, bearing, lat, lng
                # print('distance', distance)
                # print('speed', round(distance*3600, 2))
                # print('bearing', bearing)
            prev_data = data


if __name__ == '__main__':
    try:
        while True:
            distance, speed, bearing, lat, lng = gps_function()

            #print('Distance:', distance)
            print('######################')
            print('Speed:', speed)
            print('Bearing:', bearing)

            location = "{} {}".format(lng, lat)
            x = heading(location)
            if x:
                print(
                    'It seems that you are inside the 200 meter radius of a speed camera!')
            # os.system('clear') # Why this doesent work????
    except KeyboardInterrupt:
        exit()
    finally:
        print("Exit")
I appreciate your input
Could you put the os.system('clear') at the beginning of the While Loop?