Neu bei Python, bitte um Hilfe bei Fahrzeugcockpit-Simulation

Du hast eine Idee für ein Projekt?
Antworten
rattlesnake
User
Beiträge: 7
Registriert: Dienstag 15. November 2016, 21:28

Hallo liebe python Gemeinde!

Ich habe ein wenig Vorkenntnisse in anderen Programmiersprachen, aber absolut keine in Python. Mache gerade Online-Tutorials durch.
Unabhängig davon möchte ich um Mithilfe bei meinem Projekt bitten, wie ich dieses in python umsetze. Ich will bewußt keine fertige Lösung und auch kein Tool was vielleicht genau das macht was ich suche, sondern will es "selbst" (natürlich mit Eurer Unterstützung) erstellen um daraus zu lernen - und zwar von Profis! :-)

Hier mein Ziel:

Ich habe einen CAN-Bus Adapter fürs Auto, welcher mir die Kommunikation der Fahrzeugmodule mitliest. Diese Nachrichten werden über USB im LAWICEL-Protokoll zu einem PC übertragen. Dort setze ich derzeit die Software "CANHacker" ein um die Datenströme zu monitoren bzw. aufzuzeichnen. Die Aufzeichnungen lassen sich als TRC-Dateien im ASCII-Format abspeichern.

Mir ist es inzwischen durch Analyse- und Testverfahren gelungen einige der darin enthaltenen Informationen zu dekodieren. Unter anderem die aktuelle Motordrehzahl und Geschwindigkeit des Fahrzeuges (und noch vieles mehr, aber für den Anfang reicht das). Bislang habe ich die Werte in den Nachrichten mit Excel verarbeitet und visualisiert.

Mein Ziel ist es ein virtuelles Cockpit zu entwerfern auf dem ich Fahrzeugnahe Instrumente wie in einem Simulator die Daten wieder darstellen lasse. Im Grunde macht ein echtes Cockpit im Auto nichts anderes, es empfängt bestimmte CAN-Nachrichten und richtet seine Zeiger aus. Dabei geht es mir darum die Daten wieder "abzuspielen" und dabei die Meßwerte in Echtzeit darstellen zu lassen.

In einer späteren Fassung des Programmes wäre es klasse, wenn man die vom Adapter gelieferten Daten in Echtzeit visualisieren könnte.


So, ich hoffe das ist für den Einstieg nicht zu hoch gegriffen...
Ich freue mich auf rege Beteiligungen (und hoffentlich keine Beleidigungen, bin aus anderen Foren ja so einiges gewohnt...)

Vielen Dank,

rattlesnake
rattlesnake
User
Beiträge: 7
Registriert: Dienstag 15. November 2016, 21:28

Das Tracefile hat diesen Aufbau:

Code: Alles auswählen

TRC      ::= HEADER \n MESSAGE\n... ;
HEADER   ::= "Time   ID     DLC Data                    Comment" ;
MESSAGE  ::= TIMECODE " " ID "      " DLC " " [ DATA ];
TIMECODE ::= [0-9]{2} "," [0-9]{3} ;
ID       ::= HEXBYTE{3} ;
DLC      ::= 0-8 ;
DATA     ::= ( HEXBYTE " " ){0..8} ;
HEXBYTE  ::= [0-9A-F][0-9A-F] ;
Dabei ist
.. TIMECODE = Die relative Zeit vom Start des Trace in Sekunden (vor dem Komma) und Millisekunden (nach dem Komma)
.. ID = Die Nachrichten-ID (11-Bit), hexkodiert
.. DLC = die Anzahl der Datenbytes in der Nachricht (0 bis max. 8)
.. DATA = Eine Folge von hexkodierten Datenbytes

Ein Beispiel:

Code: Alles auswählen

Time   ID     DLC Data                    Comment
21,723 040      8 FB 95 00 00 00 01 B0 27 
21,724 079      8 00 00 00 00 00 00 00 00 
21,728 010      8 08 00 00 00 00 40 00 00 
21,728 08B      8 27 00 00 38 00 1E 13 50 
21,732 028      8 00 81 10 00 48 FF FF FF 
21,734 509      8 11 12 00 00 09 00 00 00 
21,736 067      8 41 80 08 02 80 A0 00 01 
21,743 038      8 00 00 00 61 00 01 08 00 
21,748 06B      8 43 D3 04 03 81 22 3F 00 
21,749 220      8 C0 00 2C 00 02 0C E2 31 
21,753 048      8 7F 07 6D 05 27 02 E0 20 
21,753 084      8 03 00 00 80 00 00 00 00 
21,754 035      8 00 02 00 00 00 00 00 00 
21,755 065      8 00 00 01 00 BC 12 B2 02 
....
Die meisten IDs wiederholen sich ständig in festen Zeitabständen (Periode), z.b. alle 200ms oder 500ms. Andere wiederum treten nur zeitweise auf. Der Timecode läuft bei 59,999 auf 00,000 über. Um daraus eine absolute Zeit zu machen muss man einen eigenen Minuten, Stundenzähler mitberechnen. Auf dem MS-CAN Bus wird in einer bestimmten ID die aktuelle Uhrzeit und Datum mitgeliefert. Hieraus kann man die Basiszeit ermitteln.

Beim MS-CAN ist ein Tracefile von 15 Minuten ca. 15 MB groß. Jedoch interessiert nur ein Teil der Nachrichten.
rattlesnake
User
Beiträge: 7
Registriert: Dienstag 15. November 2016, 21:28

Ziel 1: Eine Tracedatei verarbeiten.

Wie sollte ich das tun?
Variante A) Die kompletten Daten einlesen, vorfiltern und dann diese Daten "abspielen"
Variante B) Die Daten aus der Datei "streamen" und direkt verarbeiten um Arbeitsspeicher zu sparen und beliebig große Dateien verarbeiten zu können

"B" hätte den Vorteil das man dieselbe Methode bei einem Live-Zugriff auf die Daten des Adapters verwenden könnte. Jedoch bin ich mir unsicher ob die Performance ausreichend ist hierfür. Sicher könnte man nicht jedes Datum verarbeiten, was aber auch nicht zwingen notwendig ist.


Ziel 2: Eine grafische Oberfläche modellieren

Zu beginn sollte eine Menüzeile für die Befehle und ein Canvas für die Grafikelemente verfügbar sein. Ggf. noch ein Log-Fenster für Nachrichten oder die Rohen CAN-Daten.
rattlesnake
User
Beiträge: 7
Registriert: Dienstag 15. November 2016, 21:28

Folgende CAN-Werte sind interessant:

Motordrehzahl:
CAN-ID: "078"
Periode: 60ms
Daten: Bytes D5 und D6 (von 0 gezählt) ergeben zusammen einen 16-Bit Wert, welcher die Drehzahl in U/min direkt ausdrückt (0-6500).

Geschwindigkeit:
CAN-ID: "08B"
Periode: 220ms
Daten: Bytes D1 und D2 ergeben einen 16-Bit Wert, welcher geteilt durch 100 die Geschwindigkeit mit zweistelliger Genauigkeit repräsentiert.
BlackJack

@rattlesnake: Ich würde die Daten ”streamen”. Das ist flexibler und letztendlich ja auch ein Teil von Lösung A). Man kann A) leicht aus B) erstellen, aber eben nicht umgekehrt. Zudem bietet sich das in Python an, weil einem dort ja andauernd Iteratoren beziehungsweise iterierbare Objekte begegnen und auch Syntax-Unterstützung (Generatorfunktionen und -ausdrücke) und das `itertools`-Modul existieren.
rattlesnake
User
Beiträge: 7
Registriert: Dienstag 15. November 2016, 21:28

Blackjack, vielen Dank. Ich müsste also einen Filehandle erzeugen und dann zeilenweise daraus lesen? Könnte dieser Handle dann auch ein Port/Socket sein?
Würdest Du mir ein praktisches Beispiel geben, am besten gleich wie man auch den Strin in ein Array splittet?

Wie schaut es mit der Mainloop aus? Das lesen der Daten sollte doch sicher asynchron geschehen, Menüpunkte und Buttons sind vermutlich irgendwelche Ereignisse. Wie baut man diese Hauptschleife auf? Threads? Timer? Auch hier wär ich über ein praktisches Beispiel froh.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@rattlesnake: in Deinen Tutorials wird sicher irgendwo ein Abschnitt sein, wie man mit Dateien arbeitet.

Code: Alles auswählen

import datetime
import codecs
from collections import namedtuple

CanData = namedtuple("CanData", "time,id,dlc,data")

def read_can(filehandle, basetime):
    filehandle = iter(filehandle)
    _header = next(filehandle)
    lasttime = basetime
    for line in filehandle:
        parts = line.split()
        time, id, dlc = parts[:3]
        data = codecs.decode(b''.join(parts[3:11]), "hex")
        time = basetime + datetime.timedelta(seconds=float(time.replace(b',', b'.')))
        if time < lasttime:
            basetime += datetime.timedelta(seconds=60)
            time += datetime.timedelta(seconds=60)
        yield CanData(time, int(id, 16), int(dlc), data)


basetime = datetime.datetime(2016,11,16,8,27)
with open("datei.txt", "rb") as can_data:
    for data in read_can(can_data, basetime):
        print(data)
Zum Entpacken der Daten bietet sich struct.unpack_from an.
Antworten