Fehlersuche in Sketch während Betrieb

Hallo zusammen,

in meinem Projekt das Steuergerät meines Motorrads auszulesen habe ich unregelmäßige Abbrüche.

Kurz zum Aufbau:
Ein Arduino Nano ist mit einem K-Line zur Seriell Konverter ausgestattet (L9637D).
Der HC-06 Bluetooth Adapter spricht mit der Außenwelt.

Ablauf:
Ein OBD II kompatibles Gerät verbindet sich per BT und konfiguriert die Schnittstelle.
Es gibt einen Abgleich welche Abfragen (PID´s) unterstützt werden.
Anschließend werden in einer Dauerschleife diese Werte abgefragt.
Aufgabe meines Adapters ist, diese Anfragen umzuwandeln, dass das Motorrad diese versteht (Etwas anderes Schema der Nachrichten und unterschiedliche PID´s). Auch das Ergebnis muss nun umgerechnet und wieder in das Schema des OBD II Protokolls gebracht werden.

Testumgebung:
Für die Entwicklung habe ich einen Emulator geschrieben, der per Zufallsgenerator auf die Anfragen per Serieller Schnittstelle antwortet.
Apps wie z.B. Torque oder Car Scan und meine ActionCam können nun stundenlang mit dem Adapter kommunizieren.

Echtbetrieb:
Mit meinem Motorrad verbunden, kommuniziert eine ActionCam mit dem Adapter und zeichnet die Daten auf.
Diese Aufzeichnung hört nach maximal 30 Minuten einfach auf. Manchmal auch bereits nach 15 Minuten.

Nun stehe ich vor dem Problem, dass ich weder Kamera noch Arduino während der Fahrt debuggen kann. Auch erkenne ich einen Abbruch erst Zuhause, wenn ich mir das Video ansehe.

Grundsätzlich scheint der Code ja zu funktionieren. Also erwarte ich keinen Variablen-Überlauf o.ä.
(Globale Variablen verwenden 603 Bytes (29%) des dynamischen Speichers)
Eher, dass es Werte geben könnte, die ich im Emulator nicht vorgesehen habe.

Bleiben also nur die Vermutungen:
Arduino erhält einen Wert, der in einer Kalkulation zu einem Fehler führt (z.B. Null-Division)
Kamera bekommt einen Wert, der zum "Absturz" der Aufzeichnung führt

Habt ihr eine Idee wie ich das weiter testen/eingrenzen kann?
Man kann ja schlecht eine LED leuchten lassen, wenn der Arduino abgeraucht ist :wink:
Die Kamera ist per BT weiterhin verbunden, mehr kann man ihr leider nicht entnehmen, ohne das Video auszulesen.

Man kann ja schlecht eine LED leuchten lassen, wenn der Arduino abgeraucht ist

"abgeraucht"?
Du meinst doch eher das Auftreten deinens Programmierfehlers, als echten "Rauch", oder?

Und ja, das geht.

Ja, ich meine natürlich einen Abbruch des Programmablaufs. Hardwareseitig ist alles in Ordnung.

Aufgrund dessen, dass mein Emulator länger läuft als das Motorrad selbst, müsste es ja an den eingehenden Daten liegen. Die entweder in meinen Kalkulationen einen Fehler hervorrufen oder Kameraseitig nicht verarbeitet werden können.
Oder es liegt daran, dass das Motorrad irgendwann nicht mehr antwortet. Dann würde ich aber eine gleichmäßige Zeit erwarten, wann die Verbindung gekappt wird. Bzw. sollte sich das Programm dann selbst neu verbinden.

Hallo zusammen,

ich habe nun ein seltsames Verhalten feststellen können, welches vielleicht zu des Pudels Kern führen könnte.

Eine Berechnung sieht so aus, dass ich einen Wert erhalte, der zwischen 201 und 895 liegt.
Diesen muss ich umrechnen, dass er 0x00 (0%) - 0xFF (100%) ergibt.

uint8_t ecuResponse[12];

void ConvertResult()
{
  unsigned int value = 0;
  uint8_t minimum = 201;
  uint8_t maximum = 895;

  value = ecuResponse[2] * 255 + ecuResponse[3];
            
  if(value > maximum)
    maximum = value;

  if(value > minimum)
    ecuResponse[2] = (value - minimum) *100 / (maximum - minimum) * 255/100;
  else
    ecuResponse[2] = 0x00;
  ecuResponse[3] = 0x00;
}

Steigt der Wert nun an, funktioniert das bis ~92,7%. Dann beginnt er wieder bei 0%.
Würde für mich bedeuten, dass es einen Überlauf gibt. Kann imho doch nur daran liegen, dass auf den falschen datentypen gecastet wird, oder?
Hätte nun vermutet, dass die Kalkulation mit unsigned int abläuft und dann in das uint8_t "gerundet" wird.

Muss ich nun den minimum & maximum Wert casten damit die Berechnung funktioniert?
Was wäre der "korrekte" Weg?

Es sei Euch für einen Denkanstoß gedankt!
Schönes Wochenende :slight_smile:

uint8_t maximum = 895; // unmöglich

Eine 8 Bit Variable kann maximal 256 Werte annehmen.

uint8_t maximum = 895;
Wird dadurch zu
uint8_t maximum = 127;
Und das scheint mir ein unerwünschtes Verhalten zu sein.

Das kann auch zu einem Überlauf führen:

ecuResponse[2] * 255

Hier wird standardmäßig in int gerechnet

Argh, das war ein kopierfehler. Sorry!
Im original Code ist diese Stelle korrekt:

uint16_t maximum = 895;

Aber wenn in int gerechnet wird, wäre das die schuldige Stelle!
Was wäre die korrekte Herangehensweise?
ecuResponse[2] vorher in einen unsigned-Wert kopieren oder casten (uint32_t)ecuResponse[2] * 255?

Denke das wird auch der Grund dafür sein, dass bei bestimmten Werten der Ardu resettet.
Vielen Dank schonmal!

ecuResponse[2] = (value - minimum) *100 / (maximum - minimum) * 255/100;
Wieso multiplizierst Du erst mit 100, und dividierst anschließend wieder dadurch?
Klammern vergessen, oder soll das auf 2 Nachkommastellen runden?
Da besteht die Gefahr, daß der Compiler das merkt und diese Operationen einfach wegoptimiert.

Und Konstanten (minimum, maximum) sollten als const deklariert werden.

Aber das alles kann nicht die Ursache für Abstürze sein, die dürften IMO eher aus der rauhen Umgebung (Motorrad) kommen.

Hallo,
mache es doch so:

Prozent = map(Wert,201,895,0,100);

Gibt 0 bis 100% raus.
Gruß und Spaß
Andreas

@DrDiettrich: Ja, ich hatte erst die Klammern anders gesetzt um möglichst mit Ganzzahlen zu rechnen.
Kurios finde ich eben, dass die Berechnung bis ca. 92,7% genau funktioniert. Erst dann kommt der Einbruch...
Das wäre natürlich möglich. Vom Gefühl her würde ich aber sagen, dass es früher zu Abbrüchen kommt, je ambitionierter man fährt. Also die Maximalwerte auslotet (Keine Sorge: Auf der Rennstrecke :slight_smile: ).
Es ist alles extra dick verlötet und vibrationsgeschützt mehrfach in Luftfolie untergebracht.

Max ist absichtlich keine Konstante, da ich diese laufend anpasse. Offensichtlich lässt sich die Drosselklappe bei Betriebstemperatur und höheren Gängen weiter öffnen als im Stand/Testbetrieb.
Wird aber angepasst sobald ich den "wahren" Maximalwert kenne!

Danke Andreas! Werde ich so versuchen:
map(Wert,201,895,0,255);
Muss den "Echten" Wert ja wieder OBD II konform umrechnen, damit die ELM327 kompatiblen Apps den vernünftig anzeigen.
Motorrad Hersteller halten nix von Standardisierungen :-/

Das ist natürlich nicht meine einzige Berechnung, daher hatte ich einen grundsätzlichen Denkfehler in Sachen Rundungen und Datentypen vermutet.
So muss ich wohl nochmal schnell vor die Tür :roll_eyes:

Trib:
Es ist alles extra dick verlötet und vibrationsgeschützt mehrfach in Luftfolie untergebracht.

Das schützt nichts gegen EM-Störungen, und bringt noch die Gefahr einer Überhitzung dazu.

Hallo,

gibt ja noch die Möglichkeit, ein Protokoll auf eine SD-Karte aufzuzeichnen.
Das dann auslesen und sehen, wann es nicht mehr weiter geht.

Gruß Kalli

@SkobyMobil: Danke für den Tipp mit map(). Das liefert nun saubere Werte zurück, die von meiner Kamera, als auch zahlreichen OBD2-Apps, als 0-100% erkannt werden!

DrDiettrich:
Das schützt nichts gegen EM-Störungen, und bringt noch die Gefahr einer Überhitzung dazu.

Der µC liegt im Heck des Motorrads und ist keiner (zusätzlichen) Hitze ausgesetzt. Der Arduino war nach 1h handwarm, der HC-06 war minimal wärmer. Messe beim nächsten mal aber mit einem Laser-Thermometer nach.
EM-Störungen kann ich natürlich nicht ausschließen :o

@Kalli: Klar, hatte ich aber bisher nicht geplant. Habe momentan nur ein Ethernet-Shield mit SD rumliegen. Das passt gar nicht unter meine Sitzbank :frowning:
Prinzipiell kann ich ja sehen, welche Daten zuletzt übermittelt wurden. Die waren "mittendrin" also keine Grenzwerte und immer unterschiedlich. Die Temperatur ist meist der erste Wert der dann nicht mehr angezeigt wird. Das kann natürlich die Ursache oder erste Abfrage nach einem Fehler/Neustart sein.

Werde mal alle Abfragen bis auf die Drosselklappe (die ja nun funktioniert) auskommentieren und noch eine Runde drehen. Dann hoffe ich, kann ich eingrenzen ob es an einer Kalkulation liegt.
Bricht das Ganze dennoch ab, bleiben Spannungseinbrüche, elektromagnetische Störungen oder was anderes im Code. Was im Testaufbau mit meinem Emulator hätte auffallen müssen...

Ansonsten muss wohl der WatchDog her. Bei einem Spannungsabbruch dürfte der ja nichts mitbekommen, sonst die entsprechende Zeile zurückmelden.