Arduino uno jeux vidéo

Bonjour, j’ai un projet avec une carte arduino uno et un écrans lcd. Je joue au jeux f1 22 avec un volant et je voulais savoir si c été possible d afficher sur un écrans lcd rgb les tour par minute, vitesse, quel rapport on est etc.. pour ensuite le mettre sur mon volant. J’ai regardé sur internet et je n’ai pas trouvé où ça employait des termes trop compliqués.

:warning:
Post mis dans la mauvaise section, on parle anglais dans les forums généraux. déplacé vers le forum francophone.

Merci de prendre en compte les recommandations listées dans Les bonnes pratiques du Forum Francophone

est-ce que le jeu dispose d'un moyen d'obtenir les données que vous voulez afficher ?

Oui le jeux dispose d’un moyen pour récupérer les donne que je veux afficher

comment ?

soyez pro-actif et donnez toutes les infos car on ne va pas aller à la pêche...

cf les recommandations listées dans "Les bonnes pratiques du Forum Francophone” pour savoir comment poster

Il faut avant ça, faire ton mods pour extraire la télémétrie et l'envoyer sur ton Arduino.
Ce n'est pas forcément quelque chose de trivial et la documentation est souvent pauvre.
Si tu as trouvé les termes trop compliqué, cela signifie qu'il va surement falloir t'armé de persévérance et de motivation.

Quand tu dis mettre sur le volant, je suppose que tu parle du support du volant?
Car on mets rarement l'écran directement sur le volant, car celui-ci tourne.

Bonjour rvsmo

Sous quelle forme, as tu un lien sur un descriptif ?

Cordialement
jpbbricole

Bonjour et merci pour ta réponse. Désolé pour répondre que maintenant, j’étais en cours et je n’avais pas le temps de vous répondre. Justement c’est ça le problème c’est que je ne sais pas comment extraire la télémétrie. Il existe des bande rgb ou des encrans externe au volant qui peut le faire. On peut en trouver sur internet mais le prix dépasse les 100 euros. J’avais pour idée de copier leur façon de prendre ces donnés mais introuvable. Mais je suis déterminé à trouver.
Oui je veux le mettre comme les volant ou il y a cette fonctionnalité.
Désolé ci ce n’est pas très claire c’est compliqué à expliquer et je crois bien impossible mais je vais tout faire pour trouver

Bonjour jppbricole
Justement je ne sais pas. Je sais que on peut car certain volant avec cette « option » il arrive à afficher.

donnez nous des liens vers ces solutions à 100€ qu'on comprenne de quoi il s'agit

Recherches F1 22 arduino
https://www.google.com/search?hl=fr-CH&ie=UTF-8&source=android-browser&q=F1+22+arduino&gws_rd=ssl

De ce que j'ai compris le 2022 et sensiblement similaire au 2020, dans un des liens que donne ta recherche google, disent que le jeux envois la télémétrie en UDP.
Si c'est ça, c'est bien plus simple que de faire un mod :slight_smile: et relativement simple à mettre en place.

Un lien sur le forum de codemaster

Je ne vais pas vous mentir c’est du chinois pour moi. Mais si vous dite que que cela est plutôt simple à mettre en place c’est parfait. Et pour information c’est quoi la télémétrie en UDP ? Désolé je comprend pas tout et je vous aides pas trop. Mais merci.

J’ai vue sur Reddit quelqu’un qui a réussis. Mais c’est sur f1 2020. Mais d’après terwal ça serai pareil pour f1 22. Donc c’est possible, mais il n’a pas partagé ce qu’il a fait.

https://www.reddit.com/r/F1Game/comments/pofpy2/i_made_a_custom_display_for_f12020_using_an/?rdt=47527

C'est un protocole de communication.
L'utilisation qui en est faite, c'est que le jeux envois les informations à tous les machines présents sur le réseau, sans savoir qui écoute.

C'est ce que j'ai cru comprendre en regardant les mods pour le moteur de jeux, mais ça demande vérification et ça expliquerait comment les volants pas dédié au jeux, puissent récupérer l'information.
Si j'ai le temps demain, je ferais un petit wokwi qui écoute en udp et affiche les données qu'il reçoit.
Sauf si @jpbbricole se sans une âme charitable :grin:
Ou un autre évidemment :joy:

:joy::joy: merci beaucoup c vraiment gentil de votre part je vous revaudrais ça. Et remercie pour l’explication c’est plus claire.

la documentation explique comment activer l'envoi de paquets sur UDP

FAQS
How do I enable the UDP Telemetry Output?
In F1 22, UDP telemetry output is controlled via the in-game menus. To enable this, enter the options
menu from the main menu (triangle / Y), then enter the settings menu - the UDP option will be at the
bottom of the list. From there you will be able to enable / disable the UDP output, configure the IP
address and port for the receiving application, toggle broadcast mode and set the send rate. Broadcast
mode transmits the data across the network subnet to allow multiple devices on the same subnet to be
able to receive this information. When using broadcast mode it is not necessary to set a target IP
address, just a target port for applications to listen on.
Advanced PC Users: You can additionally edit the game’s configuration XML file to configure UDP
output. The file is located here (after an initial boot of the game):

...\Documents\My Games\<game_folder>\hardwaresettings\hardware_settings_config.xml

You should see the tag:

<motion>
...
<udp enabled="false" broadcast=”false” ip="127.0.0.1" port="20777" sendRate=”20”
format=”2022” yourTelemetry=”restricted” />
...
</motion>

Here you can set the values manually. Note that any changes made within the game when it is running
will overwrite any changes made manually. Note the enabled flag is now a state

et ils expliquent exactement quelles sont les structures (qui sont quasiment directement compatibles avec le C++, il suffit de modifier quelques types) qui sont émises en UDP

par exemple toutes les communications commencent avec un header qui a cette structure

struct PacketHeader
{
  uint16_t m_packetFormat;
  uint8_t m_gameMajorVersion;
  uint8_t m_gameMinorVersion;
  uint8_t m_packetVersion;
  uint8_t m_packetId;
  uint64_t m_sessionUID;
  float m_sessionTime;
  uint32_t m_frameIdentifier;
  uint8_t m_playerCarIndex;
  uint8_t m_secondaryPlayerCarIndex;
};

qui fait partie d'une structure plus large qui dépend du m_packetId qui définit quel type de données sont en train d'arriver pour décoder les octets qui suivent dans le paquet

peut-être vous pouvez configurer ce qui est émis de façon à ne recevoir que le paquet "Car Telemetry" qui ressemble à cela

struct PacketCarTelemetryData {
  PacketHeader m_header; // Header
  CarTelemetryData m_carTelemetryData[22];
  uint8_t m_mfdPanelIndex; // Index of MFD panel open - 255 = MFD closed
  // Single player, race – 0 = Car setup, 1 = Pits
  // 2 = Damage, 3 = Engine, 4 = Temperatures
  // May vary depending on game modeuint8_t m_mfdPanelIndexSecondaryPlayer; // See above
  int8_t m_suggestedGear; // Suggested gear for the player (1-8)
  // 0 if no gear suggested
};

où le type CarTelemetryData est défini par

struct CarTelemetryData {
  uint16_t m_speed; // Speed of car in kilometres per hour
  float m_throttle; // Amount of throttle applied (0.0 to 1.0)
  float m_steer; // Steering (-1.0 (full lock left) to 1.0 (full lock right))
  float m_brake; // Amount of brake applied (0.0 to 1.0)
  uint8_t m_clutch; // Amount of clutch applied (0 to 100)
  int8_t m_gear; // Gear selected (1-8, N=0, R=-1)
  uint16_t m_engineRPM; // Engine RPM
  uint8_t m_drs; // 0 = off, 1 = on
  uint8_t m_revLightsPercent; // Rev lights indicator (percentage)
  uint16_t m_revLightsBitValue; // Rev lights (bit 0 = leftmost LED, bit 14 = rightmost LED)
  uint16_t m_brakesTemperature[4]; // Brakes temperature (celsius)
  uint8_t m_tyresSurfaceTemperature[4]; // Tyres surface temperature (celsius)
  uint8_t m_tyresInnerTemperature[4]; // Tyres inner temperature (celsius)
  uint16_t m_engineTemperature; // Engine temperature (celsius)
  float m_tyresPressure[4]; // Tyres pressure (PSI)
  uint8_t m_surfaceType[4]; // Driving surface, see appendices
};

donc si vous avez activé la télémétrie en UDP sur le port 20777 par exemple, vous pourriez sans doute recevoir les données sur un ESP32 en WiFi avec le code suivant

#include <WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "NomDuWifi";
const char* password = "MotDePasseWifi";

WiFiUDP udp;
unsigned int localPort = 20777;  // port utilisé pour écouter les paquets UDP

struct PacketHeader
{
  uint16_t m_packetFormat;
  uint8_t m_gameMajorVersion;
  uint8_t m_gameMinorVersion;
  uint8_t m_packetVersion;
  uint8_t m_packetId;
  uint64_t m_sessionUID;
  float m_sessionTime;
  uint32_t m_frameIdentifier;
  uint8_t m_playerCarIndex;
  uint8_t m_secondaryPlayerCarIndex;
};


struct CarTelemetryData {
  uint16_t m_speed; // Speed of car in kilometres per hour
  float m_throttle; // Amount of throttle applied (0.0 to 1.0)
  float m_steer; // Steering (-1.0 (full lock left) to 1.0 (full lock right))
  float m_brake; // Amount of brake applied (0.0 to 1.0)
  uint8_t m_clutch; // Amount of clutch applied (0 to 100)
  int8_t m_gear; // Gear selected (1-8, N=0, R=-1)
  uint16_t m_engineRPM; // Engine RPM
  uint8_t m_drs; // 0 = off, 1 = on
  uint8_t m_revLightsPercent; // Rev lights indicator (percentage)
  uint16_t m_revLightsBitValue; // Rev lights (bit 0 = leftmost LED, bit 14 = rightmost LED)
  uint16_t m_brakesTemperature[4]; // Brakes temperature (celsius)
  uint8_t m_tyresSurfaceTemperature[4]; // Tyres surface temperature (celsius)
  uint8_t m_tyresInnerTemperature[4]; // Tyres inner temperature (celsius)
  uint16_t m_engineTemperature; // Engine temperature (celsius)
  float m_tyresPressure[4]; // Tyres pressure (PSI)
  uint8_t m_surfaceType[4]; // Driving surface, see appendices
};

struct PacketCarTelemetryData
{
  PacketHeader m_header; // Header
  CarTelemetryData m_carTelemetryData[22];
  uint8_t m_mfdPanelIndex; // Index of MFD panel open - 255 = MFD closed
  // Single player, race – 0 = Car setup, 1 = Pits
  // 2 = Damage, 3 = Engine, 4 = Temperatures
  // May vary depending on game modeuint8_t m_mfdPanelIndexSecondaryPlayer; // See above
  int8_t m_suggestedGear; // Suggested gear for the player (1-8)
  // 0 if no gear suggested
};

const char * descriptionDuPacket(const uint8_t packetId) {
  switch (packetId) {
    case 0: return "Motion";
    case 1: return "Session";
    case 2: return "Lap Data";
    case 3: return "Event";
    case 4: return "Participants";
    case 5: return "Car Setups";
    case 6: return "Car Telemetry";
    case 7: return "Car Status";
    case 8: return "Final Classification";
    case 9: return "Lobby Info";
    case 10: return "Car Damage";
    case 11: return "Session History";
    default: return "Inconnu";
  }
}


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("On rejoint le réseau WiFi..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.write('.');
    delay(1000);
  }

  Serial.println("=> OK");
  Serial.println("Attente de paquets UDP.");

  udp.begin(localPort);
}

void loop() {
  size_t packetSize = udp.parsePacket();
  if (packetSize > 0) {
    if (packetSize >= sizeof(PacketHeader)) {
      PacketHeader packetHeader;
      udp.read((uint8_t *)&packetHeader, sizeof(PacketHeader));
      if (packetHeader.m_packetId == 6) { // on a reçu un PacketCarTelemetryData structure
        if (packetSize == sizeof(PacketCarTelemetryData)) { // on confirme quand même que ça correspond
          PacketCarTelemetryData packetData;
          memcpy(&packetData.m_header, &packetHeader, sizeof(PacketHeader)); // on copie le PacketHeader
          udp.read((uint8_t *)&packetData.m_carTelemetryData, sizeof(CarTelemetryData) * 22); // on lit le tableau CarTelemetryData
          udp.read((uint8_t *)&packetData.m_mfdPanelIndex, sizeof(uint8_t)); // on lit mfdPanelIndex
          udp.read((uint8_t *)&packetData.m_suggestedGear, sizeof(int8_t)); // on lit suggestedGear

          Serial.print("Packet Description: ");
          Serial.println(descriptionDuPacket(packetData.m_header.m_packetId));
          Serial.print("Packet Format: ");
          Serial.println(packetData.m_header.m_packetFormat);
          Serial.print("Game Major Version: ");
          Serial.println(packetData.m_header.m_gameMajorVersion);
          Serial.print("Game Minor Version: ");
          Serial.println(packetData.m_header.m_gameMinorVersion);
          Serial.print("Packet Version: ");
          Serial.println(packetData.m_header.m_packetVersion);
          Serial.print("Session UID: ");
          Serial.println(packetData.m_header.m_sessionUID);
          Serial.print("Session Time: ");
          Serial.println(packetData.m_header.m_sessionTime);
          Serial.print("Frame Identifier: ");
          Serial.println(packetData.m_header.m_frameIdentifier);
          Serial.print("Player Car Index: ");
          Serial.println(packetData.m_header.m_playerCarIndex);
          Serial.print("Secondary Player Car Index: ");
          Serial.println(packetData.m_header.m_secondaryPlayerCarIndex);
          Serial.println("---------------");

          // Additional telemetry data for each car
          for (int i = 0; i < 22; ++i) {
            Serial.print("Car ");
            Serial.print(i + 1);
            Serial.println(" Telemetry Data:");
            Serial.print("Speed: ");
            Serial.println(packetData.m_carTelemetryData[i].m_speed);
            Serial.print("Throttle: ");
            Serial.println(packetData.m_carTelemetryData[i].m_throttle);
            Serial.print("Steer: ");
            Serial.println(packetData.m_carTelemetryData[i].m_steer);
            Serial.print("Brake: ");
            Serial.println(packetData.m_carTelemetryData[i].m_brake);
            Serial.print("Clutch: ");
            Serial.println(packetData.m_carTelemetryData[i].m_clutch);
            Serial.print("Gear: ");
            Serial.println(packetData.m_carTelemetryData[i].m_gear);
            Serial.print("Engine RPM: ");
            Serial.println(packetData.m_carTelemetryData[i].m_engineRPM);
            Serial.print("DRS: ");
            Serial.println(packetData.m_carTelemetryData[i].m_drs);
            Serial.print("Rev Lights Percent: ");
            Serial.println(packetData.m_carTelemetryData[i].m_revLightsPercent);
            Serial.print("Rev Lights Bit Value: ");
            Serial.println(packetData.m_carTelemetryData[i].m_revLightsBitValue);
            Serial.print("Brakes Temperature: ");
            for (int j = 0; j < 4; ++j) {
              Serial.print(packetData.m_carTelemetryData[i].m_brakesTemperature[j]);
              Serial.print(" ");
            }
            Serial.println();
            Serial.print("Tyres Surface Temperature: ");
            for (int j = 0; j < 4; ++j) {
              Serial.print(packetData.m_carTelemetryData[i].m_tyresSurfaceTemperature[j]);
              Serial.print(" ");
            }
            Serial.println();
            Serial.print("Tyres Inner Temperature: ");
            for (int j = 0; j < 4; ++j) {
              Serial.print(packetData.m_carTelemetryData[i].m_tyresInnerTemperature[j]);
              Serial.print(" ");
            }
            Serial.println();
            Serial.print("Engine Temperature: ");
            Serial.println(packetData.m_carTelemetryData[i].m_engineTemperature);
            Serial.print("Tyres Pressure: ");
            for (int j = 0; j < 4; ++j) {
              Serial.print(packetData.m_carTelemetryData[i].m_tyresPressure[j]);
              Serial.print(" ");
            }
            Serial.println();
            Serial.print("Surface Type: ");
            for (int j = 0; j < 4; ++j) {
              Serial.print(packetData.m_carTelemetryData[i].m_surfaceType[j]);
              Serial.print(" ");
            }
            Serial.println();

          }

          Serial.print("MFD Panel Index: ");
          Serial.println(packetData.m_mfdPanelIndex);
          Serial.print("Suggested Gear: ");
          Serial.println(packetData.m_suggestedGear);
          Serial.println("---------------");
        } else {
          Serial.println("taille invalide pour un PacketCarTelemetryData.");
        }
      } else {
        Serial.println("Paquet autre que PacketCarTelemetryData. Ignoré");
        while (udp.available()) udp.read();
      }
    } else {
      Serial.println("Taille du paquet incorrecte, ne contient même pas un PacketHeader.");
    }
  }
}

bien sûr ce n'est absolument pas testé mais ça pourrait donner des idées...

Si, il a partagé un lien, il faut juste lire le fil jusqu'au bout.

dans ce code il a un programme qui tourne sur le PC et qui reçoit les données par UDP et qui émet ensuite ces données sur le port série vers l'arduino qui reçoit les données pertinentes sous forme de texte

le PC tournant beaucoup plus vite que l'arduino c'est une approche qui se tient, ça évite d'avoir un pauvre petit arduino qui écoute un paquet que plusieurs centaines d'octets juste pour en extraire que quelques éléments.

Oui et non, sachant que l'Arduino le plus adéquate serait un ESP32, je suppose que même si il est bien moins performant, il sera peut être capable de mapper le buffer en temps réel.

C'est ce type de code que je voulais mettre dans un wokwi.

Oui, mais cela reste surement du charabia pour @rvsmo :laughing: