Building McLaren.com – Part 3: Reading Telemetry

I’ve just finished working on McLaren’s new F1 site, http://mclaren.com/home, for the 2010 season, at Pirata London, for Work Club.

I’ll be writing up what we’ve done here in several parts. Sign up for my RSS feed to keep updated.

Part three covers the JavaScript data for the telemetry panel, known as “The Race 1.0b”.

Using JSON-P

There’s very little processing of the feed between the web server and McLaren. The telemetry data is simply reformatted for convenience and merged with the Commentary (which is actually added through a local source by a guy in the pit garage). We made sure we sent through as much data as we could get – though you may need a large screen to be able to see it!

Data is sent using JSON-P. This is so that the data can be acquired from the feed domain rather than the site domain; crucial since the data feed server is in a different network for performance.

JSON is a great way to mark up data for consumption by JavaScript. It’s quick to assimilate, and very easy to read and debug. It’s also far shorter in length than the equivalent XML structure.

One of the principles of the Nginx Http Push Module is request idempotency. If this doesn’t mean anything to you, you’re not alone. All this means is that the client should always request the same URL, but with different caching times set. This lets the caching mechanisms within nginx serve up all the messages posted since your last request. However, this is no use to us – there is simply no way to load json-p cross-domain without using script tags, and webkit-based browsers simply will not reload the scripts if the filenames are the same. (I suspect this is true of other browsers too actually, but I’ve got caching turned off for development in Firefox).

I append a randomised string to the end of my json-p requests (using cache:false in my jQuery ajax request) to avoid caching. The broadcast mechanism still works, but I’m unable to use the queue backlog in the nginx http push module. I have therefore set the maximum queue length to zero.

The disadvantage of this is that I will only receive packets of data that are sent when I am on the line as a subscriber. If my connection is patchy, then I might miss packets of data – not critical for telemetry, but a shame for any commentary that is sent through.

However, I am able to broadcast the JSON-P packets to vast numbers of subscribers.

JSON Format

The ‘standard’ telemetry packet looks like this:

Dashboard.jsonCallback('{"drivers":{"HAM":{"code":"HAM","telemetry":{"timestamp":"18:43:38.078","nEngine":758,"NGear":0,"rThrottlePedal":0,"pBrakeF":2,"gLat":0,"gLong":0,"sLap":0,"vCar":0,"NGPSLatitude":-37.85131,"NGPSLongitude":144.97086},"additional":{"lap":"0","position":"6","is_racing":"0"}},"BUT":{"code":"BUT","telemetry":{"timestamp":"18:43:38.317","nEngine":1695,"NGear":0,"rThrottlePedal":0,"pBrakeF":1,"gLat":0,"gLong":0,"sLap":0,"vCar":0,"NGPSLatitude":-37.84984,"NGPSLongitude":144.96927},"additional":{"lap":"0","position":"1","is_racing":"0"}}}}');

It’s pretty clear what each term above means. The packet above is from a lap of the Australian Grand Prix in Melbourne.

The commentary, and all data in ‘additional’, is provided by the commentry team in the pits. This is why the lap and place can sometimes seem out of sequence.

At this point it’s a good time to add a legal note:

  • The data must not be stored or distributed. This data is copyrighted like other information published on the Internet, and all F1 data is covered by strict rules regarding usage.
  • I am not employed by McLaren and do not speak for McLaren. I give no authority nor advice on how to use this feed, and am only writing this post to help others who may wish to build a similar system.

Having said that, here are my thoughts on netiquette:

  • The speed, throttle and brake are sponsored by Vodafone. If quoting these values, it would be a good karma to give a link to their site.
  • McLaren are providing this data for you to view, as a fan. If referring to the data, you should provide a link to their site, and tell them how cool it is.
  • Don’t abuse the servers. We can see the discrepancy between viewers on our site and from others, and measures might be taken to prevent feed highjacking.

Ok, to continue. Every lap end, we get some extra information in the packet:

Dashboard.jsonCallback('{"drivers":{"HAM":{"lapTimeS":"91.959","maxSpeedKph":305,"meanSpeedKph":204,"maxLateralG":6,"code":"HAM","telemetry":{"timestamp":"17:47:32.693","nEngine":15877,"NGear":5,"rThrottlePedal":0,"pBrakeF":51,"gLat":1,"gLong":-2,"sLap":316,"vCar":202.6,"NGPSLatitude":-37.84817,"NGPSLongitude":144.96664},"additional":{"lap":"0","position":"7","is_racing":"0"}},"BUT":{"code":"BUT","telemetry":{"timestamp":"17:47:32.938","nEngine":17276,"NGear":5,"rThrottlePedal":100,"pBrakeF":1,"gLat":0,"gLong":0,"sLap":593,"vCar":232.1,"NGPSLatitude":-37.846,"NGPSLongitude":144.96573},"additional":{"lap":"0","position":"2","is_racing":"0"}}}}');

Extra fields in this packet are:

  • lapTimeS
  • maxSpeedKph
  • meanSpeedKph
  • maxLateralG

How does it request the data?

I use jQuery rather than Mootools. So, I rewrote Leo’s Mootools plugin (provided for the chatroom on the pushmodule site) in jQuery. I’m not convinced it offers me anything much anymore, since I’ve taken out most of what it did, but it’s easy to use. It’s located at http://mclaren.com/_assets/js/site/jquery.nginx_subscribe.js.

I also use the jQuery JSON parsing plugin.

I then use those plugins with this code:

var Dashboard = function () {
	// URL of data feed
	var dashboardURL = 'http://feed.mclaren.com/feed/sub'; // Live service
	// on document load
	$(document).ready(function() {
		// create subscriber
		var dashboard_subscribe = $.nginx_subscribe(
			dashboardURL, 
			function success(textResp) {
				// the script calls success function direct
			},
			function failure(resp) {
				if (window.console) {
					console.log('subscribe failure');
				}
			}
		);
	});
	var addCommentary = function(jsonStr) {
		alert(jsonObj);
	}
	var addTelemetry = function(jsonObj) {
		alert(jsonObj);
	}
	var jsonCallback = function(jsonStr) {
		try {
			var respJson = jQuery.evalJSON(jsonStr);
			if (respJson.commentary && respJson.commentary.length) addCommentary(respJson.commentary);
			if (respJson.drivers) addTelemetry(respJson.drivers);
		} catch (e) {
			if (window.console) {
				console.log(e);
			}
		}
	}
	return {jsonCallback:jsonCallback};
}

Obviously this script isn’t great because it will either alert you several times a second if a race is on, or not respond at all. You’ll need to set up an nginx feed server yourself (as described in Part 2), and start POSTing to it, before you see any responses out of race time, and you’ll want to replace the alerts with something more useful.

I like to use the Net view of Firebug to watch the network traffic.

Cool uses of the data

From the very first race, our telemetry feed has been analysed by the clever mashup coders out there. One of my favourites is OUseful.info.

This map shows the points in Bahrain where Hamilton hit 100% throttle!

And this beautiful layout shows which gear he was in as he did it.

It’s a great little site, and I’m looking forward to see more insights into the data coming out. But it would be nice to see some copyright mentions shown for the data, as well as for the map itself.

In the next part in the series, I’ll have a look at Load Testing.

  • http://ouseful.info psychemedia

    Hi Kenneth
    As the person who put together the posts on OUseful.info, I'm really interested to see how the site was put together and how you're managing the data.

    As far as copyright notices go, if you can give me a boilerplate notice, I'll happily add it to each post in the series… feel free to mail me the notice, or post it as a comment to any of the posts, just in case I don't catch it here…

  • http://ouseful.info psychemedia

    PS my latest view over the data is here: http://ouseful.wordpress.com/2010/04/07/f1-data… and explores the notion of “Driver DNA”, an expression of various data fields for a driver over the whole of the race.

    My initial technical notes about how I parsed the data are at http://ouseful.wordpress.com/2010/03/21/f1-data
    I'll post more details, along with code, once it's stable…

  • kennethkufluk

    I'm not sure what it would be, but I guess you could just add “source: mclaren.com”, like you'd attribute CC content. I can't speak for the team. I like what you put in the last post :)

    I love what you're doing with the data, and how you're displaying it. And I'm glad you liked the blog. Is there anything else you think I should add?