Collect and Parse GPS (NMEA0183) Data in R

I recently wrote a serial connection for R-2.11.0 so that I can communicate with serial devices, for example an old Garmin eTrex Legend. This GPS device is able to output NMEA0183 sentences to a standard serial port (4800,8,1,N). I hooked up the device and used the serial connection to collect some data using some R commands similar to the following

> con <- serial("/dev/ttyUSB0", baudrate=4800L)
> testdata <- rawToChar(readBin(con, "raw", 10000))
> close(con)
> testdata
[1] "5801,W,1,04,2.1,57.7,M,-32.3,M,,*4E\r\n$GPGSA,A,2,
03,06,,16,23,,,,,,,,2.3,2.1,1.0*33\r\n$GPGSV,2,2,07,23,
...
E\r\n$GPBOD,,T,,M,,*47\r\n$GPVTG,0.0,T,7.2,M,0.0,N,0.0,
K*4B\r\n$PGR"

The particular NMEA0183 sentence I want begins with $GPRMC, the recommended minimum navigation information. This sentence includes UTC time and date, latitude, longitude, heading, ground speed and others. I've attached a copy of an unofficial description of the NMEA0183 protocol. I wrote the following two R functions to parse the $GPRMC sentences.

getGPRMC <- function(data) {
  ans <- list(rmc=NULL, rest=data)
  rxp <- "\\$GPRMC(,[^,]*){12}\\*[0-9,A-F]{2}\r\n"
  beg <- regexpr(rxp, data)
  if(beg == -1) return(ans)
  end <- beg + attr(beg, "match.length")
  sub <- substr(data, beg, end - 6)
  ans$rmc <- strsplit(sub, ",")[[1]]
  names(ans$rmc) <- c("id","utc","status","lat","N/S",
                      "long","E/W","knots","cog","date",
                      "mag","E/W","mode")
  ans$rest <- substr(data, end, nchar(data))
  return(ans)
}

getAllGPRMC <- function(data) {
  res <- getGPRMC(data)
  ans <- res$rmc
  while(!is.null(res$rmc)) {
    ans <- rbind(ans, res$rmc)
    res <- getGPRMC(res$rest)
  }
  return(ans)
}

The functions and test data may be found here NMEA0183Parse.R. The regular expression used to identify the $GPRMC sentence is somewhat rudimentary, I welcome any insights in this regard. Also, these functions may be easily modified to parse other NMEA0183 sentences. The following may be reproduced in R verbatim without any additional setup.

> source("http://biostatmatt.com/R/NMEA0183Parse.R")
> ls()
[1] "getAllGPRMC" "getGPRMC"    "testdata"
> getAllGPRMC(testdata)
    id       utc      status lat         N/S long         E/W knots cog  
ans "$GPRMC" "230320" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    "$GPRMC" "230320" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    "$GPRMC" "230322" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    "$GPRMC" "230324" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    "$GPRMC" "230326" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    "$GPRMC" "230328" "A"    "3246.1080" "N" "07955.4646" "W" "0.0" "0.0"
    date     mag   E/W mode
ans "110510" "7.2" "W" "A" 
    "110510" "7.2" "W" "A" 
    "110510" "7.2" "W" "A" 
    "110510" "7.2" "W" "A" 
    "110510" "7.2" "W" "A" 
    "110510" "7.2" "W" "A" 

According to Google Maps, this location is (long/lat) is at the Charleston Battery Park, Charleston Battery Park.

2 thoughts on “Collect and Parse GPS (NMEA0183) Data in R

  1. Could it be something as simple as decimal degrees from the gps and google maps needing deg min sec?

    1. Nicholas,
      Thanks for pointing this out. Google Maps (correctly) interpreted the coordinates in decimal rather than degree, minutes, and seconds. I've corrected it now.
      -Matt

Comments are closed.