I have broken down code for adding it into Further after we have a call about that
@CAProjects: Have tried today today the code but I am getting some errors.
- Import error
To fix this i changed name from miniscreen to OLED
After this the code seemed to be working as I could see the screen clearing.
- nmea_display(nmeaDecode(l)) followed by a couple more errors.
The GPS had a fix as the green light was blinking suggesting that (this is a Ublox 7 gps usb). Also running the “grep “GPGSA” --line-buffered < /dev/ttyACM0” did output the coordinates in the terminal.
Would you happen to know what could be causing this? Would be very greatful if you could help me with fixing this.
Many thanks
Is your OS and firmware etc up to date? That import errors suggests an older version of the SDK which would also explain the 2nd error. I think OLED was an old function so your SDK may be out of date. All the errors you get are SDK related
If you have a spare SD card try flashing it with the latest OS image and try on a fresh up to date install
https://www.pi-top.com/products/os
All the code runs perfectly on my system which is always kept up to date
You can also try updating the SDK via pip3?
Also I run the code without sudo
Thanks for the quick reply, my OS (Buster) is up to date. I need to check the firmware. But to be on the safe side will do a fresh up to date install as suggested. One thing I wanted to ask, can I run both the pi-top menu system and this code? For example if the menu system is showing on the pi-top, when this code is executed will it display the gps data on the oled display or do I need to kill the process for oled menu system firsr? Thanks
When you run the code it will basically disable the menu and the script will only be on the screen. Nothing else is programmed. When we get an update to the system menu, I will look into converting it into a system widget.
No need to disable the the system menu service. When you run the script the screen will go blank then display the info on the first successful parse. When you stop the script, the system menu will return
I went back on your last reply and I think I misunderstood something. You mentioned a fresh up to date install and provided the link to Pi-top OS Sirius. In my case I am not running Pi-top OS, I am running Raspbian Buster.
When running pi-top device hub I get the following output:
I did tinker a bit with the gps code you provided and the issue is with the nmea decode variables (longitude, altitude, etc). If I comment these out:
displays the required GPS data
# to the pi-top[4] miniscreen
canvas.rectangle(ms.bounding_box, fill=0)
canvas.text((0, 0),f"Lat: {data['latitude']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 12),f"Lon: {data['longitude']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 24),f"Spd: {data['speed']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 36),f"Fix: {'Yes' if data['fix'] else 'No'}, {data['fix_type']}, {data['satelites']} Sats",font=ImageFont.load_default(),fill=1)
canvas.text((0, 48),f"UTC:{data['date_time']}",font=ImageFont.load_default(),fill=1)
And display a simple text, the text is shown on the display and the code runs perfectly.
Could for example f"Lon: {data[‘longitude’]}" be replaced with something else to see if this would work? As this is the part I think is breaking the code in my case?
Also does the code require a gps fix in order to output on the screen? Or can it display and populate the gps details when a fix is established?
I do apologies I am not very versed in terms of programming. I am still learning.
Thanks again for your support!
I’m at work atm will look at it when at home
I double checked the code on my repo and it’s all good
nmea_display(nmeaDecode(l))
This line sends a list of NMEA statements to def nmeaDecode to Extract dada from in to a dictionary and returns the dictionary and sends that to def nmea_display
f"Lon: {data[‘longitude’]}” is a formatted string that displays the text Lon: and the information in the dictionary with the key ‘longitude’
KeyError your getting means it cannot find the entry in the dictionary with that key name.
When I get home I will give you the code with print statements in it to see what the code is actually doing, if it’s actually getting the information or not
@Luis try running this and screenshot the print statements
I also forgot to add the KeyboardInterupt (ctrl+c) exception which clears the screen and exits the script
import io
import serial
from pitop.miniscreen import Miniscreen
from PIL import Image, ImageDraw, ImageFont
# Serial setup
serialConf = serial.Serial('/dev/ttyAMA0', 9600,timeout=0.3)
serialio = io.TextIOWrapper(io.BufferedRWPair(serialConf, serialConf))
# Enable only NMEA sentences required
serialConf.write(b'$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1*34\r\n')
# pi-top[4] Miniscreen setup
ms = Miniscreen()
image = Image.new(ms.mode, ms.size,)
canvas = ImageDraw.Draw(image)
ms.set_max_fps(1)
# NMEA sentences required
nmea_list = ['$GPGGA', '$GPGSA', '$GPRMC', '$GPZDA']
def speedCalc(data, u):
#converts speed to user required units
if u == 1:
return f'{round((float(data) * 1.150779448),1)} MPH'
elif u == 2:
return f'{round((float(data) * 1.852),1)} KM/H'
elif u == 3:
return f'{round((float(data) * 1.943844),1)} m/s'
else:
return f'{round(float(data),1)} kn'
def coordDecode(data, b):
#decodes lat and lon co-ordinates from GPS NMEA
sec = round((60*float(f"0.{data.split('.')[1]}")),4)
return f"{data.split('.')[0][0:-2]}{b} {data.split('.')[0][-2:]}m {sec}s "
def nmeaDecode(data):
#create dictionary to put data into
nmea_dict = {}
# for each NMEA sentence, extract the data required
# and add it to the dictionary
for x in data:
if x[0] == '$GPGGA':
nmea_dict['satelites'] = int(x[7])
nmea_dict['altitude'] = f'{x[9]} {x[10]}'
print(f'GPGGA {nmea_dict}')
elif x[0] == '$GPGSA':
nmea_dict['fix'] = True if int(x[2]) > 1 else False
nmea_dict['fix_type'] = f'{x[2]}D' if int(x[2]) > 1 else ''
print(f'GPGSA {nmea_dict}')
elif x[0] == '$GPRMC':
#decodes lat and lon to degrees and mins
nmea_dict['latitude'] = coordDecode(x[3], x[4])
nmea_dict['longitude'] = coordDecode(x[5], x[6])
# for speed, it can be calculated in MPH, KM/H, m/s Knots
# 1 = MPH | 2 = KM/H | 3 = m/s | any other no. for knots
nmea_dict['speed'] = speedCalc(x[7], 1)
print(f'GPRMC {nmea_dict}')
elif x[0] == '$GPZDA':
# gets the date and time from GPS
nmea_dict['date_time'] = f'{x[2]}/{x[3]}/{x[4][-2:]} {x[1][0:2]}:{x[1][2:4]}:{x[1][4:6]}'
print(f'GPZDA {nmea_dict}')
print(nmea_dict)
# return the dictionary
return nmea_dict
def nmea_display(data):
# displays the required GPS data
# to the pi-top[4] miniscreen
canvas.rectangle(ms.bounding_box, fill=0)
canvas.text((0, 0),f"Lat: {data['latitude']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 12),f"Lon: {data['longitude']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 24),f"Spd: {data['speed']}",font=ImageFont.load_default(),fill=1)
canvas.text((0, 36),f"Fix: {'Yes' if data['fix'] else 'No'}, {data['fix_type']}, {data['satelites']} Sats",font=ImageFont.load_default(),fill=1)
canvas.text((0, 48),f"UTC:{data['date_time']}",font=ImageFont.load_default(),fill=1)
ms.display_image(image)
while 1:
try:
# create a list for NMEA sentences
l=[]
# Get NMEA sentence
s = serialio.readline().strip().split(',')
# look for the start of the sentence queue
if s[0] =='$GPGGA':
# get all the sentences that matches the list
for x in nmea_list:
print(f'GPS DATA: {s}')
# add sentence to the list
l.append(s)
# get next sentence
s = serialio.readline().strip().split(',')
# decode the NMEA sentences and display the information
# on the pi-top[4] miniscreen
print(f'NMEA List: {l}')
nmea_display(nmeaDecode(l))
# This exeption is to prevent the script from crashing if there
# is some garbled GPS data that cannot be decoded to UTF-8
# this normally happens at the start of running the script
# and is away of ignoring it
except UnicodeDecodeError as e:
continue
except KeyboardInterrupt:
ms.clear()
exit()
@CAProjects Thanks a lot for looking into this, much appreciated
This is the output I got:
The GPS has no fix at the moment as I am indoors and I don’t have a fix with it indoors due to its poor antenna.
In the code I changed to /dev/ttyACM0.
Thanks
ah, that’s why that is happening, its because there is no fix. forgot to check for fix before getting data, my bad, will look into that this week
Looks like your also not getting GPRMC data which I use to get lat and lon coords, can you change the line
serialConf.write(b’$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1*34\r\n’)
And change all 0’s to 1’s and re run?
I’ve had a chance to run this just now, here is the output when changing all to 1 (this is without gps fix):
I’ve done some research and it seems the pi 4 doesn’t go along to well with this usb gps. It’s taking an awful long to get a gps fix and connecting anything on the usb 3.0 ports makes the reception and fix almost impossible. I’ve ordered a new gps module (with ext antenna) that is going to be connected via gpio instead of usb. Hopefully this will fix the bad reception and gps fix issues. Thanks
Later edit: tested indoors with a 1m usb extension cable and the gps dongle gets a gps fix/lock. It seems the interference issues are true.
With the gps fix I still get the same error.
GPS can take up to 30 mins to get a fix with no RTC battery, those with an RTC (real time clock) battery can get a fix faster after the 1st fix. Mine will get a fix within 5 secs thanks to using an Battery keeping the RTC alive.
Cloud cover also effects signal and fix. Using an active antenna is the best. The adafruit module with the active antenna Is really good from my experience. I did have 4x NEO6M but it they all died the same day I first powered them on
The gps fix is now less than 1 min. It was only on this Pi4 that I am having issues. The one I’ve ordered has a battery holder for RTC.
I have some good news, the code is partially working. I think something has to do with the format for latitude, longitude and date. If I comment these out the code runs. Just have to figure out how the decode sruff works so I can adapt to what my gps receiver is outputing.
date and timw is got from GPZDA, not all GPS get that NMEA. Lat and Lon is got from GPRMC, all the NMEA messages are the same in structure, it depends on the device, RMC should be obtainable on every device
@CAProjects we have an RTC inside the pi-top [4] but I’m not sure we’ve made it accessible yet - would it be useful to have that for your project?
not for GPS since GPS uses GPS sats to sync its RTC, it may come in handy for somehting else later down the line tho.
@duwudi does pi-topOS support PPS? if not, no worriesjust wanted to play around with it
@CAProjects remind me what PPS stands for? It’s our acronym for pi-top Production System internally so I’m blanking
PPS means pulse per second. It’s used to sync time mostly but can be used for a lot of things.
Can think of it like a sort of time code