I ordered a few of these to find out whether they would be any use for robot positioning and my conclusion is a very definite NO!
The reason being that the values indicate an inaccuracy of up to 10 meters.
Here is the setup.
The Arduino Nano is loaded with a blank sketch, the TXD pin on the breakout board is connected to the TX pin on the Nano.
One minute of latitude equals one nautical mile equals 1800 meters, one second of latitude is equal to 1800/60 i.e. 30 meters. And using the python program below the seconds' values are dancing around by some 0.3 of a second i.e. 10 meters.
#!/usr/bin/python3
#coded by Stephen Clements aka Pugwash 2019
#please use and/or modify as you please
#any feedback to pugwash429@gmail.com would be appreciated
import serial
# change to your COM port
gps_comm_port = '/dev/cu.wchusbserial1460'; # *nix comm port notation
# change to suit your timezone
timeOffset = 2
try:
# Change the baud rate here if not 9600
ser = serial.Serial(port=gps_comm_port, baudrate=9600)
except IOError:
print("Invalid comm port, Comm port not found for GPS.")
exit (1)
# validate the checksum
def validateChecksum(gpsData):
gpsData = gpsData.lstrip('$')
gpsList = gpsData.split('*')
gpsHex = gpsList[1]
gpsString = gpsList[0]
checksumResult = 0
for character in gpsString:
checksumResult ^= ord(character)
if checksumResult ==int(gpsHex, 16):
returnTrue
else:
returnFalse
# format and correct time to display UTC & local time
def formatTime(timeString, tempOffset):
tempTime = timeString.split('.') # split the decimal part from the time string
tempTime = tempTime[0] # discard decimal part
tempTime = tempTime.lstrip('0') # strip leading zeros
# if GPS time is later than 9:59 am
if len(tempTime) ==6:
iTemp = int(tempTime[0:2]) # extract hours
iTemp =+ iTemp + tempOffset
if iTemp >=24: # correct for day change
iTemp = iTemp -24
hrs = str(iTemp)
mins = tempTime[2:4]
secs = tempTime[4:6]
# if GPS time is before than 10:00 am
if len(tempTime) ==5:
iTemp = int(tempTime[0]) # extract hours
iTemp =+ tempOffset
hrs = str(iTemp)
mins = tempTime[1:3]
secs = tempTime[3:5]
formattedTime = "%s:%s:%s" % (hrs, mins, secs)
return formattedTime
# format longitude and latitude
def formattedPosition(posString):
tempPos = posString.lstrip('0') # strip leading zeros
tempPos = tempPos.split('.') # split the decimal part from the position string
# extract degrees and minutes
if len(tempPos[0]) ==5:
tempStr = tempPos[0]
degrees = int(tempStr[0:3], base=10)
minutes = int(tempStr[3:5], base=10)
if len(tempPos[0]) ==4:
tempStr = tempPos[0]
degrees = int(tempStr[0:2], base=10)
minutes = int(tempStr[2:4], base=10)
if len(tempPos[0]) ==3:
tempStr = tempPos[0]
degrees = int(tempStr[0:1], base=10)
minutes = int(tempStr[1:3], base=10)
# calculate seconds
seconds = float(tempPos[1]) * 0.00001
seconds = seconds * 60
# format string for output
formattedPosition = "%i° %i' %.3f\"" % (degrees, minutes, seconds)
return formattedPosition
# display extracted values
def showValues(gpsData):
gpsList = gpsData.split(',')
print("Time(UTC): "+ formatTime(gpsList[1], 0))
print("Local Time: "+ formatTime(gpsList[1], timeOffset))
print("Longitude: "+ formattedPosition(gpsList[2]) +" "+ gpsList[3])
print("Latitude: "+ formattedPosition(gpsList[4]) +" "+ gpsList[5])
print("Altitude: "+ gpsList[9] +" "+ gpsList[10])
print("No. of satellites visible: "+str(int(gpsList[7])))
print()
return
def main():
print()
print("Starting...")
while1:
data = ser.readline()
data = data.decode('utf-8', errors='ignore')
data = data.rstrip('\n')
if data.startswith('$GPGGA'):
if validateChecksum(data):
showValues(data)
else:
print("Checksum not valid")
if __name__ == '__main__':
main ()
Most of the time the above code works fine, but sometimes crashes out of the program, with a "List index out of range error." for tempPos[1] on line 91. I think this only happens when the number of visible satellites goes really low.
This what the output should look like when up and running:-
Time(UTC): 12:44:18
Local Time: 14:44:18
Longitude: xx° xx' 19.138" N
Latitude: x° xx' 6.168" E
Altitude: 20.6 M
No. of satellites visible: 9
This is the quick fix for the "List index out of range error".
# if the tempPos List has only one item return without seconds value
if len(tempPos) !=2:
formattedPosition = "%i° %i'" % (degrees, minutes)
return formattedPosition
# calculate seconds
I have attached the whole python file below. I think that trying to program this in C++ would probably be a bit of a nightmare but if anybody does try I have a 16x4 LCD that is just waiting for an Arduino sketch. ?
I discovered that if the program was started before 10:00 AM, the time field became corrupted.
This has been resolved in revision R2 and the code simplified, see attached file.
Hi Steve,
Are you running this test indoors or out? It's tough with GPS indoors for most systems. I do notice that with a better antenna, they do perform somewhat better but in the end, they will not do all that well inside a home. On the GPS bot I did, I would get good results with a rubber duck antenna and spotty without (including the one like you have).
Scott
Hi Scott,
I have been working on this indoors, due to appalling weather for the last few days. Now the sun's come out, I can do some more testing on the balcony, perhaps with a beer or two in 82°F.
The next thing will be to write another program to log the position, both longitude and latitude for 24 hours and determine the mean value and standard deviation. This I will run for 24 hours to get a decent sample.
I am getting 7 - 9 satellites indoors and 14 - 17 satellites outdoors but still getting a similar inaccuracy.
I have been trying to find out whether I can increase the polling of the NEO-6M, but the info sheet I found from Ublox is not very revealing. That Rx pin must be for something.
Hi Scott
I threw this program together to work out the position error (only latitude for the time being).
The program is in metric, but changing to suit people with twelve fingers ?, only needs changing one value and a couple of print() statements.
Try it out and let me know how you get on i.e. what sort of positional accuracy you are getting.
I'm a metric American! 🙂 I'll set up a test later today and let it run. Thanks!
Took the setup outside, where I am getting more visible satellites. But it shows no recognisable increased accuracy. But one thing I have noticed is, that there are occasional spurious values, where the "Absolute range" jumps from 0.7m to in excess of 2m.
I am trying to figure out how to filter out these extreme values.
Here are a few results from a run from my home office @3 meters from the window:
Acquiring initial data...
Mean value: 2.7471 metres
Standard deviation: 0.0019 metres
Absolute deviation: 0.0027 -0.0023
Absolute range: 0.0049
Mean value: 2.7470 metres
Standard deviation: 0.0017 metres
Absolute deviation: 0.0028 -0.0022
Absolute range: 0.0049
Mean value: 2.7471 metres
Standard deviation: 0.0016 metres
Absolute deviation: 0.0026 -0.0023
Absolute range: 0.0049
I see you have taken the first three values. I found that if you leave it recording for half an hour or so, the accuracy will go down, but you have to watch out for spurious values, as I mentioned above.
I just wish I could get further from the building's walls.
+/- 3mm was not what I was expecting. ?
I'll let it run a bit and then post to a text file.
Note: It's rainy today and my office is on the first floor of my home, and this part of my home is under a very large Sycamore tree.
Will post back later.
Scott, thanks for your help and data.
It has been interesting just to find out how much my first assertions were wrong. As your data shows a stabilised value of +/- 125mm under an open sky, that would make navigating a robot around the backyard or even for mowing a large lawn completely viable.
I read somewhere that modern car navigation systems use a combination of both GPS and dead reckoning to increase accuracy, but that is a subject for another day.
What I am looking forward too, is the Galileo system coming online, as it is reported to be more accurate than GPS, we'll see soon!
So I guess the conclusion is that GPS positioning is of no use indoors for robots, and reasonably accurate outdoors.