Following on from my earlier posting on programming bluetooth from Python, I tried talking to a bluetooth GPS unit from Python.
I have a cheap MSI Starfinder SF100 bluetooth GPS that transmits NMEA format positioning information over a bluetooth socket. So, the first thing we have to do is to is to open a bluetooth socket.
import bluetooth
# bluetooth address of the GPS device.
addr = "00:08:1B:C2:AA:6D"
# port to use.
port = 1
# create a socket and connect to it.
socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
socket.connect((addr, port))
Fingers crossed we should now be connected to the GPS unit. In the real world we’d also be checking for exceptions to make sure we really have been able to connect, but this is just a simplified example.
Now we need to receive data from the GPS.
data = ""
while True:
data = socket.recv(1024)
Here we’re initialising a holding variable called data where the received data from the bluetooth socket goes, then we create an infinate loop and continually receive data from the bluetooth socket we creataed earlier.
We should now have some data coming in, so to test it we can just print it out.
print data
Here’s what we get back.
$GPRMC,225406.537,A,5046.3972,N,00017.
3365,E,0.00,,300107,,,A*7E
$GPGGA,225407.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,
M,,,,0000*33
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPRMC,225407.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7F
$GPGGA,225408.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*3C
$GPGSA,A,3,27,1
0,2
9,28,08,,,,,,,,3.9,1.7,3.5*35
$GPGSV,2,1,08,10,70,218,31,08,64,067
,35,29,49,287,30,27,37,058,40*70
$GPGSV,2,2,08,26,35,283,,28,34,133,45,24,27,254,22,21,12,324,*72
$GPRMC,225408.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*70
$GPGGA,225409.537,5046.3972,N,00017.3365,E,1,06,1.4,55.5,M,,,
,0000*3D
Oh dear, although we are receiving data over the bluetooth socket, it’s in random packet sizes. The NMEA data we want is sent in lines terminated with a carriage return and a line feed. So how can we get the data in this format?
Well we need to use Python’s string manipulation methods. We can use the splitlines
method to split the data into a list of lines. As we can’t be sure we have a complete line at the end of the list we need to check there is a carriage return and linefeed there. By default splitlines
helpfully removes these, so we need to tell it to keep them in place, after all we can use the strip
method later to remove them manually. So all we need to do now is to check the last line in the list has the carriage return and linefeed, if it doesn’t we need to make sure the next data received from the bluetooth socket is appended to the end before we repeat the process again. Imagine we create a holding variable called olddata at the same time as data and this is to hold a copy of the last line. Here’s the code…
# make sure we actually have some data.
if len(data) > 0:
# append the old data to the front of data.
data = olddata + data
# split the data into a list of lines, but make
# sure we preserve the end of line information.
lines = data.splitlines(1)
# iterate over each line
for line in lines:
# if the line has a carriage return and a
# linefeed, we know we have a complete line so
# we can remove those characters and print it.
if line.find("rn") != -1 :
line = line.strip()
print line
# empty the olddata variable now we have
# used the data.
olddata = ""
# else we need to keep the line to add to data
else :
olddata = line
We now have some useful data coming in…
$GPRMC,225406.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7E
$GPGGA,225407.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*33
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPRMC,225407.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7F
$GPGGA,225408.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*3C
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPGSV,2,1,08,10,70,218,31,08,64,067,35,29,49,287,30,27,37,058,40*70
$GPGSV,2,2,08,26,35,283,,28,34,133,45,24,27,254,22,21,12,324,*72
$GPRMC,225408.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*70
$GPGGA,225409.537,5046.3972,N,00017.3365,E,1,06,1.4,55.5,M,,,,0000*3D
As you can see the NMEA strings are simply comma seperated blocks of data.
The most useful string is the one with the actual position in. This string is the one starting with $GPRMC
. If we look out for this line and split it’s data, we can get our latitude and longitude and use it as we please.
gpsstring = line.split(',')
if gpsstring[0] == '$GPRMC' :
print "Lat: " + gpsstring[3] + gpsstring[4]
print "Long: " + gpsstring[5] + gpsstring[5]
This gives us…
Lat: 5046.3972N
Long: 000017.3365
Which translates to 50 deg 46.3972′ N and 0 deg 17.3365 E.
There you have it, it’s time to start geocoding you data.