Notifications
Clear all

NEO-6M GPS module

13 Posts
2 Users
1 Reactions
4,835 Views
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

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.

IMG 4213

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


   
Quote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

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. ? 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

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.


   
triform reacted
ReplyQuote
triform
(@triform)
Member
Joined: 6 years ago
Posts: 324
 

@pugwash

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

 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@triform

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.


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@triform

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.

 


   
ReplyQuote
triform
(@triform)
Member
Joined: 6 years ago
Posts: 324
 

@pugwash

I'm a metric American! 🙂 I'll set up a test later today and let it run. Thanks!


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@triform

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. 


   
ReplyQuote
triform
(@triform)
Member
Joined: 6 years ago
Posts: 324
 

@pugwash

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




   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@triform

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. ? 


   
ReplyQuote
triform
(@triform)
Member
Joined: 6 years ago
Posts: 324
 

@pugwash

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.


   
ReplyQuote
triform
(@triform)
Member
Joined: 6 years ago
Posts: 324
 

@pugwash

Here is a 15min run.


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@triform

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.


   
ReplyQuote