2 Loading the Live Telemetry Route Data

The examples provided utilise data that has already been downloaded.

2.1 Spatial Utilities

The GPS data is provided as a set of latitude and longitude co-ordinates. For various forms of analysis, such as calculating and comparing distance in meters, we need to map from the latitude/longitude co-ordinate system to a projection such as UTM (Universal transverse Mercator).

The following function identifies the correct UTM region for managing the conversion.

library(sf)

lonlat2UTM_hemisphere <- function(lonlat) {
    ifelse(lonlat[1] > 0, "north", "south")
}

lonlat2UTMzone = function(lonlat) {
  utm = (floor((lonlat[1] + 180) / 6) %% 60) + 1
  if(lonlat[2] > 0) {
    utm + 32600
  } else{
    utm + 32700
  }
}

Create a simple latitude/longitude CRS (co-ordinate reference system) string to specify the CRS for use with simple lat/long data:

latlon_crs = 4326

We can also set the timezone. This might be done explicitly, or from a location co-ordinate using the R lutz package.

timezone = "Europe/Helsinki"

2.2 Loading in the Telemetry Route Data

The data is available in the form of a simple CSV data file.

The data is presented in a reverse chronological order, but it is more natural for us to present it in chronological (increasing time) order.

telem_df_min = read.csv(file.path(path, "df_telemetrydata_SS7_Evans.csv") )  %>%
                  map_df(rev)

kable(head(telem_df_min), format = "html") %>%
  kable_styling() %>%
  kableExtra::scroll_box(width = "100%")
X accx accy altitude brk driverid gear heading kms lat lon name rpm speed status throttle track utx X_rally_stageid X_carentryid X_telemetryID X_name
1870 0 0 0 0 NA 0 144 0.6 61.83077 25.12109 33 0 166 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans
1869 0 0 0 0 NA 0 150 0.7 61.82966 25.12240 33 0 140 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans
1868 0 0 0 0 NA 0 172 0.8 61.82912 25.12291 33 0 60 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans
1867 0 0 0 0 NA 0 220 0.9 61.82856 25.12200 33 0 107 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans
1866 0 0 0 0 NA 0 210 1.0 61.82766 25.12067 33 0 149 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans
1865 0 0 0 0 NA 0 208 1.1 61.82662 25.11919 33 0 159 Competing 0 NA 1.633164e+12 bcc5537d-d28a-40af-ba86-95dad7fb9cd1 b185c5df-8115-40cf-bd81-566f016f6bf5 /a3f5f3f5-3fb0-42ab-af90-24d91c0493d0/ss07eva_telemetry_js/js Evans

We note quite a few null columns in there, so let’s clean those out of the dataframe too:

telem_df_min = telem_df_min %>%
                  select(-c(accx, accy, altitude, brk, driverid,
                            gear, rpm, throttle, track)) %>%
                  select(-c(X_rally_stageid, X_carentryid, X_telemetryID))

kable(head(telem_df_min), format = "html") %>%
  kable_styling() %>%
  kableExtra::scroll_box(width = "100%")
X heading kms lat lon name speed status utx X_name
1870 144 0.6 61.83077 25.12109 33 166 Competing 1.633164e+12 Evans
1869 150 0.7 61.82966 25.12240 33 140 Competing 1.633164e+12 Evans
1868 172 0.8 61.82912 25.12291 33 60 Competing 1.633164e+12 Evans
1867 220 0.9 61.82856 25.12200 33 107 Competing 1.633164e+12 Evans
1866 210 1.0 61.82766 25.12067 33 149 Competing 1.633164e+12 Evans
1865 208 1.1 61.82662 25.11919 33 159 Competing 1.633164e+12 Evans

2.3 Preparing the Telemetry Route Data

We can perform a small amount of cleaning on the data to remove any rows where there are missing latitude or longitude values before before generating a spatial features data object with a column containing the geometry information with the lat/long co-ordinate reference system (CRS) specified.

To better manage the timing components, we can cast the universal time stamp (in milliseconds) to a datetime stamp, ensuring we also set the correct time zone along the way. A delta_s columns is also used to capture the time difference (in seconds) between sample points.

X heading kms name speed status utx X_name geometry delta_s utc
1870 144 0.6 33 166 Competing 1.633164e+12 Evans POINT (25.12109 61.83077) 0.0 2021-10-02 11:37:23
1869 150 0.7 33 140 Competing 1.633164e+12 Evans POINT (25.1224 61.82966) 3.2 2021-10-02 11:37:26
1868 172 0.8 33 60 Competing 1.633164e+12 Evans POINT (25.12291 61.82912) 6.4 2021-10-02 11:37:30
1867 220 0.9 33 107 Competing 1.633164e+12 Evans POINT (25.122 61.82856) 9.6 2021-10-02 11:37:33
1866 210 1.0 33 149 Competing 1.633164e+12 Evans POINT (25.12067 61.82766) 12.8 2021-10-02 11:37:36
1865 208 1.1 33 159 Competing 1.633164e+12 Evans POINT (25.11919 61.82662) 16.0 2021-10-02 11:37:39

For convenience, let’s also generate a UTM projection of this spatial features dataframe:

# Generate a UTM projection of the route telemetry
telem_df_min_utm = telem_df_min %>%
                      st_transform(crs = st_crs(utm_proj4_string))

2.4 Visual Preview of the Telemetry Route Data

We can preview the route on an interactive map using the leaflet package, casting the route data to a set of paired co-ordinates:

library(leaflet)
## Warning: package 'leaflet' was built under R version 4.0.5
tmp_route <- telem_df_min %>% st_coordinates() 

leaflet(tmp_route) %>% 
  addProviderTiles("OpenTopoMap", group = "OSM") %>% 
  addPolylines(color = "red", weight = 5)

The “live” telemetry includes the road section data. To access the data for just the stage we need to filter it somehow. There are two ways we might do this:

  • based on time: if we know the stage start time for the driver, and their stage time, we can filter the data based on timestamps;
  • based on location: if we have route data for the stage, we can create a buffered area around the stage route, and then filter telemetry data based on points that lay inside that buffered area.