GPS - A horrifying relization

Hello All,

I just had a horrifying relization that I wanted to ask anyone about. I lugged my gps information into google earth and the position it gave was miles away from the expected position. Now I’m left wondering if the problem is google earth (for my country) or if it’s the GPS receiver (the one for the Fez Domino).

So my question is: Is the GPS device for the Fez Domino accurate? I know that sounds bad but I need to know.

Yes it is accurate as it uses a standard and very common chipset.

Maybe you decoded the data wrong?

I’m looking at the raw data :

I’ve interpreted it manually as: 10 39 50.73 N, 61 27 43.62 W

If you have a cell phone w GPS you can try verifying against that.

Nah I don’t have a gps cellphone. I entered that data into google maps and that’s how I figure that something is wrong. The actual position is miles away. Could the google data be wrong? (Google Maps)

Google can be wrong, but never that much, at least that I have seen. If you look up my address, the spot Gmaps gives is a pretty long ways away from where my house really is.

You might try confirming that with a second map site, like Bing.

I have been playing around with GPS too. using the example code and the modified code ([url]http://www.tinyclr.com/forum/8/699/[/url]) and the first one was not accurate at all. The modified code showed real accurate data.

I drove around in my car and the coordinates were transferred into a gps coordinate website. Once I had entered a coordinate, the website actually pin pointed the roads I had been driving on

So FEZ nor the GPS reciever is wrong. It works very well.

What format does your GPS save to?
What format are you converting to?
What format does Google maps read?

Just as a test, you might try my version of a GPS parser.
It only uses the GPRMC sentence and gives coordinates in decimal degrees. It does a checksum validation and there is a built in method for checking how old the data is.
I copied some code from Noebl1 for the DistanceTo and CourceTo method.


using System;
using Microsoft.SPOT;
using System.Text;
using System.IO.Ports;
using GHIElectronics.NETMF.System;

namespace Whirligig
{
    public class COM_GPS
    {
        static readonly object _locker = new object();
        private SerialPort GPSHandle;
        private static string NMEA = "";
        static string GPRMC_sentence = "";
        static uint GPRM_count = 0;
        static uint GPRM_failed = 0;
        static bool OK = false;
        private DateTime Current_date;
        private double Current_Lat = 0, Current_Long = 0;
        private double Current_Course = 0;
        private double Current_Speed = 0;
        private double deg;
        private Int64 _fixTime = DateTime.Now.Ticks;

        public DateTime Date
        {
            get
            {
                return Current_date;
            }
        }

        public Int64 FixTime
        {
            get
            {
                return (DateTime.Now.Ticks - _fixTime) / 10000; //Returns mS
            }
        }

        public double Latitude
        {
            get
            {
                return Current_Lat;
            }
        }

        public double Longitude
        {
            get
            {
                return Current_Long;
            }
        }

        public bool Available
        {
            get { return OK; }
        }

        public uint Count
        {
            get { return GPRM_count; }
        }

        public uint Failed
        {
            get { return GPRM_failed; }
        }

        public double Cource
        {
            get { return Current_Course; }
        }

        public double Speed
        {
            get { return Current_Speed; }
        }

        public double DistanceTo(double WP_Lat, double WP_Long)
        {
            try
            {
                double tmp_Lat = Current_Lat;
                double tmp_Long = Current_Long;
                Trigonometry trig = new Trigonometry();
                double tempdistance = 0;
                double theta = tmp_Long - WP_Long;
                tempdistance = GHIElectronics.NETMF.System.MathEx.Sin(trig.DegreeToRadian(tmp_Lat)) *
                GHIElectronics.NETMF.System.MathEx.Sin(trig.DegreeToRadian(WP_Lat)) + GHIElectronics.NETMF.System.MathEx.Cos(trig.DegreeToRadian(Current_Lat)) *
                GHIElectronics.NETMF.System.MathEx.Cos(trig.DegreeToRadian(WP_Lat)) * GHIElectronics.NETMF.System.MathEx.Cos(trig.DegreeToRadian(theta));
                tempdistance = GHIElectronics.NETMF.System.MathEx.Acos(tempdistance);
                tempdistance = trig.RadianToDegree(tempdistance);
                tempdistance = tempdistance * 111189.57696;
                return tempdistance;
            }
            catch (Exception se)
            {
                Debug.Print(se.ToString());
                return -1;
            }
        }

        public double CourceTo(double WP_Lat, double WP_Long)
        {
            double tmp_Lat = Current_Lat;
            double tmp_Long = Current_Long;
            Trigonometry trig = new Trigonometry();
            double dlon = trig.DegreeToRadian(WP_Long - tmp_Long);
            tmp_Lat = trig.DegreeToRadian(tmp_Lat);
            WP_Lat = trig.DegreeToRadian(WP_Lat);
            double a1 = GHIElectronics.NETMF.System.MathEx.Sin(dlon) * GHIElectronics.NETMF.System.MathEx.Cos(WP_Lat);
            double a2 = GHIElectronics.NETMF.System.MathEx.Sin(tmp_Lat) * GHIElectronics.NETMF.System.MathEx.Cos(WP_Lat) * GHIElectronics.NETMF.System.MathEx.Cos(dlon);
            a2 = GHIElectronics.NETMF.System.MathEx.Cos(tmp_Lat) * GHIElectronics.NETMF.System.MathEx.Sin(WP_Lat) - a2;
            a2 = GHIElectronics.NETMF.System.MathEx.Atan2(a1, a2);
            if (a2 < 0.0)
            {
                a2 += GHIElectronics.NETMF.System.MathEx.PI * 2;
            }
            return trig.RadianToDegree(a2);
        }

        public COM_GPS(string comPort, int baudrate)
        {
            GPSHandle = new SerialPort(comPort, baudrate);
            GPSHandle.Open();
            GPSHandle.Flush();
            GPSHandle.DataReceived += new SerialDataReceivedEventHandler(GPS_DataReceived);
        }

        void GPS_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

                if (e.EventType == SerialData.Chars)
                {
                    try
                    {
                        byte[] ReadBuffer = new byte[GPSHandle.BytesToRead];
                        GPSHandle.Read(ReadBuffer, 0, ReadBuffer.Length);
                        NMEA = NMEA + new String(Encoding.UTF8.GetChars(ReadBuffer));
                    }
                    catch
                    {
                        Debug.Print("Error");
                    }

                    if (NMEA.IndexOf("$GPRMC") >= 0)
                    {
                        if (NMEA.IndexOf("$GPRMC") > 0) NMEA = NMEA.Substring(NMEA.IndexOf("$GPRMC")); //fjern resten av stetningen
                        GPRMC_sentence = NMEA.Substring(NMEA.IndexOf("$GPRMC"));
                        
                        if (GPRMC_sentence.IndexOf('\r') > 0)
                        {
                            NMEA = GPRMC_sentence.Substring(GPRMC_sentence.IndexOf('\r')+1);
                            GPRMC_sentence = GPRMC_sentence.Substring(0, GPRMC_sentence.IndexOf('\r')+1);

                        }
                    }


                    if (GPRMC_sentence.IndexOf("$GPRMC") == 0 && GPRMC_sentence.IndexOf("\r") > 0)
                    {
                        GPRM_count++;
                        GPRMC_sentence = GPRMC_sentence.Substring(0, GPRMC_sentence.Length - 1); //remove \r
                        if (ValidChecksum(GPRMC_sentence))
                        {
                            
                            string[] words = GPRMC_sentence.Split(',');
                            if (words[2].IndexOf("A") == 0) //We have a valid fix
                            {
                                OK = true;
                                Current_date = new DateTime(
                                    (Convert.ToInt32(words[9].Substring(4)) + 2000),
                                    (Convert.ToInt32(words[9].Substring(2, 2))),
                                    (Convert.ToInt32(words[9].Substring(0, 2))),
                                    (Convert.ToInt32(words[1].Substring(0, 2))),
                                    (Convert.ToInt32(words[1].Substring(2, 2))),
                                    (Convert.ToInt32(words[1].Substring(4, 2))));

                                // Calculate Latitude
                                Current_Lat = Convert.ToDouble(words[3]);
                                Current_Lat = Current_Lat / 100;
                                deg = System.Math.Floor(Current_Lat);
                                Current_Lat = (100 * (Current_Lat - deg)) / 60;
                                Current_Lat += deg;
                                if (words[4].IndexOf("S") == 0)
                                {
                                    Current_Lat = 0.0 - Current_Lat;
                                };

                                // Calculate Longitude
                                Current_Long = Convert.ToDouble(words[5]);
                                Current_Long = Current_Long / 100;
                                deg = System.Math.Floor(Current_Long);
                                Current_Long = (100 * (Current_Long - deg)) / 60;
                                Current_Long += deg;
                                if (words[6].IndexOf("W") == 0)
                                {
                                    Current_Long = 0.0 - Current_Long;
                                };

                                Current_Speed = Convert.ToDouble(words[7]);
                                Current_Course = Convert.ToDouble(words[8]);
                                _fixTime = DateTime.Now.Ticks;
                            }
                        }
                    }
                }
            }

        private bool ValidChecksum(string GPS_sentence)
        {
            bool Status = false;
            int Checksum = 0;
            int NMEA_Checksum = -1;
            bool ChecksumComplete = false;
            string[] cs = GPRMC_sentence.Split('*');
            if (cs.Length == 2)
            {
                NMEA_Checksum = Convert.ToInt32(cs[1], 16);
                foreach (byte Character in GPS_sentence)
                {
                    switch (Character)
                    {
                        case 36: // Ignore the dollar sign
                            break;
                        case 10: // Ignore LF
                            break;
                        case 13: // Ignore CR
                            break;
                        case 42: // Stop processing before the asterisk
                            ChecksumComplete = true;
                            break;
                        default:
                            if (!ChecksumComplete)
                            {
                                if (Checksum == 0)
                                {
                                    Checksum = Character;
                                }
                                else
                                {
                                    Checksum = Checksum ^ Character;
                                }
                            }

                            break;
                    }
                }

                if (NMEA_Checksum == Checksum) Status = true;
            }
            if (Status == false) GPRM_failed++;
            return Status;
        }

        public class Trigonometry
        {
            public double DegreeToRadian(double angle)
            {
                return GHIElectronics.NETMF.System.MathEx.PI * angle / 180.0;
            }
            public double RadianToDegree(double angle)
            {
                return angle * (180.0 / GHIElectronics.NETMF.System.MathEx.PI);
            }
        }

    }
}

Maybe it’s time we develop a community GPS driver. One that would support USB GPS receivers also. I’d be willing to code for that.

FYI USB GPS with embedded USB2Serial are already supported on FEZ. We tested couple.

Kind of an offtopic question, but that reminded me: Gus, if you connect a USB2serial chipset, will it get added to the COMs? Ie, will you have COM3? Reason I aks is that it would be a lot easier to code for that, then handing the USB device object over to the parser.

Great idea Chris.
I would love to have robust and reliable GPS driver written by people that really know C# (unlike my feeble attempt). My wish list for such a driver would be;

[ulist]Full checksum validation
A last fix time so one is not navigating on stale data
A choice of coordinate output format
Parsing the full range of GPS related NMEA sentences (not just RMC)
Methods for sending settings to the GPS unit
Methods for Course To and Distance To
GPS time with offset[/ulist]

Yeah, I need a very robust GPS driver for my RWAR project.

How about I star ta Google Code page for it. Also , a new thread on TinyCLR.

Chris, You will have a SerialPort object after enumeration a USB2Serial device.

Alright I just checked with bing and got the same results. I’m going to have to do more indept tests with modified code.

Yes, we’ll have to write another GPS driver that is community driven. Once the code aspect of the site is up we’ll get going on that (that’s what it’s for after all).

My intent here was to write a program that will talk to Google Earth (since google earth can scan for a GPS device over com ports) to have Domino + GPS integration working on my Netbook. That way when I move around I can see how long it takes me to get to work every day. I plan to strap a device to my ankle to determine what my movements are on a daily basis.

EDIT: Btw I know that the Chipset for teh GPS module is a SIRF STAR III but there are like 4 chips in that family. Does anyone have the data sheet for those devices? I’m expecially intrested in the list of commands that I can send and the interpertation of the data that is received.

Kurt,

See my new thread in the “Projects” forum.

Ok I figure it out. The information was being entered into Google incorrectly. It’s come to the fact that we can’t trust random people’s blogs anymore; either that or it’s a bug in google maps (which i doubt).

Ah, that would make sense, then. How were you entering it in?

From the serial data you will get a string like this:

,193050.000,A,1038.0504,N,06124.6508,W,0.00,060910,A

Which equates to:

10 38.0504 N, 61 24.6508 W

When entering it into Google. I was entering 10 38 05.04 N, 61 24 65.08 W <- which google and bing accepted, but was wrong. I figured it out because I relized that the data simply did not make sense.