Liberty BASIC Community Forum
« Reading GPS NMEA data sentences »

Welcome Guest. Please Login or Register.
Jan 21st, 2018, 6:13pm


Rules|Home|Help|Search|Recent Posts|Notification


« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Reading GPS NMEA data sentences  (Read 1031 times)
Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5618
xx Reading GPS NMEA data sentences
« Thread started on: Jul 3rd, 2010, 1:23pm »

Thought this might be teased out into it's own thread.

This is my latest code reading the ND100 USB based GBS dongle. The code should be able to read any serial based NMEA data stream provided you have the com port number and baud rate correct.

These devices issue a series of "sentences" some sentences every second some every five seconds. Each sentence carries specific types of GPS data. A devices will issue a set sequences of sentences, so five or more sentences will be pushed into the com buffer every second, an extra one or two at the five second point.

Every sentence starts with "$GPXXX" a six character label for the sentence. Every sentence ends with a CRLF pair or chr$(13)+chr$(10). Parsing is just a case of keeping pace with the messages.

I poll the buffer every half second and add the contents to the end of any unprocessed data from the last poll.

Then I parse out complete sentences and process the ones I am interested in, if there is any data left it sits waiting for the next poll and round we go again.

If no data is received for 5 polls I quit.

Code:
Snipped see later posts
 
« Last Edit: Jul 4th, 2010, 4:14pm by Rod » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5618
xx Re: Reading GPS NMEA data sentences
« Reply #1 on: Jul 4th, 2010, 12:02pm »

A more complex GUI taking more of the messages into account. It would appear perfectly possible to do realtime map rendering, waypoint creation tracking etc etc.

I got a bit bamboozled when I was trying to map the satelite positions, till I realised they are moving! So much for for my concept of geostationary.

There are bugs, it's more in they way of a proof of concept of timing and data processing. Liberty seems well up to the job.


Code:
Snipped see later post 
« Last Edit: Jul 4th, 2010, 4:15pm by Rod » User IP Logged

mikeukmid
Guest
xx Re: Reading GPS NMEA data sentences
« Reply #2 on: Jul 4th, 2010, 2:24pm »

Rod, I like the satellite position display, like the software supplied wih the ND100. 8-)

"The GPS satellites are not in geo-stationary orbit, but instead orbit twice every time the Earth rotates once. This means that for any observer the satellites appear to orbit once overhead each day. Such an arrangement gives better coverage. It is also clever in the sense that the motion of any GPS satellite will repeat itself each day." (ref: http://reference.wolfram.com/applications/astronomer/Notebooks/GPSSatellites.html)

Notice the time display though, sometimes it takes 3 seconds before updating which means that other data update is delayed too. My thoughts are that the parsing is too complex. Why not parse the whole string looking for the $GPxxx words and extract the data if found. If any word is missing then does it matter, the data that does exist will still be updated during the timer period. The example I posted in the 'other thread' does not seem to suffer from noticeable sync problems and the gps time updates each second. Does it matter if at startup the gps string does not begin with $, the odds are that the next and remaining $GPxxx words will be found and when the timer next fires, all data will be present. Watching the mainwin print of the gps$ seems to confirm that. I'm away again for a couple of days, on return I will 'steal' your sat position code, add it to my code and see where we go from there. :D
If I'm not back within 3 days you'll know that LB GPS has sent me off track. ;D

Have a play with this and see what results you get on your PC.

Code:
'############ LB gpsGUI version ############

'############ debug enable ############
debug=1
'nomainwin
'######################################
WindowWidth=303:WindowHeight=365
UpperLeftX=1:UpperLeftY=1
dim tag$(100)
dim fix$(3)
fix$(1)="No fix"
fix$(2)="2D fix"
fix$(3)="3D fix"
'GPS date/time
statictext #t.st1,"GPS NMEA data",10,15,230,25
statictext #t.st2,"Date/time:",10,42,70,25
stylebits #t.st21, _WS_BORDER,0,0,0
statictext #t.st21,"",80,40,160,25
'Number of sats
statictext #t.st3,"Number of Sats located: ",10,72,170,25
stylebits #t.st31, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st31,"",180,70,60,25
'Fix, No fix, 2D, 3D
statictext #t.st4,"Fix: ",10,102,60,25
stylebits #t.st41, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st41,"",80,100,144,25
graphicbox #t.gb1, 225,100,10,10
'GPS position
statictext #t.st5,"GPS position (DDmm.mmmmm):",10,135,230,25
statictext #t.st6,"Latitude:",10,160,80,25
stylebits #t.st61, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st61,"",100,160,140,25
'
statictext #t.st7,"Longitude:",10,192,80,25
stylebits #t.st71, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st71,"",100,190,140,25
'
statictext #t.st8,"Altitude:",10,222,80,25
stylebits #t.st81, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st81,"",100,220,140,25
'Speed/track
statictext #t.st9,"Speed/Track:",10,252,85,25
stylebits #t.st91, _WS_BORDER or _ES_CENTER,0,0,0
statictext #t.st91,"",100,250,140,25

checkbox #t.cb1, "Log",[log],[log],245,15,50,25
button #t.b1, "Tag",[tag],ul,245,250,45,25
open "GPS (ND-100 USB)" for window_nf as #t
#t "trapclose [quit]"
#t "font arial 11"
#t.gb1 "down;fill red;flush led"
Com=1024
oncomerror [comErr]
'set com port for device
open "com15:38400,8,n,1" for random as #gps
comOpen=1
tInt=1000

[start]
timer tInt,[go]
wait
[go]
#t.b1 "!disable"
#t.gb1 "delsegment led;fill red;flush led"
gps$ = input$(#gps, lof(#gps))
if debug then print gps$
gps$=Replace$(gps$,chr$(13)+chr$(10),",")

'find $GPGGA string
indx=1
while word$(gps$,indx,",")<>"$GPGGA"
    indx=indx+1
    scan
wend

t$=word$(gps$,indx+1,",")       'time
t$=left$(t$,2);":";mid$(t$,3,2);":";mid$(t$,5,2)
lat$=word$(gps$,indx+2,",")     'latitude
ns$=word$(gps$,indx+3,",")      'N or S
long$=word$(gps$,indx+4,",")    'longitude
ew$=word$(gps$,indx+5,",")      'E or W
s$=word$(gps$,indx+7,",")       'Number of sats in view
asl=val(word$(gps$,indx+9,",")) 'height asl (metres)

'find $GPRMC string
indx=1
while word$(gps$,indx,",")<>"$GPRMC"
    indx=indx+1
    scan
wend
gndSpeed=val(word$(gps$,indx+7,","))*1.15077945 'ground speed knots to mph
track$=word$(gps$,indx+8,",")           'track, degrees true
d$=word$(gps$,indx+9,",")       'date

'find $GPGSA string
indx=1
while word$(gps$,indx,",")<>"$GPGSA"
    indx=indx+1
    scan
wend
fix=val(word$(gps$,indx+2,","))       'fix data

#t.st21 left$(d$,2);"/";mid$(d$,3,2);"/20";right$(d$,2);" @ ";t$
#t.st31 s$              ';chr$(13)
#t.st41 fix$(fix)
if fix=3 then #t.gb1 "delsegment led;fill green;flush led"
if fix=2 then #t.gb1 "delsegment led;fill yellow;flush led"
if fix=1 then #t.gb1 "delsegment led;fill red;flush led"

#t.st61 lat$;" ";ns$
#t.st71 long$;" ";ew$
#t.st81 asl;"M / ";using("#####.##",asl*3.2808399);"ft"
#t.st91 using("##.#",gndSpeed);" / ";track$
if log then
    #lf d$;" / ";t$;" / ";lat$;" ";ns$;" / ";long$;" ";ew$;" / ";_
        asl;"M -";using("#####.##",asl*3.2808399);"ft";" / ";_
        using("##.#",gndSpeed);" / ";track$;" / ";fix
end if
#t.b1 "!enable"
wait

[log]
log=1-log
if log then
    open "gpsLogfile-";time$("seconds");".log" for output as #lf
    #lf "GPS log: Date/time/Latitude/longitude/Height asl/Speed/Track/fix"
    logFileOpen=1
    else
    if logFileOpen then close #lf
    logFileOpen=0
end if
wait

[tag]
    if tagNum<101 then
        if debug then print tagNum;": ";
        tag$(tagNum)=d$;"/";t$;"/";lat$;" ";ns$;"/";long$;" ";ew$
        print tag$(tagNum)
        tagNum=tagNum+1
        tag=0 'reset tag for next click
    end if
wait

[comErr]
notice "GPS unit not found!";chr$(13);"Program will close."

[quit]
timer 0
if comOpen then close #gps
if logFileOpen then close #lf
if tagNum>0 then
    open "geotag.log" for output as #gl
    for n=0 to tagNum-1
        if debug then print tag$(n)
        #gl tag$(n)
    next n
    close #gl
end if
close #t
end


function Replace$(string$, old$, new$)
    pos = 1
    while pos
        prevpos = pos
        pos = instr(string$, old$, pos)
        if pos then
            Replace$ = Replace$ + mid$(string$, prevpos, pos - prevpos) + new$
            pos = pos + len(old$)
        end if
    wend
    Replace$ = Replace$ + mid$(string$, prevpos)
end function

 
« Last Edit: Jul 4th, 2010, 2:31pm by mikeukmid » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5618
xx Re: Reading GPS NMEA data sentences
« Reply #3 on: Jul 4th, 2010, 4:25pm »

Mike your code runs very smoothly on my PC, so what was my code doing?

I had another go at my parsing routine. I abandond the "$" hunting and begin to trust that it will be there. So now I hunt for just the ending CRLF pair. I seem to have eliminated whatever problem I had coded as it now loops far more efficiently. Truth be told I don't know quite where it was getting hung up previously.

(edit to say, it was the way I was looping back in the old code. I did a quick fix because it stalled when there was no CRLF pair and sent it back to [getbuffer]. This fix caused it to keep seeking sentences rather than actually print the time! Fixed now.)

Now I can run it at 500ms or even 100ms but that means everything is getting drawn too often. So I use 1000ms and the clock ticks smoothly.

I also changed the GSV parsing to fix a bug falling out of sync with the three GSV messages. (I hope!)



Code:
nomainwin

    dim prn(12)'prn
    dim elv(12)'elevation
    dim azi(12)'azimuth
    dim snr(12)'signal to noise
    sat=1

    'set the window size
    WindowWidth = 500
    WindowHeight = 550

    groupbox #gps.GBTime, "Position", 6, 16, 232, 232
    statictext #gps.STTime, "Time", 14, 40, 32, 20
    statictext #gps.STDate, "Date", 14, 65, 32, 20
    textbox #gps.Time, 46, 36, 100, 25
    textbox #gps.Date, 46, 61, 100, 25
    textbox #gps.Qual, 195, 36, 40, 25
    statictext #gps.STQual, "Qual", 150, 40, 24, 20
    statictext #gps.STMode, "Mode", 150, 65, 35, 20
    textbox #gps.Mode, 195, 60, 40, 25
    statictext #gps.STLat, "Lat", 14, 131, 32, 20
    textbox #gps.LatPos, 46, 126, 96, 25
    statictext #gps.STLong, "Long", 14, 156, 32, 20
    textbox #gps.LongPos, 46, 151, 96, 25
    statictext #gps.STAlt, "Alt", 150, 131, 24, 20
    textbox #gps.Alt, 190, 126, 40, 25
    statictext #gps.STVel, "Vel", 150, 156, 24, 20
    textbox #gps.Vel, 190, 151, 40, 25
    statictext #gps.STHead, "Head", 150, 181, 36, 20
    textbox #gps.Head, 190, 176, 40, 25
    groupbox #gps.GBChannel, "Channel Status", 6, 248, 232, 232
    graphicbox #gps.Channel, 22,266 , 200, 200
    groupbox #gps.GBMap, "Mapping", 242, 16, 232, 232
    graphicbox #gps.Map, 260, 36, 200, 200
    groupbox #gps.GBSat, "Satelite Positions", 242, 248, 232, 232
    graphicbox #gps.Sat, 260,266 , 200, 200
    open "GPS NMEA Tracking" for window as #gps
    'tell the window where to go when it closes
    print #gps, "trapclose [quit]"

    #gps.Sat, "down ; home ; circle 100 ; font arial 8 ; backcolor green"
    #gps.Channel, "down ; font arial 8 ; size 12"

    oncomerror [comerror]
    open "com11:38400,n,8,1,ds0,cs0,rs" for random as #gpsbuffer

    'wait for the port to establish then read it
    timer 1000, [getbuffer]
    wait

    [getbuffer]
    'read fragmented buffer to secondary buffer
    if lof(#gpsbuffer)>0 then
        watchcount=0
        secondbuffer$=secondbuffer$+input$(#gpsbuffer, lof(#gpsbuffer))
    end if
    'check if we have a complete sentence
    endofdata=instr(secondbuffer$,chr$(13)+chr$(10),1)
    [parsedata]
            if endofdata>0 then
                'we have a valid sentence, get it
                dat$=left$(secondbuffer$,endofdata)
                'remove it from secondary buffer
                secondbuffer$=right$(secondbuffer$,len(secondbuffer$)-endofdata-1)
                'now parse it
                select case left$(dat$,6)

                case "$GPGGA" ' position info
                    t$=word$(dat$,2,",")       'time
                    t$=left$(t$,2);":";mid$(t$,3,2);":";mid$(t$,5,2)
                    #gps.Time,t$
                    lat$=word$(dat$,3,",")     'latitude
                    latDeg$=mid$(lat$,1,2)+" Deg "
                    latMin$=mid$(lat$,3,2)+"' "
                    latSec$=using("##",60*val(right$(lat$,5)))+chr$(34)
                    ns$=word$(dat$,4,",")      'N or S
                    #gps.LatPos,latDeg$+latMin$+latSec$+" "+ns$
                    long$=word$(dat$,5,",")    'longitude
                    longDeg$=str$(val(mid$(long$,1,3)))+" Deg "
                    longMin$=mid$(long$,4,2)+"' "
                    longSec$=using("##",60*val(right$(long$,5)))+chr$(34)
                    ew$=word$(dat$,6,",")      'E or W
                    #gps.LongPos,longDeg$+longMin$+longSec$+" "+ew$
                    quality=val(word$(dat$,7,","))
                    select case quality
                    case 0
                    q$="INV"
                    case 1
                    q$="GPS"
                    case 2
                    q$="DGPS"
                    case 3
                    q$="PPS"
                    case 4
                    q$="RTK"
                    case 5
                    q$="FRTK"
                    case 6
                    q$="EDR"
                    case 7
                    q$="MAN"
                    case 8
                    q$="SIM"
                    end select
                    #gps.Qual,q$
                    numsats=val(word$(dat$,8,","))
                    height$=using("####",val(word$(dat$,10,",")))
                    #gps.Alt,height$;"m"

                case "$GPRMC" ' min data including heading and velocity

                    vel=val(word$(dat$,8,","))*1.15077945 'ground speed knots to mph
                    tra=val(word$(dat$,9,","))           'track, degrees true
                    d$=word$(dat$,10,",")       'date
                    d$=left$(d$,2);"/";mid$(d$,3,2);"/20";right$(d$,2)
                    #gps.Vel,vel;"mph"
                    #gps.Head,tra
                    #gps.Date,d$
                    #gps.Map,"cls ; home ; turn ";tra;" go ";vel*5

                case "$GPGSA" ' fix quality info

                    mode$=word$(dat$,3,",")
                    select case val(mode$)
                    case 1
                    m$="No Fix"
                    case 2
                    m$="2D Fix"
                    case 3
                    m$="3D Fix"
                    end select
                    #gps.Mode,m$

                case "$GPGSV" ' satelite position and signal info

                    numsat=val(word$(dat$,4,","))
                    sennum=val(word$(dat$,3,","))
                    sat=sennum*4-3
                    offset=0
                    while (sat<=numsat) and (offset<16)
                        prn(sat)=val(word$(dat$,5+offset,","))
                        elv(sat)=val(word$(dat$,6+offset,","))
                        azi(sat)=val(word$(dat$,7+offset,","))
                        snr(sat)=val(word$(dat$,8+offset,","))
                        offset=offset+4
                        sat=sat+1
                    wend
                end select
                print dat$
            end if
            ' loop back immediately if we still have more to read
            endofdata=instr(secondbuffer$,chr$(13)+chr$(10),1)
            if endofdata then [parsedata]


    ' make sure we are still getting info
    watchcount=watchcount+1
    if watchcount>6 then [comceased]

    'now draw the satelite position and signal info
    #gps.Sat,"cls ; home ; circle 100"
    #gps.Channel,"cls"
    for n= 1 to numsat
        #gps.Sat, "up ; home ; north ; turn ";azi(n);" ; go ";90-elv(n);" ; down ;\";right$("00"+str$(prn(n)),2)
        #gps.Channel, "color black ; place ";n*14;" 180 ;\";right$("00"+str$(prn(n)),2)
        #gps.Channel, "color green ; place ";n*14+6;" 160 ; north ; go ";snr(n)*3
    next


   'wait for next [checkbuffer]
    wait

    [comceased]
    timer 0
    notice "Data transmission stopped!";chr$(13);"Program will close."
    close #gpsbuffer
    close #gps
    end

    [comerror]
    timer 0
    notice "GPS unit not found!";chr$(13);"Program will close."
    close #gps
    end


    [quit]
    timer 0
    close #gpsbuffer
    close #gps
    end



 
« Last Edit: Jul 15th, 2010, 10:33am by Rod » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5618
xx Re: Reading GPS NMEA data sentences
« Reply #4 on: Jul 5th, 2010, 10:42am »

An improved interface with some bmp backgrounds. The mapping is very rough but I'm sure you will all get the idea.

http://www.freewebs.com/gamebin/RodGPS.zip
User IP Logged

mikeukmid
Guest
xx Re: Reading GPS NMEA data sentences
« Reply #5 on: Jul 15th, 2010, 09:30am »

on Jul 5th, 2010, 10:42am, Rod wrote:
An improved interface with some bmp backgrounds. The mapping is very rough but I'm sure you will all get the idea.

http://www.freewebs.com/gamebin/RodGPS.zip


V. nice but I got lost!

longMin$=mid$(long$,3,2)+"' " should be longMin$=mid$(long$,4,2)+"' "

You may wish to use in Arial font, chr$(176), the 'degrees' symbol.

Mike. grin
« Last Edit: Jul 15th, 2010, 10:09am by mikeukmid » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5618
xx Re: Reading GPS NMEA data sentences
« Reply #6 on: Jul 16th, 2010, 11:57am »

Thanks for the fixes. I may dig out my laptop and try and get some better precision on local mapping!
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

Rules|Home|Help|Search|Recent Posts|Notification

Donate $6.99 for 50,000 Ad-Free Pageviews!

| |

This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls