DIY: Build your own rev lights for racing games with a Raspberry Pi Zero

Björn Kaiser
Couch Racer
Published in
9 min readJan 23, 2019

A little fun DIY project I did recently that uses car telemetry data from racing games (such as F1 2018, Assetto Corsa, Project Cars 2 etc.) to build rev lights using a Raspberry Pi Zero W with RGB LEDs (video at the end). Complete build time is around 20–30 minutes + a few lines of Python code. No soldering required!

The final product in action

During a visit to the Ferrari Museums in Maranello and Modena I tried the F1 simulators they have on site and boy was that an experience. You’re basically sitting in a stripped down F1 chassis with pedals, a full F1 steering wheel, it even had a Halo; the whole shebang. The chassis isn’t just a fancy seat though, it rests on a motion platform that turns the chassis left and right, shakes it, tightens the seat belt when you brake and so on.

I decided to go buy a Logitech G920 as it seemed like a good beginners wheel and was on offer on Amazon anyways. The slight downside of the G920: unlike other Logitech racing wheels, it does not come with Rev Lights. While they are definitely not required to play any (sim-)racing game, they do add to the overall experience.

This got me thinking: how does the motion platform know what to do and how do I get my hands on the same data to build a Rev Light add-on for my wheel?

The F1 Simulator at the Ferrari Museum in Modena

How do I get my hands on this telemetry data?

After searching online for a bit to learn how these motion platforms work, I found out that the games I currently play, Formula 1 2018, Assetto Corsa and Project Cars 2 all have a feature that can send the telemetry data (and more) from the game through your local network to any device that wants it. That’s the data part sorted, sound!

The specifications of the data for all three games are publicly available and all of them send the data over the network using UDP as the protocol.

Getting the required parts

My main priorities were that the hardware needs to be cheap, easy to use, small and have WiFi for better portability. I found a shop online that sells a Raspberry Pi Zero W that has GPIO pins already soldered on and since they also had a zero-soldering-required RGB LED element that you can simply slide onto the Pi’s GPIO pins it was a perfect fit since it ticked all of the boxes.

All in all the parts cost me somewhere around 50 Euros (incl. shipping). I didn’t have a spare SD card and no power supply for the Pi at home so that added a few quid to the overall cost. If you already have everything except the RGB LED element the parts will come in at a cheap 9 Euros + shipping.

I bought all my parts from thepihut.com to save on shipping and get all of it at the same time. There might be cheaper options out there to get those parts from.

Step 1: Setting up the hardware

The first step is actually the one I messed up a bit, I didn’t check what sort of HDMI port the Pi Zero has and ended up with a regular HDMI cable which does not fit in the mini HDMI port of the Pi. Since the SD card I bought had N00Bs pre-installed and not the OS directly I now had no way to setup the Pi without buying more hardware, something I wanted to avoid.

Flash an Operating System onto the SD card

A few minutes of searching online later I found this amazing guide by Mahesh Senniappan that explains the few simple steps of flashing an OS onto the SD card from another computer and how to setup the WiFi connection. I didn’t try method #1 from the guide since #2 seemed simpler to me and perfectly served my purpose.

I went for Raspbian Stretch Lite as the Operating System since we won’t need any GUI. You can download the latest release on the official website of Raspberry https://www.raspberrypi.org/downloads/raspbian/.

Once you have that setup, put the SD card into the card slot of the Raspberry Pi.

Install the LED Shim

Now, before turning it on, also install the LED Shim by simply sliding it onto the pins of your Pi, all the way to the bottom.

The hardware is now ready to go. Plug in the power supply and it will automatically start to boot (indicated by the green, blinking LED). Give it a few seconds to fully boot and then connect to it via SSH.

Getting the Pi’s IP address

Since we didn’t use a display to set the Pi up we now have no idea what it’s IP address is, the best way to get the address should be to check the list of connected devices in your router. How exactly that is done depends on your router. If your router does not have such a feature you will need to get your hands on a display though.

Step 2: Installing the LED Shim Python Library

We will be doing our coding in Python so it comes in fairly handy that the makers of the LED Shim provide a ready-to-go library for Python that gives us easy access to the LEDs. It also comes with some example files that you can use to test the LEDs.

[Picture/Video of a test file running]

If you want to use their installation script, you can run the following command after SSH’ing into your Pi and it will install everything you need:

curl https://get.pimoroni.com/ledshim | bash

If you prefer to install everything yourself you can follow the instructions for the manual installation from the readme file of the LED Shim Python Library.

Step 3: Writing the code for F1 2018

Disclaimer: I am new to writing Python and only pieced together bits I found online for this one. For v1 of my device “it works” was the only real requirement and I haven’t focused much on any sort of code optimisation.

The Data Structures

Each UDP packet that F1 2018 is sending to our Pi has a set format, all the packets will consist of a header field + the fields of the specific type of information that is being sent (telemetry, lap times etc.). We only care about the car telemetry data but feel free to add support for any other sort of data that the game provides.

For our purpose we only need the value of the revLightsPercent field from the Car Telemetry Packet which we will use to calculate which LEDs we need to turn on. The below class is what we will use to decode the packet we will receive from the game and it will automatically set the values for each field to the correct value.

Since I am new to Python I adapted the work GuyAllard did for the 2017 version to build the data structure for the Car Telemetry Packet of F1 2018.

Turning the LEDs on and off

Now that we have the data structure ready, let’s build a little helper class that will turn the LEDs on and off based on the data we receive from the game.

The class has 4 functions, setLights which is the function we will be calling at the top-level, it has only one parameter, the revLightsPercent we receive.

It then calls the three other methods, getColorForPixel which helps us determine which color a specific LED needs to be set to (green, red or blue) and then the methods to either turn an LED on or off, creatively named turnPixelOn and turnPixelOff.

We will also add some caching into the mix to avoid having to set an LED to the same color if it is already on/off. This will be stored in pixelState.

Connecting all the code

We will need an entry point for our code, something that listens for data from the game and then passes it on to our RevLightController class. The code is fairly straightforward, we first create a socket using UDP which is the type of data we will receive and start listening for data using socket.bind.

The rest is simply an infinite loop that reads incoming data from the socket, parses it into our CarTelemetryPacket data structure and if the received packet is indeed a telemetry packet it passes the revLightsPercent value on to our helper class to do all the dirty work of setting the LEDs to their proper state.

The client that listens for incoming UDP packets from the game

Step 4: Time for action!

Now that all the code is written, let’s fire up our Python script and test it. Fire up the F1 game on your console/PC (I only tested this on the Xbox One) and start a Time Trial session with any car you want.

Setting up F1 2018 to send the data to our Pi

Once the session started, go into Settings > Telemetry Settings, set UDP Telemetry to On, Broadcast Mode to Off and enter the IP address of your Pi into the IP Address field. We will also set the Send Rate to 10Hz.

You can play around with the send rate a bit but I found that 10Hz worked best for me. Essentially this settings influences how often the game will send the data to the connected device.

Lastly, make sure that the Format is set to 2018.

Launching our UDP client on the Pi

While being connected to your Pi via SSH, switch to the folder in which you stored the server.py script and run it:

python server.py

If everything worked according to plan, you should see the following output in the terminal:

starting up on <IP Address Of Your Pi> port 20777
Waiting for data...

Our Rev Lights are now ready to receive data, so go start a flying lap in F1 and the LEDs should light up accordingly as you accelerate and turn back off when you shift up a gear or stop the car entirely.

For testing you can also simply stop on track, put the car into Neutral and accelerate gently and then heavier to see the transition from low RPM (green) to higher RPM (red) all the way to “shift up” (blue).

Where to go from here?

My plan is to build this into a little recording device that stores the telemetry information it receives from the game(s) so I can later analyze it (more on that comes in another post). As mentioned earlier, all games send way more information than just car telemetry, get creative!

Adding support for more games

As part of this post we only touched on F1 2018, I will be adding support for more games eventually. So far I have Assetto Corsa and Project Cars 2 support planned.

Putting the Rev Lights into a nice case and mount it on a wheel

I’m still looking for a good case to make this look a bit nicer, it is probably going to be the Adafruit RPi Zero case since it has a cut out for the GPIO pins.

Display other events (Safety Car, Flags etc.)

At least F1 2018 does send information about zones that are under yellow flags etc., if we reduce the number of LEDs used for the Rev Lights we can easily use some LEDs to flash in the color of the corresponding flag or even the DRS status.

--

--