Connecting to Codemasters telemetry feed

Codemasters publishes telemetry data packets you can receive to make your own telemetry based applications.
March 24 2012
f1 2010    f1 2011    f1 2012    projects

Codemasters F1 201x (lastest incarnation is F1 2012) does not come with utilities that allow you analyse your telemetry.  This is disappointing to a many long time F1 game players.  Even Geoff Crammands’ Grand Prix series came with the ability to analyse many different data points, including: wheelspin at each of the four corners of the car, speed, brake input, throttle input, gear, time, ground clearance, and more.   I think Codemasters response when asked why this was not included was because it was a more advanced feature and wouldn’t be popular with the majority of the gamers (the game is available on PC, Xbox, and PS3).

Fortunately for those who are interested in really “Living the life”, Codemasters has exposed a telemetry data point via UDP.  By creating a UDP ‘server’ (though it’s only a UDP endpoint) the game can connect to, we can receive the telemetry published by F1 2012.  I recently spent a bit of time analysing this stream to help with building my realtime telemetry app for the F1 2012 game ( see here )

Before receiving the data we need to reconfigure F1 2012 to point to our end point.  This is done by modifying the “hardware_settings_config.xml” file found in your My Documents folder subpath ./My Games/FormulaOne2012/hardwaresettings/. Open the file and change the line

Old Telem Setting

to be

New Telem Setting

You can set ip and port to the correct values for wherever your UDP end point will be listening for a connection.

The packet F1 2011 puts out through this contains the following fields in order.  All fields are float datatype (in C#)

Field Description
Lap

The number of laps since the session began.

Restarting a Session in the game will set this back to 0.

Time

Time in seconds since this telemetry session began

Restarting a Session in the game will set this back to 0.

LapTime Time in seconds since the lap began. F1 2012 has a capture/send rate of 60 telemetry packets per second.  This is 0 for an 'out lap'
LapDistance The distance in meters since the lap began.  This can be negative for 'out' laps.  If you cross the start finish line and then reverse back over it the LapDistance will shoot back up buytbut the Lap will stay the same
Distance

The laps and percent of laps covered since the session began.

The value is negative when you first enter a practice session.  After you cross the start finish line for the first time it becomes positive (0).  A value of 1.5 would indicate you're halfway through your second lap.  1.995 would indicate you're almost finished your second lap.

X The X position of the car in the world
Y The Y position of the car in the world
Z The Z position of the car in the world
Speed The car speed at this point in time.  To get km/hr, multiply this value by 3.6 (I’m not sure why codemasters uses this scale).
XV  
YV  
ZV  
XR  
YR  
ZR  
XD  
YD  
ZD  
SuspensionPositionRearLeft The position of the rear left suspension
SuspensionPositionRearRight The position of the rear right suspension
SuspensionPositionFrontLeft The position of the front left suspension
SuspensionPositionFrontRight The position of the front right suspension
SuspensionVelocityRearLeft The speed of travel of the rear left suspension
SuspensionVelocityRearRight The speed of travel of the rear right suspension
SuspensionVelocityFrontLeft The speed of travel of the front left suspension
SuspensionVelocityFrontRight The speed of travel of the front right suspension
WheelSpeedRearLeft The speed the rear left wheel is travelling.  I assume this value with Speed subtracted gives wheelspin.  Although it’s a good 6 km/hr faster than the front, if that’s the case!
WheelSpeedRearRight The speed the rear right wheel is travelling.
WheelSpeedFrontLeft The speed the front left wheel is travelling
WheelSpeedFrontRight The speed the front right wheel is travelling
Throttle The percent of throttle applied.  1 = full throttle and 0 = no throttle
Steer The amount of left/right (-/+) input into steering. 0 = straight ahead.
Brake The percent of brake applied. 1 = full brake and 0 = no brake
Clutch This value will always be 0
Gear The current gear
GForceLatitudinal The amount of gforces being generated due to turning
GForceLongitudinal The amount of gforces being generated due to acceleration or braking
Lap The current Lap.  0 = first lap across the start/finish line.
EngineRevs The RPM of the engine. This value needs to be multiplied by 10 to get the real RPM, so it would seen.

Detecting new laps

From what I can tell, the following can be used to determine which lap the driver is on.

Action Details
Sitting in the Pits When the driver is sitting in the pits LapTime is 0, Speed is 0.
Out Laps

Out laps, that is laps where the driver has exited the pits but not yet crossed the start/finish line on the race track have a LapTime value of 0 and a negative Distance value or a Distance value of less than 1.   The value is the fraction of a lap you have left before you start your first timed lap.  As you leave it'll be around -0.95 (95% to go) and as you're about to cross the start finish line it'll be -0.0001 (.01% to go) approx.  If you've crossed the start/finish line once, the value starts at 0 and gets larger as you progress through the lap, toward a value of 1 (which is the start of the next lap).

On your very first of the session the Lap value will be the same as the next lap so you cannot use only changes in the Lap value to detect new laps.

Return to Pits When you return to the pits after being partway through a lap your Lap value will not change, so you need to use some logic to recognise a return to pits.  LapTime = 0 is a good one.
Packet frequency The first packet received from F1 2012 after the car has crossed the start/finish line will be within 1/60th of a second, which is the rate at which F1 2011 publishes data.
Reversing back across the start finish line LapDistance will vary depending on how much you move around during your lap.  If you cross the line it'll be set back to 0.  If you then reverse back across the finish line it'll jump to a large number.

 

The Source

To read the data from UDP point in C# you can use the following

// This method runs continously in the data collection thread.  It
// waits to receive UDP packets from the game, converts them and writes
// them to the shared struct variable.
private void FetchData()
{
    while (true)
    {
        // Get the data (this will block until we get a packet)
        Byte[] receiveBytes = udpSocket.Receive(ref senderIP);

        // Lock access to the shared struct
        syncMutex.WaitOne();

        // Convert the bytes received to the shared struct
        latestData = PacketUtilities.ConvertToPacket(receiveBytes);
        manager.AddPacket(latestData);
        
        // Release the lock again
        syncMutex.ReleaseMutex();
    }
}

public static class PacketUtilities
{
    // Helper method to convert the bytes received from the UDP packet into the
    // struct variable format.
    public static TelemetryPacket ConvertToPacket(byte[] bytes)
    {
        // Marshal the byte array into the telemetryPacket structure
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var stuff = (TelemetryPacket)Marshal.PtrToStructure(
            handle.AddrOfPinnedObject(), typeof(TelemetryPacket));
        handle.Free();
        return stuff;
    }
}

My TelemetryPacket class is the following. For my particular application (F1Speed) I only need to store certain fields.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml.Serialization;

namespace F1Speed.Core
{
    [Serializable]
    public struct TelemetryPacket : ISerializable
    {
        public TelemetryPacket(SerializationInfo info, StreamingContext context)
        {
            Time = info.GetValue<float>("Time");
            LapTime = info.GetValue<float>("LapTime");
            LapDistance = info.GetValue<float>("LapDistance");
            Distance = info.GetValue<float>("Distance");
            Speed = info.GetValue<float>("Speed");
            Lap = info.GetValue<float>("Lap");
            X = 0;
            Y = 0;
            Z = 0;
            XV = 0;
            YV = 0;
            ZV = 0;
            XR = 0;
            YR = 0;
            ZR = 0;
            XD = 0;
            YD = 0;
            ZD = 0;
            SuspensionPositionRearLeft = 0;
            SuspensionPositionRearRight = 0;
            SuspensionPositionFrontLeft = 0;
            SuspensionPositionFrontRight = 0;
            SuspensionVelocitoyRearLeft = 0;
            SuspensionVelocitoyRearRight = 0;
            SuspensionVelocitoyFrontLeft = 0;
            SuspensionVelocitoyFrontRight = 0;
            WheelSpeedBackLeft = 0;
            WheelSpeedBackRight = 0;
            WheelSpeedFrontLeft = 0;
            WheelSpeedFrontRight = 0;
            Throttle = 0;
            Steer = 0;
            Brake = 0;
            Clutch = 0;
            Gear = 0;
            GForceLatitudinal = 0;
            GForceLongitudinal = 0;
            EngineRevs = 0;

        }

        public float Time;
        public float LapTime;
        public float LapDistance;
        public float Distance;
        [XmlIgnore]
        public float X;
        [XmlIgnore]
        public float Y;
        [XmlIgnore]
        public float Z;        
        public float Speed;
        [XmlIgnore]
        public float XV;
        [XmlIgnore]
        public float YV;
        [XmlIgnore]
        public float ZV;
        [XmlIgnore]
        public float XR;
        [XmlIgnore]
        public float YR;
        [XmlIgnore]
        public float ZR;
        [XmlIgnore]
        public float XD;
        [XmlIgnore]
        public float YD;
        [XmlIgnore]
        public float ZD;
        [XmlIgnore]
        public float SuspensionPositionRearLeft;
        [XmlIgnore]
        public float SuspensionPositionRearRight;
        [XmlIgnore]
        public float SuspensionPositionFrontLeft;
        [XmlIgnore]
        public float SuspensionPositionFrontRight;
        [XmlIgnore]
        public float SuspensionVelocitoyRearLeft;
        [XmlIgnore]
        public float SuspensionVelocitoyRearRight;
        [XmlIgnore]
        public float SuspensionVelocitoyFrontLeft;
        [XmlIgnore]
        public float SuspensionVelocitoyFrontRight;
        [XmlIgnore]
        public float WheelSpeedBackLeft;
        [XmlIgnore]
        public float WheelSpeedBackRight;
        [XmlIgnore]        
        public float WheelSpeedFrontLeft;
        [XmlIgnore]
        public float WheelSpeedFrontRight;
        [XmlIgnore]
        public float Throttle;
        [XmlIgnore]
        public float Steer;
        [XmlIgnore]
        public float Brake;
        [XmlIgnore]
        public float Clutch;
        [XmlIgnore]
        public float Gear;
        [XmlIgnore]
        public float GForceLatitudinal;
        [XmlIgnore]
        public float GForceLongitudinal;        
        public float Lap;
        [XmlIgnore]
        public float EngineRevs;
        [XmlIgnore]
        public float SpeedInKmPerHour
        {
            get { return Speed*3.60f;  }
        }

        public override string ToString()
        {
            return "Lap: " + Lap + ", " +
                   "Time: " + Time + ", " +
                   "LapTime: " + LapTime + ", " +
                   "LapDistance: " + LapDistance + ", " +
                   "Distance: " + Distance + ", " +                   
                   "Speed: " + Speed;
        }        

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Time", Time);
            info.AddValue("LapTime", LapTime);
            info.AddValue("LapDistance", LapDistance);
            info.AddValue("Distance", Distance);
            info.AddValue("Speed", Speed);
            info.AddValue("Lap", Lap);       
} } }

The current project source for F1Speed is available on bitbucket https://bitbucket.org/robgray/f1speed/ If you want the latest source, always consult bitbucket.

Post a comment

comments powered by Disqus