Site icon R-bloggers

Collect and Parse GPS (NMEA0183) Data in R

[This article was first published on BioStatMatt » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

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.

To leave a comment for the author, please follow the link and comment on their blog: BioStatMatt » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.