The online racing simulator
Live telemetry data in test patch U9
(19 posts, started )
Live telemetry data in test patch U9
Hello programmers.

Detailed live telemetry is now available in a new customisable OutSim packet.

It is a combination of the RAF data and OutSim data. If this might be useful to you, I'd like to hear if there is any more information you would like to receive or any problems you see with this system. It is a first test in this test patch so please expect it to change.

The position of the car is the location of the reference point described in the CAR_info specification.

Enable detailed OutSim by setting the OutSim Opts value in cfg.txt
All extra data can be switched on with the value ff
The new data is documented in the attached header file OutSimPack.h

Download U9:
Attached files - 1.3 KB - 773 views
This could be really useful. Thanks Scawen
Just tested with all variables. It's great. Thank you.
(Edit - Answered my own questions while trying this out.)

Nice implementation, works very well. Love that you have wheel steer angles, forces, loads and slip angles directly available. I would like to see this level of telemetry detail available in all serious sims. rFactor 2, RRE and AMS1 have some but not all of this data.

Which coordinate systems are used for distances/velocities/accelerations (world or vehicle)?
Answer - world coordinates. Use Euler angles and the general rotation matrix to get the vehicle equivalents: ... _matrix#General_rotations

Is the telemetry streamed only to UDP or are there options to save to disk?
Answer - UDP only, but it's easy enough to write a program to write to disk as binary data, CSV etc.

In CAR_info.bin, is "parallel steer" reflecting Ackermann factor? If so, can you give more detail on the value derivation please, including for anti-Ackermann?
Answer - Yes, 1 = parallel steer.

Are the OutSimPack.h comments for Pitch and Roll correct?
Answer - Yes. LFS axis convention is X = right, Y = forward.

My suggestions for additions:
- Power at current engine speed.
- Torque at current engine speed/throttle.
- Tyre contact patch velocities.
Here's an example plot produced using McLaren ATLAS Express and a CSV file generated using the OutSim data:
- Top area shows the sim-reported slip angles.
- Middle area shows steering wheel angle (solid orange) and car yaw angle (dotted orange).
- Bottom area shows slip angles computed using a technique originally developed by Todd Wasson, which is useful for sims that don't directly report slip angles in their telemetry stream. Two values are shown per tyre, one (name suffix CSV) was computed in real time during telemetry capture and the other computed offline during the Atlas session.

Vehicle is the MRT5 driven at the skid pad. It's initially driving a counter-clockwise lap on the 100 meter diameter circle, then it does a fast full left lock turnaround, rejoins the circle and continues on a clockwise lap.

Also attached are annotated copies of the OutSimPack and Car_info.bin documentation showing base addresses for all the data items, which I found very helpful when developing my telemetry capture program.

This is a great piece of work Scawen. Many thanks for releasing it to us.
Attached images
MRT5 Skidpad.PNG
Attached files
OutSimPack Format.txt - 5.3 KB - 217 views
Car_info Bin Format (Annotated).txt - 8.8 KB - 201 views
Thank you for the test results!

Sorry I didn't answer your questions in October. I remember seeing your post and thought I should answer but didn't make a note to remind myself to do so.
No worries Scawen, I was being lazy when I asked them. They were easily answered by paying full attention to the telemetry data and your documentation while I developed my program.
Hey Johnners, can you post a code snippet of your world to vehicle transformation for the linear velocity and acceleration? I've been banging my head over this for way to long, thanks
Of course, happy to help, coded in C++.

X rotation = Pitch
Y rotation = Roll
Z rotation = Yaw

Positive = counter-clockwise, looking inward along the positive axis toward the axis origin.

Vector World2Local(Vector WorldVector, float Pitch, float Roll, float Yaw)
// Function to transform WorldVector to LocalVector using the Euler angles and
// 3D affine transformation. Uses the 3x3 matrix form because only rotation is
// required (no translation).
Vector LocalVector;

// Total rotation matrix row 1 * WorldVector
LocalVector.X = cosf(Roll)*cosf(Yaw)*WorldVector.X \
+ (cosf(Pitch)*sinf(Yaw) + sinf(Pitch)*sinf(Roll)*cosf(Yaw))*WorldVector.Y \
+ (sinf(Pitch)*sinf(Yaw) - cosf(Pitch)*sinf(Roll)*cosf(Yaw))*WorldVector.Z;

// Total rotation matrix row 2 * WorldVector
LocalVector.Y = -cosf(Roll)*sinf(Yaw)*WorldVector.X \
+ (cosf(Pitch)*cosf(Yaw) - sinf(Pitch)*sinf(Roll)*sinf(Yaw))*WorldVector.Y \
+ (sinf(Pitch)*cosf(Yaw) + cosf(Pitch)*sinf(Roll)*sinf(Yaw))*WorldVector.Z;

// Total rotation matrix row 3 * WorldVector
LocalVector.Z = sinf(Roll)*WorldVector.X \
- sinf(Pitch)*cosf(Roll)*WorldVector.Y \
+ cosf(Pitch)*cosf(Roll)*WorldVector.Z;

return LocalVector;

And two examples of calling the function:

// Transform linear velocity and acceleration vectors from world coordinate
// system to vehicle coordinate system.

LocalVel = World2Local(packet.OSMain.Vel, \
packet.OSMain.Pitch, packet.OSMain.Roll, packet.OSMain.Heading);

LocalAccel = World2Local(packet.OSMain.Accel, \
packet.OSMain.Pitch, packet.OSMain.Roll, packet.OSMain.Heading);

thank you so much this works exactly as I wanted.

in case anyone wants a shortcut here is a python implementation

def world_to_local(
world_vector: np.ndarray, pitch: float, roll: float, yaw: float
) -> np.ndarray:
Function to transform world_vector to local_vector using the Euler angles
and 3D affine transformation. Uses the 3x3 matrix form because only rotation is


world_vector (np.ndarray): The world vector to be transformed
pitch (float): The pitch of the car
roll (float): The roll of the car
yaw (float): The yaw of the car (don't forget outsim provides the heading
pointing to the right, not straight ahead)

np.ndarray: The local transformed vector

sin_roll, cos_roll = np.sin(roll), np.cos(roll)
sin_pitch, cos_pitch = np.sin(pitch), np.cos(pitch)
sin_yaw, cos_yaw = np.sin(yaw), np.cos(yaw)

local_vector = np.empty(3)

# Total rotation matrix row 1 * world_vector
local_vector[0] = (
cos_roll * cos_yaw * world_vector[0]
+ (cos_pitch * sin_yaw + sin_pitch * sin_roll * cos_yaw) * world_vector[1]
+ (sin_pitch * sin_yaw - cos_pitch * sin_roll * cos_yaw) * world_vector[2]

# Total rotation matrix row 2 * world_vector
local_vector[1] = (
-cos_roll * sin_yaw * world_vector[0]
+ (cos_pitch * cos_yaw - sin_pitch * sin_roll * sin_yaw) * world_vector[1]
+ (sin_pitch * cos_yaw + cos_pitch * sin_roll * sin_yaw) * world_vector[2]

# Total rotation matrix row 3 * world_vector
local_vector[2] = (
sin_roll * world_vector[0]
- sin_pitch * cos_roll * world_vector[1]
+ cos_pitch * cos_roll * world_vector[2]

return local_vector

Quote from papalotis :thank you so much this works exactly as I wanted.


The potential trap is the axis system convention. LFS convention is different to that used in the Wikipedia article, so it is essential to re-order the Euler angles accordingly when implementing that formula. I botched it on my first attempt! Big grin
Another screenshot showing more of the tyre telemetry.

Side by slide plots from two laps through the final few corners of Fern Bay Club in the MRT5.

In lap 1 on the left, I took too much kerb through one corner and had a series of three massive oversteer events.

In lap 2 on the right, I got through without drama.

From top to bottom, the sub-plots are:
- Slip angles plus steering wheel angle (dotted orange).
- Slip fraction (narrow plot).
- Touching (narrow plot).
- Lateral forces.
- Vertical loads.
Attached images
MRT5 - Fern Bay Club - Oversteer v Normal.png
Here's the C++ source code for my telemetry program, for any C/C++ developers that would like to experiment with using it and perhaps as a starting point or a source of ideas for their own projects.

I developed this on Windows 10 Home 64-bit using Visual Studio Community 2015. It is intended to be compiled as a console program. When run from a command prompt it will listen for an active LFS session and UDP stream. It will then generate a CSV file rendering of the telemetry stream for the duration of the session. Fair warning - the CSV files can grow very large.

The CSV file format used is generic and designed to be used with multiple current generation sims, including LFS. (Yes, I regard LFS as a current-generation sim, in terms of the quality of its physics implementation.) The generic file format currently provides for a total of 176 channels, but note that any one sim (including LFS) populates only a subset of the available channels, i.e. no single sim provides everything.

This tool is part of a larger project directed at physics benchmarking of multiple sims, my primary telemetry focus. This is in contrast to most telemetry specialists, who direct their work primarily at driver performance analysis and setup development.

See the source code comments for more details about the utility and the telemetry file naming convention used. The first two rows of the CSV file are headers which define the channel names (row 1) and the units of measure (row 2); these are also reflected in the source code comments. The header rows are compatible with McLaren Atlas Express, my preferred telemetry analysis tool.

In addition to the CSV output file, the utility generates a binary (.bin) file containing a verbatim rendering of the UDP packets; this is very useful when studying the UDP packets in detail and I used it heavily while developing the utility. See also my earlier annotated OutSim Format document, which is helpful when inspecting the content using a hex editor, for example.

As currently implemented, the code that generates the computed slip angle channels (83-88) contains various hard-coded parameters reflecting an MRT5 running the default setup. These will need to be adjusted for other cars and setups. Yes, messy I know, but this is essentially a proof of concept at this stage. The computations are based on a technique originally developed by Todd Wasson, who used to be a very active forum contributor both here and in iRacing. I can give more detail on how the computation works if anybody is interested, but it's not actually needed for studying LFS telemetry because Scawen has so kindly chosen to make slip angles directly accessible to us! I use it in sims that do not directly report slip angles in order to generate useful estimates.

Channel 52 (steering wheel angle) also contains a hard-coding (steering ratio). There might be one or two others I have forgotten, but hopefully they will be fairly obvious in the source code.

The target sims for my larger project are iRacing (using Atlas with native iRacing binary telemetry (IBT) files), LFS, rFactor2, AMS1 and RRE. I may extend the list over time, with Assetto Corsa and ACC being the most likely additions.
Attached files - 8.1 KB - 308 views
how do we work with that? Smile
I have never worked on this at LFS and would like to do it Smile
Quote from joaopaulopt :how do we work with that? Smile
I have never worked on this at LFS and would like to do it Smile

isso e coisa de programadores joao
From Johnners's OutSimPack format.txt file, I deduce that OSWheels[0] = Left rear, OSWheels[1] = Right rear, OSWheels[2] = Left Front etc.
Is it correct ?
(sorry if I missed the information elsewhere ...)
Yes, that's correct.

For the OSWheels[4] array of OutSimWheel structs, the indexing is 0 = LR, 1 = RR, 2 = LF, 3 = RF.
Thanks Johnners !
Quote from juliao :isso e coisa de programadores joao

Não, é telemetry iria ajudar-nos imenso com setups, e há provas que iriam dar uma enorme ajuda principalmente Rallys e rallycross que iria ajudar-nos imenso melhorar desempenho do nosso setup.
Eu cheguei usar um em outro jogo que ajudou imenso.

Live telemetry data in test patch U9
(19 posts, started )