Arduino OBD2 Soundgenrator

Hallo liebe Community,

Ich würde gerne über OBD2 für unser Rennauto einen Soundgenerator bauen.
Als Sensorwerte würde ich die Motordrehzahl, die Motorlast, die Geschwindigkeit und den aktuellen Gang verwenden.

Ich habe bereits angefangen und mir einige Bauteile zugelegt, wie etwa 2x 30w Lautsprecher, einen Arduino Mega 2560 und den SeeedStudio CAN-Bus-Shield.

Ich habe auch schon die entsprechenden OBD-PIDs rausgesucht:
Getriebe-Gang: A4

Motordrehzahl: 0C

Fahrzeuggeschwindigkeit: 0D

Motorlast: 04

Jetzt ist halt die Frage, wie man das ganze programmiert, da ich auch gerne eine Samplingrate von mindestens 44khz hätte und die Lautstärke über ein digitales Poti steuern würde. Es würde praktisch so sein, dass dauerhaft solange man im Leerlauf ist oder auf dem Gas ist das gleiche Motorengeräusch abgespielt werden soll und die Lautstärke abhängig von Motorlast und Motordrehzahl sein soll. Beim Motorstart soll anfangs ein jeweils anderes Soundfile abgespielt werden und auch bei der Launchcontrol und beim Schaltvorgang.

Ich hoffe jmd kann mir helfen :wink:

Und bitte keine Hassbeiträge, ich möchte nur Hilfe:)

Mit freundlichen Grüßen
Simon

Interesting question, is this a model or a real racing car. The reason for asking is all race cars I have been near make enough noise on their own. This is way more then a few 30w speakers would provide. Have you looked at and codec shields, they would have most of the hardware needed.

Ich weiß, was du meinst:) Aber es ist ein Straßenauto, dass für die Rennstrecke umgebaut wird, aber auch im Straßenverkehr bewegt werden kann, wenn der Soundgenerator ausgeschaltet bzw ausgebaut ist. Das Auto hat einen Hubraum von nur 1400ccm aber eine Leistung von 320ps bei wenig Gewicht. Nur leider ist das Auto sehr leise :confused:
Und da kommt natürlich kein Rennstrecken-feeling

Hoffe meine Situation ist es klarer:) Es soll kein übertriebener Lärm sein, nur dezent für den Innenraum.

Leider weiß ich nicht wie man einen Codec Shield nutzt und ich würde das ganze gerne kompakt und realistisch bauen wollten. Gibt es einen guten MP3 shield mit hoher Abtastrate?

Hallo Simon,

ich sehe hierbei durchaus ein paar Probleme.
OBD2 ist nicht so dermaßen schnell. Vielleicht kannst Du die CAN-Bus Nachrichten direkt abfangen?
Die Launchcontrol wirst Du bei OBD2 auch nicht finden.

Für den Soundgenerator möchtest Du kein MP3 Shield haben. Der Motor soll ja nicht immer identisch klingen, sondern Drehzahlabhängig. Mit dem Shield spielst Du nur einzelne Titel ab.
Daher würde ich mich mal im Modellbau umsehen, die haben solche Lösungen mit verschiedensten Motorcharakteristiken.

Also Soundgenerator suchen.
Mit dem CAN-Bus Shield schon mal erste Versuche starten an die entsprechenden Morordaten zu gelangen,
Und erst wenn die einzelnen Entwicklungsschritte passen, alles zusammenfügen.

Hallo TriB,

Was meinst du mit Can-Bus nachrichten direkt abgreifen?
Die Launch Control hätte ich mit der Geschwindigkeit 0kmh und einer Konstanten Drehzahl +-200rpm gemacht.

Aktuell habe ich schon alles ab Verstärker bis Lautsprecher. Klar soll das ganze nicht immer identisch klingen, aber im Modellbau habe ich leider nichts gefunden:/

Komme schon an die Motordrehzahl.
Das zusammenfügen ist eh klar.

Ich würde als erstes mal gerne die Geschwindigkeit, Drehzahl, Motor last und den Gang auslesen wollen. Die Werte sollen dann immer als Variable abgespeichert werden und im seriellen Monitor ausgegeben werden. Habe aktuell nur die Motordrehzahl, den Rest bekomme ich irgendwie nicht hin. Vll hat ja jmd. schon einen Code dafür, wenn ja bitte mal reinschicken.

Dann wäre es doch praktisch, wenn Du uns zeigst, was Du hast.

Soundgenerator.ino (1.0 KB)

Das ist mein aktueller Code:)

So kann man ihn direkt lesen :smirk:

#include <CAN.h>
const bool useStandardAddressing = true;

void setup() {
  Serial.begin(9600);

  Serial.println("CAN OBD2 Motordrehzahl");

  // CAN Bus Geschwindigkeit auf 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }

  // Filterung
  if (useStandardAddressing) {
    CAN.filter(0x7e8);
  } else {
    CAN.filterExtended(0x18daf110);
  }
}

void loop() {
  if (useStandardAddressing) {
    CAN.beginPacket(0x7df, 8);
  } else {
    CAN.beginExtendedPacket(0x18db33f1, 8);
  }
  CAN.write(0x02); // Anzahl Bytes
  CAN.write(0x01); // Anzeige aktueller Daten
  CAN.write(0x0c); // Motordrehzahl PID
  CAN.endPacket();

  // warte auf Antwort
  while (CAN.parsePacket() == 0 ||
         CAN.read() < 3 ||          // correct length
         CAN.read() != 0x41 ||      // correct mode
         CAN.read() != 0x0c);       // correct PID

  float rpm = ((CAN.read() * 256.0) + CAN.read()) / 4.0;

  Serial.print("Motordrehzahl = ");
  Serial.println(rpm);

  delay(100);
}

Im Code wird ja auch explizit nur nach der Drehzahl gefragt.

Prinzipiell könnte man den ganzen Teil im loop in verschiedene Funktionen kopieren und dort neben 0x0C auch 0xA4 und 0x0D als PID schreiben.
In der Antwort musst Du dann allerdings darauf achten, die richtige PID zu checken und dass die Längen der Nachrichten unerschiedlich sein werden!

Könnte man auch sauberer mit einem Switch-Case lösen, als mit dem while( or or or).

OBD2 ist nur ein Protokoll, welches nach einem bestimmten Schema Anfragen stellen kann und dann darauf eine Antwort bekommt.
Dahinter steht die technische Übertragungsart. Früher war das gerne eine sog. K-Line und jetzt CAN-Bus.
Da alle Komponenten (Tacho, Steuergeräte, Klima, Taster, usw.) miteinander über den CAN-Bus sprechen, ist da i.d.R. mächtig was los.
Deshalb kann das CAN-Shield Filter setzen und einfach zuhören. Also kein zeitintensives Anfrage-Antwort Spiel. Da sind aber imho die PID´s andere als per OBD2.

Guter Vorschlag, aber ich weiß nicht wie man das genau programmiert, vll könntest du oder wer anders mir da helfen😅

Im Modellbau bin ich übrigens leider nicht fündig geworden😅

Der Datenpin ist übrigens Pin 10😅 Habe den CS-Pin von pin 9 auf pin 10 umgestellt

Und hier die Links zu dem Shield.

https://wiki.seeedstudio.com/CAN-BUS_Shield_V2.0/

Hallo?:sweat_smile:

Bekomme leider keine Antwort mehr:/

Wie Du gelesen hast, habe ich mich mit dem CAN-Bus von Arduino zu Arduino beschäftigt. Aber da ich Dein Auto nicht habe, kann ich schlecht irgendwelche Codes ermitteln, die Dein Auto von sich gibt.

Wie stellst Du Dir eine Hilfe vor?

Ich habe mittlerweile alle möglichen Pids ausgelesen und habe dabei rausgefunden, dass ich bestimmte PIDs nicht auslesen kann.

Unten ist eine Liste der unterstützten PIDs

OBD2 Supported PIDs

00 -> PIDs supported [01 - 20]
01 -> Monitor status since DTCs cleared
03 -> Fuel system status
04 -> Calculated engine load
05 -> Engine coolant temperature
06 -> Short term fuel trim — Bank 1
07 -> Long term fuel trim — Bank 1
0b -> Intake manifold absolute pressure
0c -> Engine RPM
0d -> Vehicle speed
0e -> Timing advance
0f -> Intake air temperature
11 -> Throttle position
13 -> Oxygen sensors present (in 2 banks)
14 -> Oxygen Sensor 1 - Short term fuel trim
15 -> Oxygen Sensor 2 - Short term fuel trim
1c -> OBD standards this vehicle conforms to
1f -> Run time since engine start
20 -> PIDs supported [21 - 40]
21 -> Distance traveled with malfunction indicator lamp (MIL) on
22 -> Fuel Rail Gauge Pressure (diesel, or gasoline direct injection)
2e -> Commanded evaporative purge
2f -> Fuel Tank Level Input
30 -> Warm-ups since codes cleared
31 -> Distance traveled since codes cleared
33 -> Absolute Barometric Pressure
3c -> Catalyst Temperature: Bank 1, Sensor 1
40 -> PIDs supported [41 - 60]
41 -> Monitor status this drive cycle
42 -> Control module voltage
43 -> Absolute load value
44 -> Fuel–Air commanded equivalence ratio
45 -> Relative throttle position
46 -> Ambient air temperature
47 -> Absolute throttle position B
49 -> Absolute throttle position D
4a -> Absolute throttle position E
4c -> Commanded throttle actuator
51 -> Fuel Type
56 -> Long term secondary oxygen sensor trim

Dein Auto gibt Dir doch exakt die unterstützen Werte an.
Dazu gibt es ja die PID 00, 20, 40, 60, 80, A0 & C0.
Als Rückgabe erhälst Du die Bit-Maske die die folgenden 32 PID´s als unterstützt an- oder abhakt.
Oder man testet in einer Schleife alle aus und sieht an den 0x7F Rückgaben was abgelehnt wird.

Aber grundsätzlich ist doch alles dabei, was ich von OBD2 auch erwartet hätte. Der Gang (A4) ist zwar mehr oder weniger offiziell aufgelistet, aber nur Herstellerspezifisch unterstützt.
Habe ehrlich gesagt nicht einmal herausgefunden wie sich der Gang berechnet. Liefere ich in einem Testaufbau 0x01 zurück, zeigt mir CarScan "0" an. Torque kennt den Gang nicht einmal.

Daher meine Idee direkt auf den CAN-Bus zu setzen. CAN ist die Kommunikationsart auf dem Draht. Also wie die Steuergeräte, Sensoren und z.B. der Tacho miteinander sprechen. Da kann man sich quasi als Empfänger melden und alle oder gefiltert Datenströmen lauschen.
OBD2 ist lediglich ein Protokoll, welches über CAN diese normierten Befehle absetzen & empfangen kann.
Also einen Layer weiter hoch gehen und sich die rohen Daten auf dem Bus direkt abgreifen. Dann muss man aber wie gesagt viel rechechieren wie sich diese Daten Herstellerspezifisch zusammensetzen.
Ist aber i.d.R. in zahlreichen Foren schon gut für verschiedenste Fahrzeuge zu finden.

Achso und ich finde bei diesem Google auch massenweise Soundgeneratoren. Sogar mit Schaltgeräusch, usw. Das wird dann aber vermutlich schwierig das zu timen, da der Generator schlicht auf minimal und maximal Geschwindigkeitswerte zu konfigurieren ist und die Schaltpunkte dann vermutlich einfach die Gänge dazwischen aufteilt.

Habe persönlich einfach zu wenig Ahnung wie man ein Geräusch geschwindigkeitsabhängig selbst moduliert. Dazu vermute ich aber Dokumentation im Bereich des Spieledesigns, wenn Du das wirklich selbst machen möchtest.

#include <CAN.h>

// Most cars support 11-bit adddress, others (like Honda),
// require 29-bit (extended) addressing, set the next line
// to true to use extended addressing
const bool useStandardAddressing = true;

void setup() {
  Serial.begin(9600);

  Serial.println("CAN OBD-II engine RPM");

  // start the CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }

  // add filter to only receive the CAN bus ID's we care about
  if (useStandardAddressing) {
    CAN.filter(0x7e8);
  } else {
    CAN.filterExtended(0x18daf110);
  }
}

void loop() {
  if (useStandardAddressing) {
    CAN.beginPacket(0x7df, 8);
  } else {
    CAN.beginExtendedPacket(0x18db33f1, 8);
  }
  CAN.write(0x02); // number of additional bytes
  CAN.write(0x01); // show current data
  CAN.write(0x0d); // vehicle speed
  CAN.endPacket();

  // wait for response
  while (CAN.parsePacket() == 0 ||
         CAN.read() < 2 ||          // correct length
         CAN.read() != 0x41 ||      // correct mode
         CAN.read() != 0x0d);       // correct PID

  float kmh = ((CAN.read()));

  Serial.print("Speed = ");
  Serial.println(kmh);






  
if (useStandardAddressing) {
    CAN.beginPacket(0x7df, 8);
  } else {
    CAN.beginExtendedPacket(0x18db33f1, 8);
  }
  CAN.write(0x02); // number of additional bytes
  CAN.write(0x01); // show current data
  CAN.write(0x0c); // engine rpm
  CAN.endPacket();

  // wait for response
  while (CAN.parsePacket() == 0 ||
         CAN.read() < 3 ||          // correct length
         CAN.read() != 0x41 ||      // correct mode
         CAN.read() != 0x0c);       // correct PID

  float rpm = (((CAN.read())*256)/4);

  Serial.print("Engine RPM = ");
  Serial.println(rpm);
}

Aktuell kann ich schon Geschwindigkeit und Drehzahl auslesen auf den seriellen Monitor:)

Wird doch :slightly_smiling_face:

// Copyright (c) Simon2008
// This Sketch should funkction as an OBD2-Soundgenerator and driving-data-monitor


#include <CAN.h>

// Most cars support 11-bit adddress, others (like Honda),
// require 29-bit (extended) addressing, set the next line
// to true to use extended addressing
const bool useStandardAddressing = true;



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Setup/////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  Serial.begin(9600);

  Serial.println("CAN OBD-II Soundgenerator");

  // start the CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }

  // add filter to only receive the CAN bus ID's we care about
  if (useStandardAddressing) {
    CAN.filter(0x7e8);
  } else {
    CAN.filterExtended(0x18daf110);
  }
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Loop//////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop() {



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//vehicle speed/////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

  if (useStandardAddressing) {
    CAN.beginPacket(0x7df, 8);
  } else {
    CAN.beginExtendedPacket(0x18db33f1, 8);
  }
  CAN.write(0x02); // number of additional bytes
  CAN.write(0x01); // show current data
  CAN.write(0x0d); // vehicle speed
  CAN.endPacket();

  // wait for response
  while (CAN.parsePacket() == 0 ||
         CAN.read() < 2 ||          // correct length
         CAN.read() != 0x41 ||      // correct mode
         CAN.read() != 0x0d);       // correct PID

  float kmh = ((CAN.read()));

  Serial.print("Speed = ");
  Serial.println(kmh);



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//engine speed//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

if (useStandardAddressing) {
    CAN.beginPacket(0x7df, 8);
  } else {
    CAN.beginExtendedPacket(0x18db33f1, 8);
  }
  CAN.write(0x02); // number of additional bytes
  CAN.write(0x01); // show current data
  CAN.write(0x0c); // engine RPM
  CAN.endPacket();

  // wait for response
  while (CAN.parsePacket() == 0 ||
         CAN.read() < 3 ||          // correct length
         CAN.read() != 0x41 ||      // correct mode
         CAN.read() != 0x0c);       // correct PID

  float rpm = (((CAN.read())*256)/4);

  Serial.print("Engine RPM = ");
  Serial.println(rpm);



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//geartranslation///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

  float geartranslation = (rpm / ((kmh) / ((2.001) * 60)));



////////////////////////////////////////////////////////////////////////////////////////////////////////////
//gear//////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

  if (kmh = 0.0)  {
    Serial.println("Gear = N"); 
  }
  else if ((13<(geartranslation)<14.5))  {
    Serial.println("Gear = 1");
  }
  else if ((7<(geartranslation)<8.5))  {
    Serial.println("Gear = 2"); 
  }
  else if ((4.5<(geartranslation)<6))  {
    Serial.println("Gear = 3");
  }
  else if ((3.5<(geartranslation)<4.3))  {
    Serial.println("Gear = 4");
  }
  else if ((3<(geartranslation)<3.3))  {
    Serial.println("Gear = 5");
  }
  else if ((2<(geartranslation)<2.8))  {
    Serial.println("Gear = 6");
  }



delay(500);
}

Hallo, aktuell habe ich das Problem, dass wenn ich den Gang auslesen will, ich immer nur Gear = 1 rausbekomme :confused:

Kann mir da jmd helfen. Ich glaube es liegt am float, aber leider muss ich mit Nachkommastellen wegen der Übersetzungen der Gänge arbeiten.

  1. Gang
    14,087040

  2. Gang
    7,985167

  3. Gang
    5,282640

  4. Gang
    3,923663

  5. Gang
    3,100497

  6. Gang
    2,602591

Ich hoffe, mir kann da jmd bitte helfen

Gruß Simon