Skip to content

chrshdl/instrument-cluster

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

An embedded sim racing dash with a real instrument-cluster layout. Built for readability and reliability while racing. Runs on Raspberry Pi with 7" displays and supports Gran Turismo 7 telemetry.

INSTRUMENT CLUSTER IN ACTION

Build Status Download Raspberry Pi 4 64 Image Discord

Join the chat to share ideas and influence what gets built next.

Features

Telemetry & Gauges

  • Tire temperatures
  • Vehicle speed
  • Gear indicator
  • Graphical RPM

Driver Coaching

  • Shift lights (torque-based optimal shift point)
  • Best lap time
  • Previous lap time
  • Predicted lap time
  • Live delta (in real-time)

Delta Time Display

The delta time widget shows the time difference between the current lap and the reference lap in real-time. The implementation follows professional motorsport dashboard patterns (similar to MoTEC, AiM) to ensure the display is informative without being distracting.

Architecture

┌─────────────────┐      ┌─────────────┐      ┌──────────────────┐
│  DeltaSignal    │─────▶│ VehicleBus  │─────▶│ DeltaTimeWidget  │
│  (calculator)   │      │  (signals)  │      │   (display)      │
└─────────────────┘      └─────────────┘      └──────────────────┘
     60 Hz                  raw delta           200ms refresh
   continuous              passthrough          + hysteresis
  • DeltaSignal (delta_signal.py): Calculates the delta time continuously at full telemetry rate (~60 Hz) and publishes delta_diff to the vehicle bus
  • DeltaTimeWidget (delta_time_widget.py): Reads delta_diff from the bus and applies display filtering before rendering

Sample-and-Hold Pattern

Raw delta values update at ~60 Hz, but displaying every update would cause distracting digit flicker. The widget uses sample-and-hold to limit visual updates:

Parameter Value Purpose
_refresh_period 0.2s Display updates at most 5× per second
_force_refresh flag Bypasses rate limiting on lap changes

This ensures the driver can glance at the display and read a stable value without the digits constantly changing.

Hysteresis Filtering

Even with rate limiting, the display can flicker when the delta value oscillates near a digit boundary (e.g., +0.99+1.00). Hysteresis (dead-band filtering) solves this:

Parameter Value Purpose
_hysteresis 0.02s Minimum change required to trigger a display update

The display only updates when:

|new_delta - displayed_delta| ≥ 0.02 seconds (20ms)

This eliminates "digit hunting" where small oscillations cause the least-significant digit to flip back and forth rapidly.

Visual Feedback

  • Color coding: Green (ahead of reference), Red (behind reference)
  • Trend dashes: 1–5 dashes indicating magnitude (0.1s per dash), positioned left (ahead) or right (behind) of the value

Supported Hardware

  • Single-board computers

    • Raspberry Pi 4 Model B (1GB RAM, built-in Wi-Fi)
  • Displays

    • Raspberry Pi Touch Display 2, 24-bit RGB, 720×1280, five-finger touch
  • Peripherals

    • Pimoroni Blinkt! 8-LED bar
  • Input

    • Touch control (UI buttons)
    • On-screen soft keys for display brightness (+ / −)

Standalone

If you prefer the turnkey experience of a standalone system (fast boot straight into the dash), download the prebuilt Raspberry Pi image and follow the installation instructions in the Wiki.

Download Raspberry Pi 4 64 Image

Development Setup

The codebase uses uv for managing the dependencies and the virtual environment. Follow the installation guide for uv.

Install dependencies

After installing uv on your system switch to the repo root and execute

uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv sync

python -m instrument_cluster

How to debug in VS Code

Specify the debugger configuration by creating a launch.json file in the "Run and Debug" view. Then paste the following and save.

{
    "version": "0.2.0",
    "configurations": [{
        "name": "Python Debugger: Current File",
        "type": "debugpy",
        "request": "launch",
        "module": "instrument_cluster.main",
        "cwd": "${workspaceFolder}",
        "env": {
            "PYTHONPATH": "${workspaceFolder}/src"
        },
        "console": "integratedTerminal"
    }]
}

Now you are ready to start debugging by hitting F5 or by pressing the green arrow.

Legal Disclaimer

This project is created for educational and personal use and provided without warranty of any kind, express or implied. Use at your own risk.

All trademarks, logos, and brand names are the property of their respective owners.

Gran Turismo, Gran Turismo 7, GT7 and PlayStation are trademarks or registered trademarks of Sony Interactive Entertainment Inc. and Polyphony Digital Inc.

License

All of my code is MIT licensed. Libraries follow their respective licenses.