[PYTHON] Ich habe versucht, die Laufdaten des Rennspiels (Assetto Corsa) mit Plotly zu visualisieren

Einführung

Ich liebte Rennspiele und spielte Gran Turismo 5/6, aber nachdem ich zu Assetto Corsa gewechselt war, stellte ich fest, dass ich nicht sehr gut lief. Insbesondere besteht die Situation darin, dass das KI-Fahrzeug (Stärke = 100%) durch fast 4 Sekunden pro Runde voneinander getrennt ist (bei Verwendung der Catalunya-Rennstrecke / TOYOTA GT86, Gamepad). In GT6 habe ich alles Gold mit Assist AUS außer ABS = 1 / TCS = 1 bekommen, also dachte ich, ich wäre nicht so schlecht ...

Um zu analysieren, warum es einen solchen Unterschied gibt, habe ich auch das Visualisierungstool studiert, die laufenden Daten meines Spiels und des KI-Spiels mit Python erfasst und mit Plotly visualisiert.

Übrigens gibt es ein Tool namens Motec i2 Pro zur Datenerfassung und -visualisierung. Dieses Mal untersuche ich auch Visualisierungstools, sodass ich Motec nicht verwenden werde.

Datenerfassung

Assetto Corsa verfügt über einen Mechanismus namens "In-Game-App", mit dem Benutzer unabhängig voneinander Anwendungen entwickeln können, die Fahrdaten in Python-Sprache auf dem Spielbildschirm anzeigen. APIs zur Erfassung von Fahrdaten und APIs zur Anzeige auf dem Bildschirm werden vorbereitet.

Basierend auf diesen Referenzinformationen habe ich ein Programm erstellt, um die folgenden Informationen zu erhalten.

ACTelemetry.py

ACTelemetry.py



class ACTelemetry:

(Abkürzung)

    def logging(self):
        if self.outputFile == None:
            return
        
        lapCount = ac.getCarState(self.carId, acsys.CS.LapCount) + 1
        lapTime = ac.getCarState( self.carId, acsys.CS.LapTime)
        speed = ac.getCarState(self.carId, acsys.CS.SpeedKMH)
        throttle = ac.getCarState(self.carId, acsys.CS.Gas)
        brake = ac.getCarState(self.carId, acsys.CS.Brake)
        gear = ac.getCarState(self.carId, acsys.CS.Gear)
        rpm = ac.getCarState(self.carId, acsys.CS.RPM)
        distance = ac.getCarState(self.carId, acsys.CS.NormalizedSplinePosition)
        steer = ac.getCarState(self.carId, acsys.CS.Steer)
        (x, y, z) = ac.getCarState(self.carId, acsys.CS.WorldPosition)
        
        self.outputFile.write('{}\t{:.3f}\t{:.4f}\t{:.2f}\t{:.3f}\t{:.3f}\t{}\t{:.0f}\t{:.1f}\t{:.2f}\t{:.2f}\t{:.2f}\n'.format(\
        lapCount, lapTime/1000, distance, speed, throttle, brake, 
        gear, rpm, steer, x, y, z))
        
(Abkürzung)

def acUpdate(deltaT):
    global telemetryInstance
    telemetryInstance.logging()

Ich werde nicht auf die Details des Codes eingehen, aber der App-Mechanismus im Spiel führt jedes Mal, wenn eine Grafik aktualisiert wird, "acUpdate (deltaT)" aus (60 Mal pro Sekunde in meiner Umgebung). Datenerfassung und Dateiausgabe werden in "ACTelemetry.logging ()" ausgeführt, das von "acUpdate (deltaT)" aufgerufen wird.

Gehen Sie wie folgt vor, um diese In-Game-App zu aktivieren:

  1. Platzieren Sie ACTelemetry.py unter "(Steam-Installationsordner) \ steamapps \ common \ asserttocorsa \ apps \ python \ ACTelemetry".
  2. Aktivieren Sie "ACTelemetry" in "Optionen" ⇒ "Allgemein" ⇒ "UI-Modelle" im Spiel
  3. Bewegen Sie die Maus während des Spiels (auch während der Wiedergabe) an den rechten Bildschirmrand und wählen Sie "ACT-Telemetrie" aus den angezeigten Apps.

Die folgende Benutzeroberfläche wird angezeigt. Klicken Sie auf die Schaltfläche "Weiter", um das Fahrzeug auszuwählen, für das Daten erfasst werden sollen, und klicken Sie auf die Schaltfläche "Start", um die Protokollerfassung zu starten. ui.png

Als Ergebnis können die folgenden Daten erhalten werden. Ich möchte diese Daten sowohl für mein Spiel als auch für mein KI-Spiel abrufen und vergleichen.

logger_20190817_1257.log


Course : ks_barcelona
Layout : layout_gp
Car Id : 0
Driver : abe.masanori
Driver : ks_toyota_gt86

lapCount	lapTime	distance	speed	throttle	brake	gear	RPM	steer	x	y	z
1	151.829	0.9399	115.7	1.00	0.00	4	6425	33	490.4	-14.6	-436.3
1	151.846	0.9400	115.8	1.00	0.00	4	6425	33	490.5	-14.6	-435.7
1	151.862	0.9401	115.8	1.00	0.00	4	6421	33	490.5	-14.7	-435.2
1	151.879	0.9402	116.0	1.00	0.00	4	6425	33	490.6	-14.7	-434.7

Datenformung vor der Visualisierung

Dieses Mal möchte ich die Daten mithilfe der Javascript-Bibliothek von Plotly visualisieren. Die obige tabulatorgetrennte Datei mit Header kann so behandelt werden, wie sie ist, ist jedoch etwas problematisch. Fügen Sie daher im Voraus die folgende Verarbeitung und Formgebung hinzu.

Die Datei sieht wie folgt aus.

my_data_before.js


my_data = [
    [2, 0.125, 0.0017, 155.96, 1.000, 0.000, 5, 6672, 0.0, 365.52, -18.43, -187.32],
    [2, 0.142, 0.0019, 155.96, 1.000, 0.000, 5, 6672, 0.0, 365.13, -18.43, -186.72],
    [2, 0.158, 0.0020, 156.11, 1.000, 0.000, 5, 6674, 0.0, 364.73, -18.43, -186.11],
    [2, 0.175, 0.0022, 156.11, 1.000, 0.000, 5, 6676, 0.0, 364.34, -18.44, -185.51],
    (Folgendes wird weggelassen)

Visualisierung der erfassten Daten

Ich möchte das folgende Viz mit Plotly machen. Sie können es tatsächlich von (hier verschieben. Es ist etwas schwer, aber das animierte GIF ist [hier](https: // abe-masanori). github.io/AC_analysis/data_viz/ui.gif))

--Für Geschwindigkeit, Gas- / Bremsöffnung, Gang, Motordrehzahl und Lenkwinkel zeigen Sie Ihre eigenen und AI (CPU) -Daten auf der linken Seite des Liniendiagramms mit dem Abstand vom Start als horizontaler Achse an.

Diese Art von Daten zeigt normalerweise die horizontale Achse = Zeit und die vertikale Achse = Metriken an. Wenn Sie dies jedoch diesmal tun, ist es schwierig, Ihre eigenen Daten mit AI-Daten (CPU-Daten) zu vergleichen, sodass die horizontale Achse von vorne beginnt. Verwenden Sie die numerischen Werte (0.0: Start bis 1.0: Ziel), die die Entfernung von darstellen.

goal.png

Erstellung von HTML-Dateien

Erstellen Sie zunächst eine Basis-HTML-Datei.

--Lade die Bibliothek von Plotly.

viz_before.html

viz_before.html


<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>mich selber(Vor der Verbesserung)Und AI-Datenvergleich</title>
        <script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
        <style>
            html,
            body {
                margin: 0;
                padding: 0;
                height: 100%;
                display: flex;
            }
            </style>
    </head>
    <body>
        <div>
            <div id="div-speed"></div>
            <div id="div-throttle"></div>
            <div id="div-brake"></div>
            <div id="div-gear"></div>
            <div id="div-rpm"></div>
            <div id="div-steer"></div>

        </div>
        <div id="div-position"></div>
    </body>
    <script src="data/my_data_before.js"></script>
    <script src="data/cpu_data.js"></script>
    <script src="my_viz.js"></script>
</html>

Erstellen von Geschwindigkeitsdiagrammen usw.

Da die Diagramme für Geschwindigkeit, Gas- / Bremsöffnung, Gang, Motordrehzahl und Lenkwinkel nahezu identisch sind, wird ein Liniendiagramm mit Ihren eigenen Daten, AI-Daten (CPU), der Position zur Erstellung des Diagramms und dem Titel der vertikalen Achse als Argumente übergeben. Erstellen Sie eine Funktion, die erstellt.

my_viz.js

my_viz.js


function plot_speed(my_x, my_y, cpu_x, cpu_y, divId, title_y){
    var data_me = {
        x: my_x,
        y: my_y,
        mode: 'lines',
        name: 'me'
    };

    var data_cpu = {
        x: cpu_x,
        y: cpu_y,
        mode: 'lines',
        name: 'cpu'
    };

    var layout = {
        autosize: false,
        yaxis: {title: title_y},
        width: 600,
        height: 250,
        margin: {l: 70, r: 70, b: 25, t: 25}
    };

    Plotly.newPlot(divId, [data_me, data_cpu], layout);
}

my_data_distance = Array.from(my_data, x => x[2]);
cpu_data_distance = Array.from(cpu_data, x => x[2]);

my_data_speed = Array.from(my_data, x => x[3]);
cpu_data_speed = Array.from(cpu_data, x => x[3]);
plot_speed(
    my_data_distance, my_data_speed, cpu_data_distance, cpu_data_speed, 
    'div-speed', 'Geschwindigkeit(km/h)'
);
(Folgendes wird weggelassen)

Es ist ein wenig ärgerlich, das zweidimensionale Array nicht so passieren zu können, wie es ist.

Erstellen eines Diagramms mit Positionsdaten

Dadurch wird auch eine Diagrammerstellungsfunktion erstellt.

my_viz.js


function plot_position(min_distance, max_distance) {
    my_x = Array.from(my_data.filter(v => (min_distance < v[2]) && (v[2] < max_distance)), x => x[9]);
    my_z = Array.from(my_data.filter(v => (min_distance < v[2]) && (v[2] < max_distance)), x => x[11]);

    my_pos = {
        x: my_x,
        y: my_z,
        mode: 'scatter',
        mode: 'line',
    };

    var layout = {
        xaxis: {autorange: false, range: [-600, 600]},
        yaxis: {autorange: false, range: [600, -600]},
        autosize: false,
        width: 300,
        height: 300,
        margin: {l: 50, r: 50, b: 50, t: 50, pad: 10},
        showlegend: false,
        images: [{
            source: 'pos_base.png',
            xref: 'x',
            yref: 'y',
            x: 500,
            y: 600,
            xanchor: 'right',
            yanchor: 'bottom',
            sizex: 1000,
            sizey: 1200,
            sizing: 'stretch',
            opacity: 0.4,
            layer: 'below'
        }]
    };

    Plotly.react('div-position', [my_pos], layout);
}

Zusammenarbeit zwischen Graphen

Wenn Sie im Geschwindigkeitsdiagramm einen Bereich auf der horizontalen Achse (Zoom) auswählen, wird das Ereignis ausgelöst und das Ergebnis in anderen Diagrammen wiedergegeben.

my_viz.js


document.querySelector('#div-speed').on(
    'plotly_relayout',
    function(eventdata) {
        if(eventdata['xaxis.autorange']) {
            x_start = 0.0;
            x_end = 1.0;
            option = {'xaxis.autorange': true};
        } else {
            x_start = eventdata['xaxis.range[0]'];
            x_end = eventdata['xaxis.range[1]'];
            option = {'xaxis.range': [x_start, x_end]}
        }

        Plotly.relayout('div-throttle', option);
        Plotly.relayout('div-brake', option);
        Plotly.relayout('div-gear', option);
        Plotly.relayout('div-rpm', option);
        Plotly.relayout('div-steer', option);

        plot_position(x_start, x_end);
    }
);

Bestätigung der Visualisierungsergebnisse

Jetzt können Sie mit folgendem Ablauf analysieren.

  1. Sehen Sie sich das Geschwindigkeitsdiagramm an und sehen Sie, wo Sie langsamer als AI (CPU) sind.
  2. Zoomen Sie auf das als langsam identifizierte Teil.
  3. Überprüfen Sie andere Metriken, um die Ursache für die Langsamkeit zu ermitteln.

(Doppelklicken Sie auf das Geschwindigkeitsdiagramm, um den Zoom abzubrechen.)

Nun, ich musste nicht so weit gehen, um zu sehen, warum es langsam war, es war nur so, dass der Lenkwinkel zu groß war. Sobald die Ursache bekannt ist, ist es einfach, aber der GT5 / 6 hat eine Obergrenze für den Lenkwinkel (er scheint sich dynamisch zu ändern), sodass die Situation anscheinend nicht so schlecht war.

newplot (1).png

Indem ich mit dem Bewusstsein spielte, dass die Ursache zu viel Lenkung war, konnte ich den Unterschied mit AI (CPU) von 4 Sekunden auf 1 Sekunde oder weniger reduzieren. Wenn ich die Daten jedoch erneut überprüfe, scheint die Lenkung immer noch zu scharf und der Weg zum Abbiegen steil zu sein, sodass ich mich noch verbessern muss.

[Vergleich der Daten zwischen mir (nach Verbesserung) und AI](http: // localhost: 8000 / viz_after.html)

Plotly Eindruck

Dieses Mal habe ich bei der Visualisierung der Daten die folgenden Tools außer Plotly ausprobiert. Bitte geben Sie mir einen kleinen Eindruck.

Zusammenfassend ist Plotly sehr gut.

Recommended Posts

Ich habe versucht, die Laufdaten des Rennspiels (Assetto Corsa) mit Plotly zu visualisieren
Ich habe versucht, die Daten mit Zwietracht zu speichern
Ich habe versucht, den Text des Romans "Wetterkind" mit Word Cloud zu visualisieren
Ich habe versucht, die Spacha-Informationen von VTuber zu visualisieren
Ich habe versucht, die Tweets von JAWS DAYS 2017 mit Python + ELK einfach zu visualisieren
Ich habe versucht, die Entropie des Bildes mit Python zu finden
[Pferderennen] Ich habe versucht, die Stärke des Rennpferdes zu quantifizieren
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
[Python] Ich habe versucht, die folgende Beziehung von Twitter zu visualisieren
Ich habe versucht, die Eigenschaften der neuen Informationen über mit dem Corona-Virus infizierte Personen mit Wordcloud zu visualisieren
Ich habe versucht, den Stromverbrauch meines Hauses mit Nature Remo E lite zu visualisieren
Ich habe versucht, die Daten des Fußballturniers der FIFA Fussball-Weltmeisterschaft Russland mit Fußball zu analysieren
Ich schrieb einen Test in "Ich habe versucht, die Wahrscheinlichkeit eines Bingospiels mit Python zu simulieren".
Ich habe versucht, den Verkauf von Spielesoftware mit VARISTA anhand des Artikels von Codexa vorherzusagen
Ich habe versucht, die Bewässerung des Pflanzgefäßes mit Raspberry Pi zu automatisieren
Ich habe versucht zu beheben "Ich habe versucht, die Wahrscheinlichkeit eines Bingospiels mit Python zu simulieren"
Ich habe versucht, die Größe des logischen Volumes mit LVM zu erweitern
Ich habe versucht, den DNN-Teil von OpenPose mit Chainer-CPU auszuführen
Ich habe versucht, die Effizienz der täglichen Arbeit mit Python zu verbessern
Ich habe versucht, den allgemeinen Zustand der VTuber-Kanalbetrachter zu visualisieren
Ich habe versucht, AutoEncoder mit TensorFlow zu visualisieren
[Python] Ich habe versucht, das Preisgeld von "ONE PIECE" über 100 Millionen Zeichen mit matplotlib zu visualisieren.
[Python] Ich habe versucht, die Nacht der Galaxienbahn mit WordCloud zu visualisieren!
Ich habe versucht, die Altersgruppe und die Ratenverteilung von Atcoder zu visualisieren
Ich habe versucht, den Authentifizierungscode der Qiita-API mit Python abzurufen.
Ich habe versucht, die Bewegungen von Wiire-Playern automatisch mit Software zu extrahieren
Ich habe versucht, die Negativität von Nono Morikubo zu analysieren. [Vergleiche mit Posipa]
Ich habe versucht, die Standardrolle neuer Mitarbeiter mit Python zu optimieren
Ich habe versucht, das Modell mit der Low-Code-Bibliothek für maschinelles Lernen "PyCaret" zu visualisieren.
Ich habe versucht, die Filminformationen der TMDb-API mit Python abzurufen
Ich habe versucht, alle Entscheidungsbäume des zufälligen Waldes mit SVG zu visualisieren
Ich habe versucht, das Verhalten des neuen Koronavirus mit dem SEIR-Modell vorherzusagen.
Ich habe versucht, CloudWatch-Daten mit Python abzurufen
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich habe versucht, die statistischen Daten der neuen Corona mit Python abzurufen und zu analysieren: Daten der Johns Hopkins University
Da es der 20. Jahrestag der Gründung ist, habe ich versucht, die Texte von Parfüm mit Word Cloud zu visualisieren
Ich habe versucht, die 100-Yen-Lagerstätte von Rakuten-Pferderennen (Python / Selen) zu automatisieren.
Ich habe das TensorFlow-Tutorial mit Kommentaren ausgeführt (Textklassifizierung von Filmkritiken).
Ich habe versucht, die Daten des Laptops durch Booten unter Ubuntu zu retten
Die Geschichte von soracom_exporter (Ich habe versucht, SORACOM Air mit Prometheus zu überwachen)
Ich habe versucht, ein Modell mit dem Beispiel von Amazon SageMaker Autopilot zu erstellen
Ich habe versucht, die Literatur des neuen Corona-Virus mit Python automatisch an LINE zu senden
Ich habe versucht, die Sündenfunktion mit Chainer zu trainieren
Ich habe versucht, Funktionen mit SIFT von OpenCV zu extrahieren
Ich habe versucht, die Grundform von GPLVM zusammenzufassen
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Ich habe versucht, das Spiel in der J League vorherzusagen (Datenanalyse)
Ich habe versucht, Soma Cube mit Python zu lösen
Ich habe versucht, die API von Sakenowa Data Project zu verwenden
Ich habe versucht, den negativen Teil von Meros zu löschen
Ich habe versucht, das Problem mit Python Vol.1 zu lösen
Ich habe versucht, die Stimmen der Sprecher zu klassifizieren
Ich habe versucht, den Beispielcode des Ansible-Moduls auszuführen
Ich habe versucht, die String-Operationen von Python zusammenzufassen
Ich habe versucht, mit dem Seq2Seq-Modell von TensorFlow so etwas wie einen Chatbot zu erstellen