kelly watch the stars
I found that the phone apps that I used to track my walking did not always reliably record my position, track, or time. I decided to build a gps tracker running on a Raspberry Pi to, hopfully, do a better job. My tracker prototypes write nmea data to a file for processing later. There is no live position display, yet.
The first prototype was a Pi 2 with a USB GPS dongle and gpsd. It worked.
The next, and current, prototype is a Pi Zero W, an Adafruit Ultimate GPS HAT for Raspberry Pi, a reboot or shutdown switch, a tri-colour LED, is that and my own scripts (no gpsd).
GPS units typically output strings of nmea formatted text. I use some venerable command line text processing tools, and a little python, to process this text, write it to a file, and light an LED to display the fix status.
The scripts do what I intend, but these may not be good examples of how to program, or how to choose filenames! I wanted to script using existing command line text processing tools. I write this some months after writing the scripts. These scripts and how these interact may reveal some of the development steps I took: these might need refining.
The scripts communicate via files and file contents.
I use GPXSee to visualize the nmea data files.
Files:
gpsstatus.log
Each line: date and time, a comma, a status integer that can be 0,1, or 2.
gpsstatus.fix
A single integer that can be 0,1,2.
gpsdate.log
The gps date.
gpslogfile.log
Filename of the current file of gps data.
gps-[datetime].nmea
A file of gps data in nmea format.
crontab entries
@reboot ~/gpslogger/initializeserial.sh
@reboot ~/gpslogger/loggermonitor.sh
@reboot ~/gpslogger/gpsstartlogging.sh
@reboot ~/fixtest.py
At each boot crontab runs each script. Some loop forever, or continue forever.
Scripts
initializeserial.sh
#!/bin/bash
# initializeserial for ADAFRUIT ULTIMATE GPS HAT
stty -F /dev/serial0 raw 9600 cs8 clocal -cstopb
Runs once to initilize the ADAFRUIT ULTIMATE GPS HAT as Adafruit recommend.
loggermonitor.sh
#!/bin/bash
# monitors the gps logging file
# write new status log on running at reboot
# checks time in tail as well as status - necessary.
# 2018 Jul 16 added gpsstatus.fix - single char 0 1 or 2
echo "$(date -u +%Y%m%d%H%M%S),0" > gpsstatus.log
echo "0" > gpsstatus.fix
LASTTAIL="$(tail -1 $(cat gpslogfile.log) | awk -F , '{print $2","$7}')"
sleep 10
while true
do
THISTAIL="$(tail -1 $(cat gpslogfile.log) | awk -F , '{print $2","$7}')"
if [ "$THISTAIL" != "$LASTTAIL" ]
then
LASTTAIL="$THISTAIL"
echo $THISTAIL | awk -F , '{ print $1","$2}' >> gpsstatus.log
echo $THISTAIL | awk -F , '{ print $2}' > gpsstatus.fix
else
echo "$(date -u +%Y%m%d%H%M%S),0" >> gpsstatus.log
echo "0" > gpsstatus.fix
fi
sleep 10
done
- Nothing happend so far so:
- Write a date and time, and a status of 0 to gpsstatus.log.
- Write 0 to gpsstatus.fix.
- Read the last line of yet another file, gpslogfile.log and use awk to put 2 fields from the line in the variable LASTTAIL.
- We wait for 10 seconds.
- Start the loop until the end of time!
- Read the last line of gpslogfile.log again and use awk to put 2 fields from the line in the variable THISTAIL.
- Compare THISTAIL with LASTTAIL. If these are different it means that we are logging gps data, good!
- Make LASTTAIL the same as THISTAIL.
- Append contents of THISTAIL to gpsstatus.log
- Overwrite gpsstatus.fix with the current fix status.
- If THISTAIL and LASTTAIL are identical then we:
- Write a date and time, and a status of 0 to gpsstatus.log.
- Write 0 to gpsstatus.fix.
- Keep looping forever.
gpsstartlogging.sh
#!/bin/bash
# logs nmea data from when gpshhmmss available
# V0.0
# grep -v ,,, so we do not log useless nmea output
# sleep to give time for a lock
sleep 20
# timestamp for nmea filename
# We only take date no time because logger gets own time from gps
RAWGPSDATE="$(cat /dev/serial0 | stdbuf -oL grep RMC | head -1 | awk -F , '{ print $10 }')"
GPSDATE="20${RAWGPSDATE:4:2}${RAWGPSDATE:2:2}${RAWGPSDATE:0:2}"
echo $GPSDATE > ~/gpsdate.log
# gets gpshhmmss from gps serial0 stream
GPSHHMMSS="$(cat /dev/serial0 | stdbuf -oL grep GGA | head -1 | awk -F "," '{ print $2}' | awk -F "." '{print $1}')"
GPSLOGFILE="gps-$GPSDATE$GPSHHMMSS.nmea"
echo $GPSLOGFILE > ~/gpslogfile.log
# logs timestamped nmea strings to file
# does not log data with missing fields ,,,
cat /dev/serial0 | stdbuf -oL grep GGA | stdbuf -oL grep -avE ',,,|,[0-9]{6},' >> "$GPSLOGFILE" &
- Waits for an RMC nmea string and extracts the date.
- Write the date to gpsdate.log, but I cannot remember why!
- Waits for a GGA nmea stirng and extracts the time.
- Builds the gpslog file filename using the RMC date and GGA time.
- Write the filename to gpslogfile.log.
- Appends (writes) received GGA nmea strings to the .nmea file. This last process continues until shutdown, reboot, or the end of time, whichever is sooner. The process continues because
/dev/serial0
is a stream of data andcat
will keep processing the stream until it receives an EOF (end of file).
fixtest.py
#!/usr/bin/env python3
from gpiozero import LED
from time import sleep
from os import system
# Set the rgbled to the correct pins
redled = LED(16)
greenled = LED(13)
blueled = LED(12)
# set some varibles
searching = 0
fix = 1
dgps = 2
fixstatus = 0
def getfixstatus():
# reads the fix status
try:
fixstatusfile = open("gpsstatus.fix","r")
fixstatusread = fixstatusfile.read()
# print("-"+fixstatusread)
fixstatusfile.close()
except:
fixstatusread = "0"
try:
fixstatus = int(fixstatusread)
except:
fixstatus = 0
return fixstatus
while True:
# fixstatusfile = open("gpsstatus.fix","r")
# fixstatus = int(fixstatusfile.read())
# fixstatusfile.close()
fixstatus=getfixstatus()
# print(fixstatus)
# We have a fix, dgps, or not so blink LED once
if (fixstatus == fix):
greenled.blink(n=1)
# print("fix")
elif (fixstatus == dgps):
blueled.blink(n=1)
# print("dgps")
else:
redled.blink(n=1)
# print("searching")
# sleep to save mAh
sleep(5)
The clue is in the name of this script; just a test script.
- The function
getfixstatus():
reads and returns the status of the fix from gpsstatus.fix.- If that fails then we return a fix status of 0: no fix.
- Loops until forever:
- Blinks an LED of colour Green (fix), Blue (dgps fix), or Red (no fix)
- Sleeps for 5 seconds to save power.
I used some of the commented out instructions to debug the script. I use a tri-colour LED to display fix status, but this script would also work for 3 individual LEDs.
gpsstoplogging.sh
#!/bin/bash
# stops gps logging by killall cat - so stops all cat!
#
killall cat
Not the most elegant of solutions, but it stops my running scripts.