CAN BUS Gaming Simulator

Controlling a VW CAN BUS dashboard of a Polo 6R with an Arduino and a CAN BUS shield using the Telemetry API of Euro Truck Simulator 2

Similar projects worth following
Ever wanted to play a car/truck simulator with a real dashboard on your PC? Me too! I'm trying to control a VW Polo 6R dashboard via CAN Bus with an Arduino Uno and a Seeed CAN Bus Shield. Inspired by Silas Parker.

[!!!] PLEASE NOTE [!!!]
This project only works with an instrument cluster of a Volkswagen Polo 6R.
I can't give you any help when you try out this project with other instruments from different manufacturers, as every company has their own CAN BUS protocol.

I use this dashboard in combination with a Logitech G27 wheel and coded a program for it. Just come round to my other Hackaday Project:

Click on one of the following Links to navigate through the project page:

All Project LogsAll CAN Codes
Project Page @ Seeed Studios
Silas Parker's Blog
YouTube ChannelYouTube Playlist
Download CenterSources
Supporters and Sponsors

See the project in action:

German demonstration:

VW Speedometer

Source of the circuit board used to connect the instrument cluster to the arduino

Zip Archive - 676.76 kB - 12/19/2017 at 09:13



Newest version of test sketch. For Arduino with Seeed CAN BUS Shield and installed libraries.

ino - 12.51 kB - 12/30/2016 at 15:31



The software used in my latest videos. It simulates an RNS310 from VW and plays online radio stations over the Internet (m3u-Streams and RTMP://) and also plays Windows Media Playlists (WPL file format). You can also visit some webpages (like maps for games) with it. Have fun. This file is a WinRAR-self-extracting archive. Just double-click it and install it. For support, or feedback please PM me.

x-msdownload - 16.04 MB - 04/06/2016 at 21:50


3D-Print Radio-Case.stl

3D-Print Radio-Case (STL 3d-printable Sketch)

- 30.43 MB - 12/24/2015 at 14:30


3D-Print Radio-Case.123dx

3D-Print Radio-Case (Autodesk 123D Design Project File)

- 4.68 MB - 12/24/2015 at 14:30


View all 8 files

View all 7 components

  • Reverse Engineering the Steering Column Switch

    Leon Bataille10/22/2019 at 06:19 1 comment

    As mentioned before in my last project log, I used the long silence to dive deeper in the electronics of the Polo 6R.
    In this project log I want to share some details regarding the Steering Column Switch (or in German “Lenkstockschalter”).
    Its Task is to measure the rotation position of the steering wheel and it provides the switches for wipers, turning signal and light options.
    A while ago I bought an old steering column switch from eBay as well as the case for it. I also bought a key switch for usage as a ignition lock.
    Here’re some photos:

    What I wanted to build was an USB interface which connects to the PC running the simulation game. That way you could control the corresponding functions with the simulation game.
    I used an Arduino micro which can use USB HID profiles, so that it will be recognized as a keyboard by my PC.
    Now my task was to find out the pin assignments for the column switch, which you can find below.

    If you want to build this part of the project as well, here’s the Arduino sketch and the wiring diagram for it.

    VW Polo 6R - Lenkstockschalter - Controller Software
    by Leon Bataille
    Version 1.0
    Last modified: 04.07.2017
    Pin assignments:
    A0: HW  (FSW Wischwasser)
    A1: 53c (HSW)
    A2: (R) (MFA OK/Reset)
    A3: I   (SW Intervallschaltung)
    A4: 1   (SW Wischer-Stufe 1)
    A5: 2   (SW Wischer-Stufe 2)
    D2: SDA - I2C Arduino Communication
    D3: SCL - I2C Arduino Communication
    D4: L   (Blinker links <-)
    D5: R   (Blinker rechts ->)
    D6: 30  (Klemme 30: Lichthupe)
    D7: 56  (Klemme 56: Fernlicht)
    D8: 7   (GRA Reset/+)
    D9: 8   (GRA Set/-)
    D10: 3  (GRA an)
    D12: auf (Trip/MFA+ auf)
    D13: ab  (Trip/MFA+ ab)
    More information on my hackaday project site:
    #include <Wire.h>
    #include <Keyboard.h>
    //Pin Definitions
    int SW_WW = A0;
    int HSW = A1;
    int MFA_OK = A2;
    int SW_INT = A3;
    int SW_lv1 = A4;
    int SW_lv2 = A5;
    int tisch_hoch = 0;
    int tisch_runter = 1;
    int blnk_l = 4;
    int blnk_r = 5;
    int licht_hupe = 6;
    int licht_fern = 7;
    int GRA_plus = 8;
    int GRA_minus = 9;
    int GRA_an = 10;
    int MFA_auf = 11;
    int MFA_ab = 12;
    bool state_GRA = 0;
    bool lastState_SW_WW = 0;
    bool lastState_HSW = 0;
    bool lastState_MFA_OK = 0;
    bool lastState_SW_INT = 0;
    bool lastState_SW_lv1 = 0;
    bool lastState_SW_lv2 = 0;
    bool lastState_blnk_l = 0;
    bool lastState_blnk_r = 0;
    bool lastState_licht_hupe = 0;
    bool lastState_licht_fern = 0;
    bool lastState_GRA_plus = 0;
    bool lastState_GRA_minus = 0;
    bool lastState_GRA_an = 0;
    bool lastState_MFA_auf = 0;
    bool lastState_MFA_ab = 0;
    void setup() {
      // put your setup code here, to run once:
      //-> Alle Eingänge sind mit Pull-Up-Widerständen verbunden
      pinMode(SW_WW, INPUT);
      pinMode(HSW, INPUT);
      pinMode(MFA_OK, INPUT);
      pinMode(SW_INT, INPUT);
      pinMode(SW_lv1, INPUT);
      pinMode(SW_lv2, INPUT);
      pinMode(blnk_l, INPUT);
      pinMode(blnk_r, INPUT);
      pinMode(licht_hupe, INPUT);
      pinMode(licht_fern, INPUT);
      pinMode(GRA_plus, INPUT);
      pinMode(GRA_minus, INPUT);
      pinMode(GRA_an, INPUT);
      pinMode(MFA_auf, INPUT);
      pinMode(MFA_ab, INPUT);
      pinMode(tisch_hoch, OUTPUT);
      pinMode(tisch_runter, OUTPUT);
    void loop() {
      // put your main code here, to run repeatedly:
      if (digitalRead(MFA_OK) == LOW && lastState_MFA_OK == 0) //If the switch is pressed
          lastState_MFA_OK = 1;
      else if (digitalRead(MFA_OK) == HIGH && lastState_MFA_OK == 1) //If the switch is released
          lastState_MFA_OK = 0;
      if (digitalRead(SW_lv1) == LOW && lastState_SW_lv1 == 0) //If the switch is pressed
          lastState_SW_lv1 = 1;
      else if (digitalRead(SW_lv1) == HIGH && lastState_SW_lv1 == 1) //If the switch is released
          lastState_SW_lv1 = 0;
      if (digitalRead(blnk_l) == LOW && lastState_blnk_l == 0) //If the switch is pressed
          lastState_blnk_l = 1;
      else if (digitalRead(blnk_l) == HIGH &&...
    Read more »

  • Back again...

    Leon Bataille10/20/2019 at 12:43 4 comments

    Hi there,

    here're some updates regarding the project after long two years of silence and some explanation.

    So, why isn't there an up-to-date source code available?

    As the project has grown over time, I got some help of very capable people and was able to develop the source code further with them. We squished most of the known bugs like the wrong blinking turning signal or randomly flashing oil indicators and added many new indicators and functions to the project. But the problem is that the source code of the project is open source on this page (which is good of course) but unfortunately I am not allowed anymore to release the source code in its current state due to copyright problems.

    I reverse engineered the dashboard first by myself which is completely fine.

    But later on I got information from other people and specifically these information mustn't be published here.

    So what's the solution to this problem?

    Yeah, that's the point at the moment. I don't know...

    What else did you do in the meantime?

    I changed some essential parts of the project to not only work with the ETS2 game but also with many other simulator and racing games by using another component between my adapter board and the PC.
    I'm using a RevBurner Pro from SymProjects (no sponsoring here). Their software collects through game plugins or APIs the telemetry data from the games and transfers them to the RevBurner. More about this in a future update.

    And now...?

    I will release further project updates regarding the general state of the project, some wiring diagrams, as well as the new parts I'm using for this. But as mentioned before I cannot post any more source code for this project.

    Thanks for your understanding.

  • Circuit Board Source online

    Leon Bataille12/19/2017 at 09:16 0 comments


    I just uploaded the source files for the circuit board which connects the instrument cluster with the CAN-BUS Shield. You can find it in the Download section of this project.

    I hope this clears the questions about connection problems in the comments.

    I wish you all merry christmas and nice holidays!

  • New Version of VWRadio available (v1.2.1)

    Leon Bataille06/12/2017 at 14:55 0 comments

    I've just released a newer version for the VWRadio software.

    I fixed several small bugs. Especially the loop after the first launch without a prior configuration file has been fixed.

    There's now the option to enable a graphic visualization for music playback in the lower left corner.

    You can now also shut down your computer within the program. Therefore you have to go to the settings menu and click on exit. There you're can choose either to exit the program or to completely shut down your PC. I'll show you this feature in a future video. But at the moment it's a surprise for what I implemented it in the software.

  • Building a dashboard desk

    Leon Bataille06/09/2017 at 17:12 1 comment

    Hi there.

    It's been a long time since the last update.
    I'm back with some great news and some exciting plans.

    At the moment I'm building a new desk out of an Polo 6R dashboard. All buttons of the dashboard shall be used as controller in ETS2 and other simulation games.

    Even the Navigation System will display the map of the game (at least that's my goal).

    So here're some pictures of my new sub-project:

  • Creating an automatic Install and Setup Tool

    Leon Bataille05/08/2017 at 11:39 0 comments

    I'm in the process of building an Installation and Setup Tool for those of you, who wanted a detailed instruction on how to set everything up. This software does the job for you!

    I hope to complete this Setup Tool as fast as I can.

    Here's already a screenshot (You can manually choose the packages which you want to install)

  • New Demo-Sketch for Dashboard

    Leon Bataille12/30/2016 at 15:32 3 comments


    Just as promised a few days ago: Here's the new version of the test sketch.

    It contains more CAN BUS functions (such as much more LEDs to switch on or off) and is completely rewritten for a better structure and easier usage.

    These are the LEDs you can manually turn on or off in the sketch

    There's also a new section where you can setup a userdefined setup for testing your dashboard's functions!

    You find the new sketch in the download section of this project,

    or directly here.

    Best regards, and a happy new year!

  • More dashboard functions found

    Leon Bataille12/27/2016 at 21:20 2 comments

    Happy Holidays to all of you!

    The last few days I worked pretty hard on finding new functions of some CAN Commands for the dashboard!

    New functions I found:

    • Battery low warning
    • Fog Light
    • High Beam
    • ABS signal
    • Seat Belt warning
    • Hand brake
    • Low tire pressure warning
    • Offroad mode
    • Diesel particle filter
    • Diesel preheater
    • Water temperature alarm

    I also rewrote the hole demo script with more explanations and comments. The speed needle should also be more accurate (but sadly still not perfect yet)

    I will release the new demo source code in the next few days, so stay tuned.

    And I wish all of you a happy new year!

  • It's been a while

    Leon Bataille07/27/2016 at 11:36 5 comments

    After moving to antother city and my exams there's now time again for hackin'!

    So expect frequent updates from now on.

    I've bought a real dashboard from a VW Polo 6R and I want to build something like a desk out of it. So you can play great racing games and work on it.

    I'm really excited about the next months and hope to get everything working :D

  • Dashboard Photoshoot

    Leon Bataille04/18/2016 at 11:45 0 comments

    Hello Tech-Enthusiasts!

    I just updated the thumbnails for this project. Therefore I got help in a photo studio to take some better profile pics. I hope you enjoy them!

View all 50 project logs

  • 1
    Step 1

    Known CAN Codes so far:

    For CAN Codes please visit the Sources-Page.

  • 2
    Step 2

    Instruction Video:

  • 3
    Step 3

    Arduino Source Code:

    //Volkswagen CAN BUS Gaming
    //Test Sketch v3.0
    //(C) by Leon Bataille 2015-2016
    //Hackaday Project Page:
    //Sketch information #DO NOT REMOVE!
    String game = "VW Static v3.0";
    String vendor = "Leon Bataille";
    //END Sketch information
    //For individual setup scroll down to the section MAIN CONFIGURATION
    #include <mcp_can.h>            //CAN Bus Shield Compatibility Library
    #include <SPI.h>                //CAN Bus Shield SPI Pin Library
    #include <Servo.h>              //Library for Controlling Servos
    #include <Wire.h>               //Extension Library for measuring current
    #include <LiquidCrystal_I2C.h>  //Libraries for controlling LC Displays
    #include <LCD.h>                
    #include <LiquidCrystal.h>
    #define lo8(x) ((int)(x)&0xff)
    #define hi8(x) ((int)(x)>>8)
    //Variables (Dashboard LEDs)
    int high_beam = 13;
    int fog_beam = 12;
    int park_brake = 11;
    //Variables (VW Dashboard Adapter)
    int LEFT_INDICATOR  = A0;
    int PARKING_BREAK   = A2;
    int FUEL_WARNING    = A3;
    //Variables (Dashboard Functions)
    int turning_lights = 3;
    boolean turning_lights_blinking = true;
    int turning_lights_counter = 0;
    int temp_turning_lights = 0;
    boolean backlight = false;
    int oilpswitch = 8;
    int pack_counter = 0;
    boolean add_distance = false;
    int drive_mode = 0;
    int distance_multiplier = 2;
    boolean oil_pressure_simulation = true;
    boolean door_open = false;
    boolean clutch_control = false;
    int temp_clutch_control = 0;
    boolean check_lamp = false;
    int temp_check_lamp = 0;
    boolean trunklid_open = false;
    int temp_trunklid_open = 0;
    boolean battery_warning = false;
    int temp_battery_warning = 0;
    boolean keybattery_warning = false;
    int temp_keybattery_warning = 0;
    int lightmode = 0;
    boolean seat_belt = false;
    int temp_seat_belt = 0;
    int engine_control = 0;
    int temp_dpf_warning = 0;
    boolean dpf_warning = false;
    boolean light_fog = false;
    int temp_light_fog = 0;
    boolean light_highbeam = false;
    int temp_light_highbeam = 0;
    boolean signal_abs = false;
    boolean signal_offroad = false;
    boolean signal_handbrake = false;
    boolean signal_lowtirepressure = false;
    boolean signal_dieselpreheat = false;
    boolean signal_watertemp = false;
    int temp_signal_abs = 0;
    int temp_signal_offroad = 0;
    int temp_signal_handbrake = 0;
    int temp_signal_lowtirepressure = 0;
    int temp_signal_dieselpreheat = 0;
    int temp_signal_watertemp = 0;
    //Variables (Speed and RPM)
    int speed = 0;
    byte speedL = 0;
    byte speedH = 0;
    int rpm = 0;
    short tempRPM = 0;
    byte rpmL = 0;
    byte rpmH = 0;
    int distance_adder = 0;
    int distance_counter = 0;
    //Variables LCD
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Addr, En, Rw, Rs, d4, d5, d6, d7, backlightpin, polarity
    //Variables CAN BUS
    /* the cs pin of the version after v1.1 is default to D9
    v0.9b and v1.0 is default D10 */
    const int SPI_CS_PIN = 9;
    MCP_CAN CAN(SPI_CS_PIN);  // Set CS pin
    //Setup Configuration
    void setup()
      //Initialize LCD
      showLCD("VW Dashboard","by Leon Bataille");
      showLCD("VW Dashboard","booting...");
      //Define Dashboard LEDs as Outputs
      pinMode(high_beam, OUTPUT);
      pinMode(fog_beam, OUTPUT); 
      pinMode(park_brake, OUTPUT);
      pinMode(oilpswitch, OUTPUT);
      //Visual Start Sequence on Dashboard
      digitalWrite(high_beam, HIGH);
      digitalWrite(fog_beam, HIGH);
      digitalWrite(park_brake, LOW);
      digitalWrite(PARKING_BREAK, HIGH);
      delay(500);               // wait for a second
      digitalWrite(high_beam, LOW);
      digitalWrite(FUEL_WARNING, HIGH);
      digitalWrite(PARKING_BREAK, LOW);
      digitalWrite(FUEL_WARNING, LOW);
      digitalWrite(LEFT_INDICATOR, HIGH);
      digitalWrite(RIGHT_INDICATOR, HIGH);
      digitalWrite(fog_beam, LOW);
      digitalWrite(LEFT_INDICATOR, LOW);
      digitalWrite(RIGHT_INDICATOR, LOW);
      //Begin with Serial Connection
      //Show Sketch information on LCD
      showLCD(game,"by "+vendor);
      //Begin with CAN Bus Initialization
        if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
            Serial.println("CAN BUS Shield init ok!");
            Serial.println("CAN BUS Shield init fail");
            Serial.println("Init CAN BUS Shield again");
            goto START_INIT;
    //Reload LC Display
    void showLCD(String line1,String line2)
      lcd.setCursor(0, 0);
      lcd.setCursor(0, 1);
    //Send CAN Command (short version)
    void CanSend(short address, byte a, byte b, byte c, byte d, byte e, byte f, byte g, byte h)
      unsigned char DataToSend[8] = {a,b,c,d,e,f,g,h};
      CAN.sendMsgBuf(address, 0, 8, DataToSend);
    //fuel gauge (0-100%)
    void Fuel(int amount)
      pinMode(2, INPUT);
      pinMode(3, INPUT);
      pinMode(4, INPUT);
      pinMode(5, INPUT);
      pinMode(6, INPUT);
      pinMode(7, INPUT);
      if (amount >= 90)
        pinMode(2, OUTPUT);
        digitalWrite(2, LOW);
      if (amount >= 75)
        pinMode(3, OUTPUT);
        digitalWrite(3, LOW);
      if (amount >= 50)
        pinMode(4, OUTPUT);
        digitalWrite(4, LOW);
      if (amount >= 25)
        pinMode(5, OUTPUT);
        digitalWrite(5, LOW);
      if (amount >= 10)
        pinMode(6, OUTPUT);
        digitalWrite(6, LOW);
      if (amount >= 0)
        pinMode(7, OUTPUT);
        digitalWrite(7, LOW);
    void loop()
      //Set constant speed and RPM to show on Dashboard
      speed = 0;                        //Set the speed in km/h
      rpm = 800;                        //Set the rev counter
      Fuel(30);                          //Set the fuel gauge in percent
      //Set Dashboard Functions
      backlight = true;                  //Turn the automatic dashboard backlight on or off
      turning_lights = 0;                //Turning Lights: 0 = none, 1 = left, 2 = right, 3 = both
      turning_lights_blinking = false;   //Choose the mode of the turning lights (blinking or just shining)
      add_distance = false;              //Dashboard counts the kilometers (can't be undone)
      distance_multiplier = 2;           //Sets the refresh rate of the odometer (Standard 2)
      signal_abs = false;                //Shows ABS Signal on dashboard
      signal_offroad = false;            //Simulates Offroad drive mode
      signal_handbrake = false;          //Enables handbrake
      signal_lowtirepressure = false;    //Simulates low tire pressure
      oil_pressure_simulation = true;    //Set this to true if dashboard starts to beep
      door_open = false;                 //Simulate open doors
      clutch_control = false;            //Displays the Message "Kupplung" (German for Clutch) on the dashboard's LCD
      check_lamp = false;                //Show 'Check Lamp' Signal on dashboard. B00010000 = on, B00000 = off
      trunklid_open = false;             //Simulate open trunk lid (Kofferraumklappe). B00100000 = open, B00000 = closed
      battery_warning = false;           //Show Battery Warning.
      keybattery_warning = false;        //Show message 'Key Battery Low' on Display. But just after first start of dashboard.
      light_fog = false;                 //Enable Fog Light
      light_highbeam = false;            //Enable High Beam Light
      seat_belt = false;                 //Switch Seat Betl warning light.
      signal_dieselpreheat = false;      //Simualtes Diesel Preheating
      signal_watertemp = false;          //Simualtes high water temperature
      dpf_warning = false;               //Shows the Diesel particle filter warning signal.
      //Conversion Speed
      speed = speed / 0.0075; //KMH=1.12 MPH=0.62
      //Conversion Low and High Bytes
      speedL = lo8(speed);
      speedH = hi8(speed);
      tempRPM = rpm*4;
      rpmL = lo8(tempRPM);
      rpmH = hi8(tempRPM);
      if (add_distance == true)
        distance_adder = speed * distance_multiplier;
        distance_counter += distance_adder;
        if (distance_counter > distance_adder) { distance_counter = 0; }
      if ( oil_pressure_simulation == true)
      //Set Oil Pressure Switch
        if (rpm > 1500) {
          digitalWrite(oilpswitch, LOW);
        else {
          digitalWrite(oilpswitch, HIGH);
      /*Send CAN BUS Data*/
      CanSend(0x3D0, 0, 0x80, 0, 0, 0, 0, 0, 0);
      //Engine on and ESP enabled
      CanSend(0xDA0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
      //Enable Cruise Control
      //CanSend(0x289, 0x00, B00000001, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
      //Dashboard Functions
      //Turning Light blinking
      if (turning_lights_blinking == true)
        if (turning_lights_counter == 15)
          temp_turning_lights = turning_lights;
          turning_lights_counter = turning_lights_counter + 1;
        if (turning_lights_counter == 30)
          temp_turning_lights = 0;
          turning_lights_counter = 0;
          turning_lights_counter = turning_lights_counter + 1;
        temp_turning_lights = turning_lights;
      //Check main settings
      if (dpf_warning == true) temp_dpf_warning = B00000010;
      else temp_dpf_warning = B00000000;
      //Seat Belt
      if (seat_belt == true) temp_seat_belt = B00000100;
      else temp_seat_belt = B00000000;
      //Battery Warning
      if (battery_warning == true) temp_battery_warning = B10000000;
      else temp_battery_warning = B00000000;
      //Trunk Lid (Kofferraumklappe)
      if (trunklid_open == true) temp_trunklid_open = B00100000;
      else temp_trunklid_open = B00000000;
      //Check Lamp Signal
      if (check_lamp == true) temp_check_lamp = B00010000;
      else temp_check_lamp = B00000000;
      //Clutch Text on LCD
      if (clutch_control == true) temp_clutch_control = B00000001;
      else temp_clutch_control = B00000000;
      //Warning for low key battery
      if (keybattery_warning == true) temp_keybattery_warning = B10000000;
      else temp_keybattery_warning = B00000000;
      //Lightmode Selection (Fog Light and/or High Beam)
      if (light_highbeam == true) temp_light_highbeam = B01000000;
      else temp_light_highbeam = B00000000;
      if (light_fog == true) temp_light_fog = B00100000;
      else temp_light_fog = B00000000;
      lightmode = temp_light_highbeam + temp_light_fog;
      //Engine Options (Water Temperature, Diesel Preheater)
      if (signal_dieselpreheat == true) temp_signal_dieselpreheat = B00000010;
      else temp_signal_dieselpreheat = B00000000;
      if (signal_watertemp == true) temp_signal_watertemp = B00010000;
      else temp_signal_watertemp = B00000000;
      engine_control = temp_signal_dieselpreheat + temp_signal_watertemp;
      //Drivemode Selection (ABS, Offroad, Low Tire Pressure, handbrake)
      if (signal_abs == true) temp_signal_abs = B0001;
      else temp_signal_abs = B0000;
      if (signal_offroad == true) temp_signal_offroad = B0010;
      else temp_signal_offroad = B0000;
      if (signal_handbrake == true) temp_signal_handbrake = B0100;
      else temp_signal_handbrake = B0000;
      if (signal_lowtirepressure == true) temp_signal_lowtirepressure = B1000;
      else temp_signal_lowtirepressure = B0000;
      drive_mode = temp_signal_abs + temp_signal_offroad + temp_signal_handbrake + temp_signal_lowtirepressure;
      //Send CAN data every 200ms
      if (pack_counter == 20)
        //Turning Lights 2
        CanSend(0x470, temp_battery_warning + temp_turning_lights, temp_trunklid_open + door_open, backlight, 0x00, temp_check_lamp + temp_clutch_control, temp_keybattery_warning, 0x00, lightmode);
        //Diesel engine
        CanSend(0x480, 0x00, engine_control, 0x00, 0x00, 0x00, temp_dpf_warning, 0x00, 0x00);
        //CanSend(0x388, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
        //Cruise Control
        //CanSend(0x289, 0x00, B00000101, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
        pack_counter = 0;
      CanSend(0x320, 0x00, (speedL * 100), (speedH * 100), 0x00, 0x00, 0x00, 0x00, 0x00);
      CanSend(0x280, 0x49, 0x0E, rpmL, rpmH, 0x0E, 0x00, 0x1B, 0x0E);
      CanSend(0x5A0, 0xFF, speedL, speedH, drive_mode, 0x00, lo8(distance_counter), hi8(distance_counter), 0xad);
      CanSend(0x1A0, 0x18, speedL, speedH, 0x00, 0xfe, 0xfe, 0x00, 0xff);
      CanSend(0x050, 0x00, 0x80, temp_seat_belt, 0x00, 0x00, 0x00, 0x00, 0x00);
      //Wait a time

View all 3 instructions

Enjoy this project?



Steph Geiselh. wrote 04/28/2017 at 10:00 point

Hey Leon,

I have seen a wiring diagram for the engine temperature and the fuel gauge on a photo.

Can we see this circuit diagram in more details?? Thanks :)

  Are you sure? yes | no

Leon Bataille wrote 07/11/2017 at 18:59 point

Yes of course :) Did you mean the outside temperature insted of the engine temp.?

  Are you sure? yes | no

Tom wrote 04/17/2017 at 09:14 point


I'm trying to bring this project to life on my own, however - it seems like the cluster isn't communicating with Arduino.

Have you removed a 62k resistor from can bus shield?



  Are you sure? yes | no

Leon Bataille wrote 07/11/2017 at 19:01 point

no, i didn't remove any parts from the can bus shield. however it could be that newer versions of the can bus shield are little bit different. especially the CS pin could have changed. I think mine has D9 as CS pin and newer have D10. but I'm not sure at the moment.

  Are you sure? yes | no

Tom wrote 07/12/2017 at 06:46 point

Hi Leon!

Thank you for the reply. Indeed - mine shield has CS pin on D10, but that wasn't the case. It turned out that on my shield CAN high an low pins are swapped (pins itself are fine, but the pins' description on the shield are contrariwise), so I've got it working :)

Unfortunately - I couldn't get the Passat's B6 Instrument to work (speed gauge was jumping for few seconds and after that - it's been turning off), so I've took a instrument cluster out from... Fiat Panda and it's working perfect ;)

Thank you very much for this project :)

Best regs

  Are you sure? yes | no

lego wrote 04/16/2017 at 12:51 point

i've got the tacho, the arduino and the canbus shield, got the code on the arduino but when i go into ets 2 nothing happens. the rpm needle stays at 800 rpm and that's it. 

could it be from the plugin? maybe they changed something in the telemetry. 

Silas's plugin is 3 years old...

  Are you sure? yes | no

Leon Bataille wrote 07/11/2017 at 19:02 point

Oh this would be not godd (*panic). I will double check this and reply when I know more about it. Thanks for the info.

  Are you sure? yes | no

Felix wrote 03/15/2017 at 09:10 point

I've purchased the exact same tacho from a 6R with the same pinout and all. But when I connect it it says no key and beeps then no function with any of the can bus calls. Do you have any suggestions to bypass this or what might be the issue? How do you connect the immobiliser pins or is it not necessary to touch?

  Are you sure? yes | no

Leon Bataille wrote 07/11/2017 at 19:04 point

The tacho should work even when it says "no key". Mine tells me the same. Did you upload my newer script or did you try to send one single command?

  Are you sure? yes | no

alex wrote 08/09/2018 at 22:03 point

hi! I have the same issue at the moment with the “no key found” message. It seems that if I send any CAN message of the steering wheel buttons to go to the next MFD display, nothing bypasses the “no key found” message. 

Do you have any suggestion for this? 


  Are you sure? yes | no

animireddysaip wrote 01/26/2017 at 11:33 point

Hie i am a student trying to build a two way communication (using can bus protocol) between two arduino's which have some sensors and actuators on them, 

can you please help me with the code required for sending and receiving the sensor values on CAN BUS protocol. (atleast where to refer)

  Are you sure? yes | no

Leon Bataille wrote 07/11/2017 at 19:06 point

Hi, sorry for my late replay. But I hope it's not too late ;-). There are very useful examples for the CAN BUS protocol in the Arduino library of the Seeedstudio CAN BUS Shield. Just open Arduino IDE, import the library and click on File>Examples>CAN.

There should be everything you need.

  Are you sure? yes | no

vitecd wrote 01/24/2017 at 09:18 point

wiring diagram has some missing components

  Are you sure? yes | no

Leon Bataille wrote 01/24/2017 at 10:45 point

thanks for the info. yes the diagram is out of date.

I'll make a new one as soon as i can.

  Are you sure? yes | no

bigvicproton wrote 01/08/2017 at 03:35 point

Perhaps I am missing something, but I have the Silas Parker plugin installed and telemetry is working.  Compiled on the Arduino and running RMP goes to 800, so I know the CanBus Shield is talking to the cluster.  Yet when playing ETS2 it is not talking to the cluster.  What am I doing wrong?

  Are you sure? yes | no

Leon Bataille wrote 01/24/2017 at 09:44 point

Hi, did you check the config file inside the plugin folder of ETS2? (i.e. C:\Program Files\Euro Truck Simualtor 2\bin\win_x86\plugins\dash_plugin.txt)

You have to configure the COM Port of your Arduino inside this file.

Best regards,


  Are you sure? yes | no

Jeroen van der Velden wrote 01/05/2017 at 14:18 point

Hi Leon, I lost my board schematic you send me along with your Board. Could you please send me a copy? Best Regards, Jeroen

  Are you sure? yes | no

bigvicproton wrote 12/21/2016 at 14:23 point

Hi Leon,  Could you show us the code you used to get the gas gauge working? 

  Are you sure? yes | no

trandi wrote 10/25/2016 at 22:24 point

Hi Leon, I'm trying to replicate your work but using a Skoda Octavia 2002 instrument cluster and a LM3S8962 dev board from Texas Instruments (which has a CAN peripheral included).

I could immediately turn on / off a few lights and the RPM indicator ( ) but now I'm completely stuck with the Speed indicator and/or the other 2 smaller ones (oil temperature and petrol tank).

I've obviously tried you codes for the speed but they don't seem to work... any other idea ?


  Are you sure? yes | no

jsfrederick2011 wrote 06/07/2016 at 11:25 point

hey leon is there a way to PM you?

  Are you sure? yes | no

Leon Bataille wrote 06/07/2016 at 14:26 point

yes of course, just click on my name and write me an PM :)

  Are you sure? yes | no


[this comment has been deleted]

Leon Bataille wrote 05/19/2016 at 04:58 point

Hi Paul,

Yes you can use the Plugin of Silas Parker and the commands I used in combination. 

I also have written the script for this purpose but because of licensing problems I can't publish it. (Silas' Arduino script is published under GNU GPL).

But I try to contact him for a long time in the hope that I can publish my script with his permission.

I'll let you know If I know more

  Are you sure? yes | no

Danel K wrote 05/11/2016 at 05:04 point

I rarely get impressed to a point where i truly say WOW out loud (WOL?) but this project, hoooooly... **** = WOW!!!

  Are you sure? yes | no

Leon Bataille wrote 05/11/2016 at 05:14 point

Thanks Danel!

I should remember WOL, sounds great ;

  Are you sure? yes | no

Einārs Deksnis wrote 04/30/2016 at 13:25 point

Hi Leon!
Thanks for sharing Your work! 
This inspired to  use this VW dashboard in one of my projects. 
Also I managed to get working speed gauge, so thought this can be useful for you too.
Basically, when I got trip distance counter kind of working, speed gauge stopped detecting fault and don't drop to zero anymore. 
Here is my code for reference:

void CAN_Speed_Send(uint16_t speed){
    uint16_t sp = speed / 0.0075;
    uint16_t distance_adder = speed*2;

    counter += distance_adder;
    if( counter > distance_adder ) { counter = 0; } 

    CAN_TX_DATA_BYTE4(CAN_TX_MAILBOX_SPEED) = 0x02 | 0x08;  


After weird operation of arduino with CAN-BUS Shield, which suddenly stopped sending data on MISO line, I switched to PSoC5LP chip. 

  Are you sure? yes | no

Leon Bataille wrote 04/30/2016 at 14:38 point

Wow! Thank you!

I'll try this as fast as I can! It's great to have such a great community here on hackaday.

You helped me and everyone who wants to rebuilt this project a lot.

I'll keep you updated!

  Are you sure? yes | no

Einārs Deksnis wrote 04/30/2016 at 19:54 point

You are welcome!
Be aware that CAN-BUS message interval shall be constant.
I made 10ms timer to do this.

    if(pack_counter == 20){ //Some messages sending 20x times less
        CAN_LIGHT_Send(0, backlight);
        pack_counter = 0;

There is magic constant which is dependent on message interval.

distance_adder = speed*X;  

I got gauge working when X=2 with 10ms interval, but it can be tuned for other intervals.
Unfortunately trip distance counter on dashboard don't count adequate distance (it is slower than necessary).  In my application it doesn't matter, but probably it would be necessary to read messages on polo CAN-BUS to better figure out relation on these parameters.

  Are you sure? yes | no

Dan wrote 11/05/2016 at 08:29 point

Hi Einars,  

Thank you so much for the above tip on how to make the speedometer work !

I've managed to use the above for a VW Passat B6 dashboard, however it *only* works when the speed is around 100km/h. If I try with 50 or 200km/h, your above formula doesn't work anymore...

Any idea ? Have you managed to find the exact formula between the speed the frequency of the updates and that "X" coefficient ?

Also if I read correctly your code:

counter += distance_adder;    

if( counter > distance_adder ) { counter = 0; }

it means that you're literally sending the distance_adder then "0" every other iteration, as that "if" clause will always be true every 2nd time...

Am I missing something ? Could you please clarify ?

Anyhow, any help / hint would be HUGELY appreciated, as I've spend countless number of hours trying to make this work, and it's becoming really frustrating :)  (I also don't have the actual car so that I can sniff the "real" packages :) )


  Are you sure? yes | no

Jeroen van der Velden wrote 03/23/2016 at 13:24 point

Hi Leon, my simulator is ready to get connected t this stage. For testing I`m using laptops and PC`s but every time I use a new system I need to find all the right .h files for Arduino.IDE.

So far only my home PC has everything to compile without errors. Would you be able to post a copy of both your IDE Library`s so its less hard for us to get the "Hardware Test" runining on UNO?

  Are you sure? yes | no

Jeroen van der Velden wrote 03/24/2016 at 17:58 point


This should do it! Libraries.rar

This file is for the VW Polo Board and CAN-BUS Shield. Delete all your Arduino
IDE Library’s from your system and copy past these in both library locations.

  Are you sure? yes | no

Leon Bataille wrote 06/26/2015 at 07:36 point

Hi @monnoliv,

Yeah the Conrod is a project about controlling motor and dash controllers, but my project is about controlling a dash for a computer game. It has another purpose.

But thank you for the info!

  Are you sure? yes | no

papyDoctor wrote 06/25/2015 at 13:52 point


Just for info, there is another project like yours here:


  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates