PDA

View Full Version : Changing GPS co-ordinates into Degrees-Minutes-Seconds



FromTheCockpit
- 26th October 2009, 10:04
Hi
I am able to get GPS NMEA data and display it onto my PC. Has anyone done any project to change the GPS co-ordinates into Degrees Minutes and Seconds they would like to share here. Thanks :)

ScaleRobotics
- 26th October 2009, 16:53
I have some ugly code that I could share ... (if you really want it...)

But the basic conversion is *5/300 for minutes and *5/18000 for seconds

For instance 30 minutes *5/300 = .50 degrees


if latitude = 47 deg 32 min 14 sec
47 32' 14"

then we can use:
32 *500/3 = 5333 (really .5333 degrees)

for seconds:
14*50/18 = 38 (really .0038 degrees)

Then add 5333 + 38 = 5371 or .5371 degrees

So, 47.5371 degrees is the answer.

financecatalyst
- 26th October 2009, 18:05
I am confused as well.

FromTheCockpit
- 26th October 2009, 18:17
I have some ugly code that I could share ... (if you really want it...)

But the basic conversion is *5/300 for minutes and *5/18000 for seconds

For instance 30 minutes *5/300 = .50 degrees


if latitude = 47 deg 32 min 14 sec
47 32' 14"

then we can use:
32 *500/3 = 5333 (really .5333 degrees)

for seconds:
14*50/18 = 38 (really .0038 degrees)

Then add 5333 + 38 = 5371 or .5371 degrees

So, 47.5371 degrees is the answer.

I would like to see the code if you dont mind. Currently the coordinates are in a string format. Being new to this field your code will help me to have a starting point and will help me understand and decide the way forward

ScaleRobotics
- 26th October 2009, 18:43
Sorry, let me explain a little more. I will try to explain this better tonight when I get home from work.

The basic conversion is:


Converting Between Decimal Degrees, Degrees, Minutes and Seconds, and Radians
(dd + mm/60 +ss/3600) to Decimal degrees (dd.ff)

dd = whole degrees, mm = minutes, ss = seconds

dd.ff = dd + mm/60 + ss/3600

Example: 30 degrees 15 minutes 22 seconds = 30 + 15/60 + 22/3600 = 30.2561

Decimal degrees (dd.ff) to (dd + mm/60 +ss/3600)

But division by 3600 does not work so well for PICs, so .......

Here are a couple ways of converting 15 minutes:
15minutes/60 = .25 degrees. Unfortunately PicBasicPro will round it off to 0, which we do not like.

So, if we change it to 15minutes*500/3=2500 (you'll notice this is the same as the first equation, only multiplied by 10000). We want whole numbers here, and we will need to add seconds to it in whole numbers too.


Here is one part of my minutes to degrees conversion, but I will try to make this a lot clearer tonight. char_A is the validity character in a gps string called gpsdata.


lathome_min = ((((gpsdata[char_A+9]-48)*10) + (gpsdata[char_A+10]-48))*5)/3 'lathome_min

ScaleRobotics
- 26th October 2009, 20:32
Hi
I am able to get GPS NMEA data and display it onto my PC. Has anyone done any project to change the GPS co-ordinates into Degrees Minutes and Seconds they would like to share here. Thanks :)

OOPS. My bad.

Did you really mean that you only want Degrees Minutes and Seconds? Or do need to convert to deg.deg ?

If you just need the digits, its the ASCII -48 = digits.

FromTheCockpit
- 26th October 2009, 21:31
OOPS. My bad.

Did you really mean that you only want Degrees Minutes and Seconds? Or do need to convert to deg.deg ?

If you just need the digits, its the ASCII -48 = digits.

Yes thats correct. I only need to convert the lat & long to degrees minutes and seconds and display it on my pc screen.

ScaleRobotics
- 27th October 2009, 06:24
Well, then...........

There are a couple different ways to do it. I'm going to show you the Serin2 example, because that is the gps example that MeLabs gives.
Another good way to do it is to read the entire NMEA sentence into an array like this, then worry about parsing it later:

HSerin 200, Main, [WAIT("$GPRM"), STR gpsdata\MAXDATA\13]
but we will stick with serin2 for now.

Here is MeLabs gps example for reading speed.
http://melabs.com/resources/samples/submitted/read_gps.bas

You would have to adjust to get degrees minutes and then do a conversion for seconds
For instance, their ...


SerIn2 GPSin,baudGPS,Timeout,Nogps,[wait("$GPRMC"),skip 34,DEC1 tens,DEC1 digits,skip 1,DEC1 tenth]

means wait till it sees $GPRMC that begins the NMEA sentence, skip 34 characters to the speed tens digit, put it in variable "tens", then read next speed digit and put in variable called "digits", then skip the "." and read the last decimal into a variable called "tenth".

You would have to adjust the skips to match the digits you want to get.


$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4 ,230394,003.1,W*6A

Where:
RMC Recommended Minimum sentence C
123519 Fix taken at 12:35:19 UTC
A Status A=active or V=Void.
4807.038,N Latitude 48 deg 07.038' N
01131.000,E Longitude 11 deg 31.000' E
022.4 Speed over the ground in knots
084.4 Track angle in degrees True
230394 Date - 23rd of March 1994
003.1,W Magnetic Variation
*6A The checksum data, always begins with *

If your NMEA sentence was similar to above (some add more resolution and are of slightly different format), then you could use:


SerIn2 GPSin,baudGPS,Timeout,Nogps,[wait("$GPRMC"),skip 11,DEC2 lat_deg,DEC2 lat_min,skip 1,DEC3 lat_min_dec ... then same for longitude]

Now, you need to convert decimal minutes to seconds .... am I right this time? Because the GPS will output in decimal minutes, not seconds.

So, to convert decimal minutes into seconds:
lat_seconds = lat_min_dec * 6
so, using the NMEA sample above: 038 * 6 = 228

When you print this out to your computer, you print a "." in between the twos
and get 2.28 seconds. This part just prints the seconds out through the serial port.
The dig specifies which digit you want to print of the variable called seconds. Rightmost digit is 0


DEBUG DEC lat_seconds dig 2,".",DEC lat_seconds dig 1, DEC lat_seconds dig 0,13,10

FromTheCockpit
- 27th October 2009, 12:50
Ok, thanks for your time in writing a detailed explanation, BUT little bit of confusion still left. I have the following string :

$GPRMC,123339.000,A,5134.2770,N,00007.8480,E,1.14, 254.38,271009,,*09

Can you please show me as to how to convert "5134.2770" & "00007.8480" into degrees - minutes - seconds in PBP + speed to Km/H.
I have done this online and the answer is
Degrees, Minutes & Seconds
Latitude - Longitude
N51 34 16 - W0 07 50 and 2.111 Km/Hr (Though it should be 0 Km/Hr as Module is stationary)

Also what is checksum? and what it is used for?

Your effort will be much appreciated. Many Thanks

ScaleRobotics
- 27th October 2009, 14:15
You are using one of the newer GPS's with a little higher resolution. With any handheld gps, there will be a little wandering of the output. You will see slight position changes, even though you are standing still. This will result in a display of speed, although it will be very low speed.

The checksum is used to ensure the device reading the gps doesn't receive faulty input. If it is important for your application, the Pic chip can be made to perform a checksum on the sentence, and compare it to the one the gps calculated. If it differs, the data read from the gps is corrupt, and must be read again.

To convert Knotts to km/h, multiply by 1.852. Since PICs don't do decimal, we will have to make our own. A close enough approximation of knotts x 1.852 is (knotts x 2048)/11, but remind yourselft that your result will have two digits past the decimal point. If you want whole numbers for km/h then divide by 100, or do (knotts x 2048)/1100. A handy tool to figure these fractions out is a download at the very bottom of this page: http://www.miscel.dk/MiscEl/miscel.html

To convert, you follow my earlier example, but insert skips to match the format of your NMEA sentence.

For your:

$GPRMC,123339.000,A,5134.2770,N,00007.8480,E,1.14, 254.38,271009,,*09
it would be something like:


SerIn2 GPSin,baudGPS,Timeout,Nogps,[wait("$GPRMC"),skip 14,DEC2 lat_deg,DEC2 lat_min,skip 1,DEC3 lat_min_dec ....] you should be able to enter the rest for longitude now....

The degrees and whole minutes are already in the format you want. We just need to convert decimal minutes into seconds. To do this, we use the same conversion I showed you in the previous example (except you will see that I forgot to add another digit for the seconds result). Here you have .2770 minutes. We only care about the first three digits. In fact, we might care about even fewer digits, but since we used three of the digits in the last example, lets just use three again.

The following will multiply your 277 by 6. This will give you a result of 1662, which really is 16.62, but again, the PIC can't do decimal, so we will use the whole number, and just format it for output.


lat_seconds = lat_min_dec * 6
DEBUG DEC lat_deg," deg ",DEC lat_min," min ",DEC lat_seconds dig 3,DEC lat_seconds dig 2,".",DEC lat_seconds dig 1, DEC lat_seconds dig 0," sec",13,10


That would print out:
"51 deg 34 min 16.62 sec", which matches pretty well with the 51 34 16 that you converted on line.

FromTheCockpit
- 27th October 2009, 17:07
The checksum is used to ensure the device reading the gps doesn't receive faulty input. If it is important for your application, the Pic chip can be made to perform a checksum on the sentence, and compare it to the one the gps calculated. If it differs, the data read from the gps is corrupt, and must be read again.


Thanks a lot. I think I need to sit down with the manual for sometime to learn about different conversions and decimal substitutes. Seems little complicated for now.

But I still wanted to ask you that how do I checksum the data in PIC? I mean my PIC gets everything in a string which is comming from the GPS in the first place. Why it is a number, what does this number do?

Can you please put up the code you have done as it will be far far easier to understand somthing working than perform a reverse engineering technique on it. From a beginners point of view what you explained above about checksum has gone past way above my head.

Thanks

ScaleRobotics
- 27th October 2009, 17:56
...Seems little complicated for now.

But I still wanted to ask you that how do I checksum the data in PIC? I mean my PIC gets everything in a string which is comming from the GPS in the first place. Why it is a number, what does this number do?

Can you please put up the code you have done as it will be far far easier to understand somthing working than perform a reverse engineering technique on it. From a beginners point of view what you explained above about checksum has gone past way above my head.


Well, I didn't post my code because I do something a little different. I convert from deg min.min to deg.deg so I can perform some math on the waypoints. My code is very ugly and sometimes confuses me.

I think it is very helpfull for people to be able to write code, and "make it their own". That is the only way they will be able to progress, and really make the code do things they want. So I try to give enough data for people to start playing around with the parts of code. The link to MeLabs sites GPS code is a fully functional code that will not have to be reverse engineered. Only needs to be edited slightly to read different digits by changing the skip 34, and a few other small things.

I suggest you ignore pretty much everything I have written below this line for now, and get your hands fully around the above code by playing around with the serin2 command, and seeing what you can get to print out to your computer.

This is NOT the code that I suggest playing around with, but if you must see it, here is a snippet. Darrell and others would probably say they needed a lot of toilet paper and a few Amodiums to go with it. If after seing it, you don't get sick to your stomach, I will try to explain the garbage. I would not say it is advanced. It is just too messy to explain properly. There are a couple errors I need to fix, with a few parenthesis in the wrong place, etc.

This is assuming you use an array called gpsdata.....


IF gpsdata[char_A] = "A" Then 'was 9, Needs to be 13 for EB-85A
lathome_hi = ((gpsdata[char_A+2] - 48) *10)+((gpsdata[char_A+3] - 48))
lathome_low = ((((gpsdata[char_A+4] -48)*1000)+((gpsdata[char_A+5]-48)*100)+((gpsdata[char_A+7]-48)*10)+(gpsdata[char_A+8]-48))*5)/3
lathome_min = ((((gpsdata[char_A+9]-48)*10) + (gpsdata[char_A+10]-48))*5)/3 'lathome_min
lathome_min = lathome_min + 33*((((gpsdata[char_A+4] -48)*1000)+((gpsdata[char_A+5]-48)*100)+((gpsdata[char_A+7]-48)*10)+(gpsdata[char_A+8]-48))*5)//3
tempbyte = lathome_min /100
lathome_low = lathome_low + tempbyte
lathome_min = lathome_min //100
if gpsdata[char_A+12]=78 then north =1 '="N"
lonhome_hi = ((gpsdata[char_A+14]-48)*100)+((gpsdata[char_A+15]-48)*10)+(gpsdata[char_A+16]-48)
lonhome_low = ((((gpsdata[char_A+17]-48)*1000)+((gpsdata[char_A+18]-48)*100)+((gpsdata[char_A+20]-48)*10)+(gpsdata[char_A+21]-48))*5)/3
lonhome_min = ((((gpsdata[char_A+22]-48)*10) + (gpsdata[char_A+23]-48))* 5)/3
lonhome_min = lonhome_min + 33*((((gpsdata[char_A+17]-48)*1000)+((gpsdata[char_A+18]-48)*100)+((gpsdata[char_A+20]-48)*10)+(gpsdata[char_A+21]-48))*5)//3
tempbyte = lonhome_min/100
lonhome_low = lonhome_low + tempbyte
lonhome_min = lonhome_min//100
if gpsdata[char_A+25] = 87 then west = 1 'check to see if we are W or E char 87 = "W"



Ok, now you got that, have your wife or girlfriend grab you another roll of toilet paper, and we will move on to checksums.....

I also, purposely did not go into check sums. You really only need to worry about checksums if your life, or your equipment is at risk because of the way you are using your GPS data. The reason it can be important, is that the NMEA sentences can be rather long. The one you are working with is in the neighborhood of 70 to 80 characters, though I have not counted. There are plenty of chances that by transmission through wires, or wireless, that one bit here or there could be missed, giving you a completely different location. Your equipment might not realize there was an error, unless it compared the checksum from the gps to its own calculated checksum on the data received.

Basically, the checksum is a sum of all the data in the NMEA sentence. It does something similar to adding up all the ascii codes.

I have some example code from an RCAP autopilot project, but this too is not really important if you are not making an autopilot, a hazard avoidance product, etc. So it can pretty much be left out of the equation for most applications.




DoCS:
i = 0 ' Initialize the position counter

While gpsdata[i] != "*" ' Count everthing until the *
cs = cs ^gpsdata[i] ' XOR for checksum
i = i + 1 ' Increment position counter
Wend

' A quick and easy atoh function
' Make it a seperate label if we add more atoh conversions in the future
LookDown gpsdata[i+1],["0123456789ABCDEF"],tempbyte
gpscs = tempbyte * 16
LookDown gpsdata[i+2],["0123456789ABCDEF"],tempbyte
gpscs = gpscs + tempbyte

' Flag bad data "V" if checksum doesn't add up.
' Or if the sentence is less then 20 chars long
' Which means there is no active waypoint to go to.
' Should be "A" otherwise.
IF (cs != gpscs) OR (i < 20 )Then
gpsvalid = 0
Else
gpsvalid = 1
EndIF

Return

FromTheCockpit
- 27th October 2009, 21:03
You are right. Toilet paper is over now. I am going to play with the code for next day or two and will put my findings and problems here. Thanks for the advise.

FromTheCockpit
- 1st November 2009, 22:35
Hi, Ok, I have the following code now:

STRING: $GPRMC,123339.000,A,5134.2770,N,00007.8480,E,1.14, 254.38,271009,,*09

ab:
DEBUGIN 2000,ab,[WAIT("$GPRMC"),skip 14,DEC2 ladeg,DEC2 lamin,skip 1,DEC4 lasec1,skip 3,DEC3 lodeg,DEC2 lomin,skip 1,DEC4 losec1]
losec=lasec1 * 6 : lasec=lasec1 * 6
pause 1000
DEBUG "Lat ",DEC2 ladeg," Deg ", DEC2 lamin," Min ",DEC2 lasec," Sec ",10,"Lon ",DEC3 lodeg, " Deg ", DEC2 lomin," Min ",DEC2 losec," Sec ",13,10,10
goto ab

And the WRONG result on my screen is the following:
Lat 51 Deg 34 Min 36 Sec
Lon 000 Deg 07 Min 36 Sec

Can you advise me please of what am I doing wrong here?

FromTheCockpit
- 2nd November 2009, 00:35
I got the co-ordinates working now. Just wondering how to go about getting the speed into variable as it keeps changing, 1.14 knots now, may be 100.20 knots later!

ScaleRobotics
- 2nd November 2009, 03:28
I got the co-ordinates working now. Just wondering how to go about getting the speed into variable as it keeps changing, 1.14 knots now, may be 100.20 knots later!

That's great!

To convert knots to Km/h:




knots var word 'xx.x knots is going to have to become xxx knots for this math
kmph var word
temp var word

temp = knots * 1852 'first part of div32 function
kmph = div32 1000 'this result should be printed out with one decimal
'in other words result xxx should be printed as xx.x km/h


so for above example, if you had 30.0 knots as speed then
knots = 300
temp = knots * 1852 = 555600

(you may notice this is bigger than 16 bits, but that's ok. The div32 lets us have up to a 31 bit number, so not to worry).

555600/1000 = 555

So, the answer must be printed out in decimal as 55.5 km/h

which is the pbp way to do knots * 1.852 = km/h

FromTheCockpit
- 2nd November 2009, 21:25
knots var word 'xx.x knots is going to have to become xxx knots for this math
kmph var word
temp var word

temp = knots * 1852 'first part of div32 function
kmph = div32 1000 'this result should be printed out with one decimal
'in other words result xxx should be printed as xx.x km/h

How can I get xx.x into xxx as there is an "." in the middle and also the datasheet says about only one digit before decimal -Which I wonder WHY? as speed will become two digits once it goes above 9 knots. How do I use the SKIP in a problem like this where decimal will change place?

ScaleRobotics
- 3rd November 2009, 06:19
How can I get xx.x into xxx as there is an "." in the middle and also the datasheet says about only one digit before decimal -Which I wonder WHY? as speed will become two digits once it goes above 9 knots. How do I use the SKIP in a problem like this where decimal will change place?

I get what you are saying now. I think my gps example had a static xxx.x output, but most of the new (non handheld) ones (like yours) do not.
This should do the trick, hopefully not too much trouble shooting involved.

It reads in 5 characters to the array named raw_speed[x]. Then it counts decimal places to the "." character. Then adds the digits together after multiplying them by the right power of 10.



raw_speed var byte[5] 'create an array to put each possible character for speed
i var byte
decimal var byte
speed var word

DEBUGIN 2000,ab,[WAIT("$GPRMC"),skip 14,DEC2 ladeg,DEC2 lamin,skip 1,DEC3 lasec1,skip 4,DEC3 lodeg,DEC2 lomin,skip 1,DEC3 losec1,skip 4,raw_speed[0],raw_speed[1],raw_speed[2],raw_speed[3],raw_speed[4]]

for i = 1 to 3
'find which character is the decimal point
if raw_speed[i]="." then decimal = i
next i

'combine single digits to form whole speed number. Varies from 0.0 to 999.0
select case decimal
'if our gps gives us 1.4, then this will convert it to 14
'the -48 is a way to convert an ascii number to a number
case 1 'decimal is in x.x position
speed=(10*(raw_speed[0]-48))+(raw_speed[2]-48)
case 2 'decimal is in xx.x position
speed=(100*(raw_speed[0]-48))+(10*(raw_speed[1]-48))+(raw_speed[3]-48)
case 3 'decimal is in xxx.x position
speed=(1000*(raw_speed[0]-48))+(100*(raw_speed[1]-48))+(10*(raw_speed[2]-48))+(raw_speed[4]-48)
end select

FromTheCockpit
- 3rd November 2009, 20:00
Scalerobotics, thanks a lot. I am now able to get what I want and how I want it from my GPS module. Love this Forum.
Can I request you answer my one question on the following forum as well please:
http://www.picbasic.co.uk/forum/showthread.php?t=6927

Thanks again.