Synchrontester für 2-Zylindermotoren

Schon vor Jahren hatte ich mich damit beschäftigt einen Synchrontester zu bauen, dessen Messdaten auf einem PC visualisiert werden können. Das hat mehr oder weniger gut geklappt. Die Geschwindigkeit des 8-Kanal USB-Adapters war damals einfach zu langsam. Etwas enttäuscht habe ich mich damals entschieden die Variante mit den Schläuchen und einer ölgefüllten Flasche zu verwenden. Das funktioniert in gewissen Grenzen auch gut, aber letztendlich bin ich damit nicht ganz zufrieden.

Jetzt gibt es einen neuen Anlauf, da ich ja auch noch viele der benötigten Bauteile von damals in meiner Krabbelkiste liegen habe. Da wären die Druck- bzw. Unterdrucksensoren MPX5100DP und die zugehörigen Kondensatoren. Einen Arduino Nano hab ich auch noch, los geht’s.

Ich habe mich gegen eine Anzeige am Synchrontester entschieden. Die Auswertung soll über den seriellen Plotter in der Arduino IDE erfolgen. Das erscheint mir sehr komfortabel und reduziert den Aufwand erheblich.

Den Schaltplan und das Platinenlayout habe ich wie immer mit EasyEDA erstellt und die Platinen auch schon dort bestellt.

Serieller Plotter in der Arduino IDE

Eine gute Beschreibung gibt es hier.

https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-serial-plotter

17.06.2023 Die Platinen sind da und bestückt

Vor zwei Tagen sind die Platinen angekommen, wie immer schnell und in einer super Qualität.

Platine für Synchrontester.

Platine für 2-Zylinder Synchrontester

Natürlich lässt einem das keine Ruhe und man will dass es weiter geht. Also habe ich die Platinen auch gleich bestückt und siehe da es funktioniert. Getestet hab ich noch nicht am Motorrad, aber mit zwei großen Einwegspritzen. Mir fehlt noch ein T-Stück, dass man auf beiden Drucksensoren den gleichen Unterdruck hat. Mit einer Einwegspritze kommt man fast bis ca. -0,8 Bar, mehr ist schwierig, da man die Spritze nicht richtig halten kann.

2-Zylinder Synchrontester mit Arduino

Der Arduino Code

Falls sich jemand fragt, wo er die „Filter.h“ Bibliothek herbekommt, die gibt es hier (klick!).

/* 
-Synchrontester by Mario Deuse 
 
-V001 
 
*/ 
 
#include "Filter.h" 
  
const int Zyl_1_Pin = A0; 
const int Zyl_2_Pin = A1; 
const int Daempf_Pin = A5; 
 
int Daempfung = 5; 
int Zyl_1 = 0; 
int Zyl_2 = 0; 
 
ExponentialFilter<long> Zyl_1_raw(Daempfung, 0); //je größer der erste Wert umso geringer die Filterung 
ExponentialFilter<long> Zyl_2_raw(Daempfung, 0); 
  
void setup() { 
  
pinMode(Zyl_1_Pin, INPUT); 
pinMode(Zyl_2_Pin, INPUT); 
pinMode(Daempf_Pin, INPUT); 
 
 
Serial.begin(19200); 
 } 
 
void loop() { 

Daempfung = analogRead(Daempf_Pin) / 10; 

Zyl_1_raw.SetWeight(Daempfung);

Zyl_2_raw.SetWeight(Daempfung);

 
Zyl_1_raw.Filter(analogRead(Zyl_1_Pin)); 
Zyl_1 = Zyl_1_raw.Current(); 
 
Zyl_2_raw.Filter(analogRead(Zyl_2_Pin)); 
Zyl_2 = Zyl_2_raw.Current(); 
 
Serial.print("Daempfung:"); 
Serial.print(Daempfung); 
Serial.print(","); 
Serial.print("Zylinder_1:"); 
Serial.print(Zyl_1); 
Serial.print(","); 
Serial.print("Zylinder_2:"); 
Serial.println(Zyl_2); 
 }

Schaltplan kurz erklärt

Also, PS1 und PS2 sind die MPX5100DP Drucksensoren. Zum Datenblatt gehts hier (klick!). Der Sensor ist ein Differenzdruckmesser. Er hat einen Anschluss für Unterdruck und einen für Überdruck. Ich lasse hier den Anschluss für Überdruck offen, da beim Synchronisieren der Unterdruck im Ansaugkanal gemessen wird.

Der Sensor gibt proportional zum Druck/Unterdruck eine Spannung von nominal 0-4,7V aus. Das lässt sich sehr gut mit dem Arduino auswerten. Der Sensor bringt auch eine interne Kalibrierung und eine Temperaturkompensation mit. Prinzipiell ist das egal, da man beim Synchronisieren nur den Unterschied der Zylinder ausgleichen will. Druckwerte spielen da eine untergeordnete Rolle.

Der Ausgang jedes Sensors geht über einen Spindeltrimmer (VR1 & VR2) zu einem Analogeingang des Arduino. Mit den Spindeltrimmern kann man die Sensoren gegenseitig abgleichen, damit die Messwerte bei Umgebungsdruck (nicht am Motor angeschlossen) gleich sind. Über den 3. Spindeltrimmer (VR3) wird die Dämpfung eingestellt. Das ist vergleichbar mit den Einstellschrauben an den allseits bekannten Synchronuhren. Die Kurve wird in der Anzeige im Seriellen Plotter des Arduino träger oder flinker. Das kann man dann einstellen, wie es einem lieber ist.

Die Kondensatoren sind entsprechend der empfohlenen Grundbeschaltung der Sensoren aus dem Datenblatt.

22.06.2023 Kalibrieren und Dämpfung

Hier beträgt der Dämpfungswert 35. Das heißt, dass neue Daten zu 35% in die Berechnung des Durchschnitts herangezogen werden.

Hier beträgt der Dämpfungswert 5. Es gehen nur noch 5% der neuen Daten in die Berechnung des Durchschnitts ein.

Erfolgreiche Synchronisierug

Mittlerweile ist ein wenig Zeit ins Land gegangen und ich komme mal wieder dazu an diesem Projekt weiter zu arbeiten. Bereits im August konnte ich den Synchrontester erfolgreich einsetzen. Das Video zeigt die Synchronisierung meiner Guzzi. Was man sehr gut erkennen kann, ist die Wellenform. Hier wünsche ich mir eher so etwas wie eine gleichmäßige Linie. Das heißt, ich muss weiter an der Datenauswertung arbeiten. Daten stehen reichlich zur Verfügung, sie müssen nur besser Ausgewertet werden. Wenn man nur die Maximalwerte der Wellenkurve zur Visualisierung heranzieht, sollte das besser aussehen.

Das Geheimnis der Limits

Autozoom im Arduino Serial-Plotter nervt. Das kann man einfach umgehen, indem man einen unteren konstanten Wert und einen oberen konstanten Wert zusätzlich sendet. Dann sieht das ganze so aus:

Eine nächste Idee ist, die Limits über ein Poti steuern zu können. So ließe sich an einem Drehknopf in den Graph hinein- bzw herauszoomen. Der Graph wäre dann immer zentriert.

Projektupdate

Die Idee mit dem Zoomen über Potis hat mir keine Ruhe gelassen. Selbstverständlich habe ich mich gleich an die Arbeit gemacht, und eine neue Version meines Synchrontesters ausgearbeitet. Die Bauteile sind schon bei DigiKey bestellt, da es die kleinen SMD Drucksensoren nirgends in DE zu kaufen gibt, wenn man kein Unternehmer ist.

Die neue Variante hat jetzt drei Potis für das untere Level im Serial Plotter, eines für das obere Level und eines für die Einstellung der Dämpfung ähnlich der Überwurfmutter bei den mechanischen Unterdruckuhren.

Ich habe noch eine SPI Schnittstelle für ein Display vorgesehen. Dieses könnte man über einen 8Pin Header anschließen. Wer weiß, vielleicht wird aus dem Projekt ja doch nochmal eine stand-alone Version ohne Arduino Serial Plotter.

Hier der Schaltplan:

3D-Ansicht der Platine:

Der neue Arduino Code sieht nun so aus:

/*
-Synchrontester by Mario Deuse

-V001
-V002
  -ein min. und max. Wert wird zusätzlich an den Serial Plotter gesendet, dadurch wird Autoscale unterbunden

-V003
  - Anpassungen für Hardware Version V002
  - Automatische Kalibrierung der Sensoren nach dem Einschalten des Modules
  - Potis für Low und High Grenzwerte
  - Dämpfung noch kleiner regelbar

*/

#include "Filter.h"



const int Zyl_1_Pin = A0;
const int Zyl_2_Pin = A1;
const int Daempf_Pin = A5;
const int Low_Pin = A2;
const int High_Pin = A3;

long Daempfung = 0.50;
int High = 1000;
int Low = 0;
int Zyl_1 = 0;
int Zyl_2 = 0;
int Low_sum = 0;
int High_sum = 0;
int Low_out = 0;
int High_out = 0;
int i = 0;
int Zyl_1_cal = 0;
int Zyl_2_cal = 0;


ExponentialFilter<long> Zyl_1_raw(Daempfung, 0);  //je größer der erste Wert umso geringer die Filterung
ExponentialFilter<long> Zyl_2_raw(Daempfung, 0);


void setup() {


  pinMode(Zyl_1_Pin, INPUT);
  pinMode(Zyl_2_Pin, INPUT);
  pinMode(Daempf_Pin, INPUT);
  pinMode(Low_Pin, INPUT);
  pinMode(High_Pin, INPUT);


  Serial.begin(115200);

  AutoCal();
}

void loop() {

  Daempfung = analogRead(Daempf_Pin) / 30;

  Zyl_1_raw.SetWeight(Daempfung);
  Zyl_2_raw.SetWeight(Daempfung);

  Zyl_1_raw.Filter(analogRead(Zyl_1_Pin));
  Zyl_1 = Zyl_1_raw.Current();

  Zyl_2_raw.Filter(analogRead(Zyl_2_Pin));
  Zyl_2 = Zyl_2_raw.Current();



  Low = analogRead(Low_Pin);

  High = analogRead(High_Pin);

  if (i <= 50) {
    Low_sum = Low_sum + Low;
    High_sum = High_sum + High;
    i++;
  } else {
    Low_out = Low_sum / 50;
    High_out = High_sum / 50;
    i = 0;
  }




  Serial.print("untere Grenze:");
  Serial.print(Low);
  Serial.print(",");
  Serial.print("obere Grenze:");
  Serial.print(High);
  Serial.print(",");
  Serial.print("Zylinder_1:");
  Serial.print(Zyl_1 - Zyl_1_cal);
  Serial.print(",");
  Serial.print("Zylinder_2:");
  Serial.println(Zyl_2 - Zyl_2_cal);
}



void AutoCal()

{
  for (int i = 0; i <= 500; i++) {
    Zyl_1_raw.Filter(analogRead(Zyl_1_Pin));
    Zyl_1 = Zyl_1_raw.Current();

    Zyl_1_cal = Zyl_1_cal + Zyl_1;

    Zyl_2_raw.Filter(analogRead(Zyl_2_Pin));
    Zyl_2 = Zyl_2_raw.Current();

    Zyl_2_cal = Zyl_2_cal + Zyl_2;

    Serial.println("Automatische Kalibrierung");
  }

  Zyl_1_cal = Zyl_1_cal / 500;
  Zyl_2_cal = Zyl_2_cal / 500;
}

Jetzt ist es passiert,

ich finde die Idee mit dem standalone Gerät so cool, dass ich mich gleich tiefer reingekniet habe. Mit einem TFT Farbdisplay sieht der erste Test schon sehr vielversprechend aus.

Auf dem Bildschirm werden zwei waagerechte Balken dargestellt, welche den jeweiligen Unterdruck repräsentieren. Wenn beide Zylinder synchron laufen, das heißt beide Unterdrücke in einem gewissen Range liegen werden die Balken grün, sonst sind sie rot. Am unteren Rand werden die Unterdruckwerte in Zahlen gezeigt. Weiterhin werden die untere und obere Grenze des angezeigten Bereiches angezeigt. Diese lassen sich später mit je einem Poti einstellen. So kann man in den Messbereich hinein zoomen und die Auflösung der gemessenen Unterdruckwerte erhöhen. Im Video habe ich einen Unterdrucksensor mit einem Potentiometer simuliert. Weiterhin kann später mit einem weiteren Potentiometer die Dämpfung ähnlich der Rändelschrauben an den mechanischen Unterdruckuhren eingestellt werden.

Im CAD angeordnet, kann man schon ahnen wo die Reise hingeht. Jetzt noch ein schickes Gehäuse und es kann weiter gehen.

Ein Gehäuse

So könnte das Gehäuse aussehen. Mal sehen, wie es weiter geht.

Softwareupdate

Die aktuelle Softwareversion 005 bietet nun eine bessere Ablesbarkeit der Balken und mit den Potis kann in den Bereich um die Balken hinein gezoomt werden.

Hier der Code:

/*
-Synchrontester by Mario Deuse

-V001
-V002
  -ein min. und max. Wert wird zusätzlich an den Serial Plotter gesendet, dadurch wird Autoscale unterbunden

-V003
  - Anpassungen für Hardware version V002
  - Automatische Kalibrierung der Sensoren nach dem Einschalten des Modules
  - Potis für Low und High Grenzwerte
  - Dämpfung noch kleiner regelbar

-V004
  - TFT Screen 128x160 hinzugefügt
  - Autocal entfernt

-V005
 - Strich besteht nun aus zwei Linien ur besseren Sichtbarkeit
 - mit den Potis für oberne und unteren Grenzwert kann der Anzeigebereich gezoomt werden

*/

// This examples uses the hardware SPI only. Non-hardware SPI
// is just too slow (~8 times slower!)
#include <Adafruit_GFX.h>     // Core graphics library
#include <Adafruit_QDTech.h>  // Hardware-specific library
#include <SPI.h>
#define sclk 13  // Don't change
#define mosi 11  // Don't change
#define cs 10
#define dc 9
#define rst 8  // you can also connect this to the Arduino reset

#include <Filter.h>

Adafruit_QDTech tft = Adafruit_QDTech(cs, dc, rst);  // Invoke custom library

const int Zyl_1_Pin = A0;
const int Zyl_2_Pin = A1;
const int Daempf_Pin = A4;
const int Low_Pin = A2;
const int High_Pin = A3;

long Daempfung = 0.50;
int High = 1000;
int Low = 0;
int Zyl_1 = 0;
int Zyl_2 = 0;
int Low_alt = 0;
int High_alt = 0;
int Low_out = 0;
int High_out = 0;
int i = 0;
int Zyl_1_cal = 0;
int Zyl_2_cal = 0;
int y1 = 0;
int y2 = 0;
int y1_alt = 0;
int y2_alt = 0;
int Zyl_1_alt = 0;
int Zyl_2_alt = 0;
int Colour;

ExponentialFilter<long> Zyl_1_raw(Daempfung, 0);  //je größer der erste Wert umso geringer die Filterung
ExponentialFilter<long> Zyl_2_raw(Daempfung, 0);

void setup() {

  pinMode(Zyl_1_Pin, INPUT);
  pinMode(Zyl_2_Pin, INPUT);
  pinMode(Daempf_Pin, INPUT);
  pinMode(Low_Pin, INPUT);
  pinMode(High_Pin, INPUT);

  Serial.begin(115200);

  tft.init();

  uint16_t time = millis();
  tft.setRotation(0);  // 0 - Portrait, 1 - Lanscape
  tft.fillScreen(QDTech_WHITE);
  tft.setTextWrap(true);

  delay(200);

  tft.setTextColor(QDTech_BLACK);
  tft.setTextSize(1);
  tft.setCursor(45, 70);
  tft.print("Marios");
  tft.setCursor(33, 85);
  tft.print("Synchrotest");
  tft.drawLine(10, 67, 118, 67, QDTech_RED);
  tft.drawLine(10, 95, 118, 95, QDTech_RED);
  tft.setCursor(8, 150);
  tft.print("Version 001");

  delay(3000);

  tft.fillScreen(QDTech_WHITE);

  tft.setTextColor(QDTech_BLUE);
  tft.setCursor(38, 150);
  tft.print("mBar");
  tft.setCursor(102, 150);
  tft.print("mBar");

  tft.setTextColor(QDTech_BLUE);
  tft.setCursor(4, 150);
  tft.print("-");
  tft.setCursor(68, 150);
  tft.print("-");

  tft.drawLine(64, 15, 64, 135, QDTech_BLACK);
}

void loop() {

  Daempfung = analogRead(Daempf_Pin) / 30;
  if (Daempfung < 1) {
    Daempfung = 1;
  }

  Zyl_1_raw.SetWeight(Daempfung);
  Zyl_2_raw.SetWeight(Daempfung);

  Zyl_1_raw.Filter(analogRead(Zyl_1_Pin));
  Zyl_1 = Zyl_1_raw.Current();

  Zyl_2_raw.Filter(analogRead(Zyl_2_Pin));
  Zyl_2 = Zyl_2_raw.Current();

  Low = analogRead(Low_Pin);
  High = analogRead(High_Pin);
  
  Low = map(Low, 0, 1023, 1023, 0);
  High = map(High, 0, 1023, 1023, 0);

  tft.setTextColor(QDTech_WHITE);
  tft.setTextSize(1);
  tft.setCursor(57, 137);
  tft.print(Low_alt);

  tft.setTextColor(QDTech_BLACK);
  tft.setTextSize(1);
  tft.setCursor(57, 137);
  tft.print(Low);

  Low_alt = Low;

  tft.setTextColor(QDTech_WHITE);
  tft.setTextSize(1);
  tft.setCursor(52, 5);
  tft.print(1023 - High_alt);

  tft.setTextColor(QDTech_BLACK);
  tft.setTextSize(1);
  tft.setCursor(52, 5);
  tft.print(1023 - High);

  High_alt = High;

  y1 = map(Zyl_1, (Low), (1023 - High), 5, 145);

  if (y1 < 11)
   {y1 = 11;}

  y2 = map(Zyl_2, (Low), (1023 - High), 5, 145);

  if (y2 < 11)
   {y2 = 11;}

  if (abs(Zyl_1 - Zyl_2) < 15) {
    Colour = QDTech_GREEN;
  } else {
    Colour = QDTech_RED;
  }

  tft.drawLine(20, (145 - y1_alt), 63, (145 - y1_alt), QDTech_WHITE);
  tft.drawLine(20, (145 - y1_alt - 1), 63, (145 - y1_alt - 1), QDTech_WHITE);
  tft.setTextColor(QDTech_WHITE);
  tft.setTextSize(1);
  tft.setCursor(10, 150);
  tft.print(Zyl_1_alt);

  tft.drawLine(20, (145 - y1), 63, (145 - y1), Colour);
  tft.drawLine(20, (145 - y1 - 1), 63, (145 - y1 - 1), Colour);
  tft.setTextColor(QDTech_BLUE);
  tft.setTextSize(1);
  tft.setCursor(10, 150);
  tft.print(Zyl_1);

  y1_alt = y1;
  Zyl_1_alt = Zyl_1;

  tft.drawLine(65, (145 - y2_alt), 108, (145 - y2_alt), QDTech_WHITE);
   tft.drawLine(65, (145 - y2_alt - 1), 108, (145 - y2_alt - 1), QDTech_WHITE);
  tft.setTextColor(QDTech_WHITE);
  tft.setTextSize(1);
  tft.setCursor(75, 150);
  tft.print(Zyl_2_alt);

  tft.drawLine(65, (145 - y2), 108, (145 - y2), Colour);
  tft.drawLine(65, (145 - y2 - 1), 108, (145 - y2 - 1), Colour);
  tft.setTextColor(QDTech_BLUE);
  tft.setTextSize(1);
  tft.setCursor(75, 150);
  tft.print(Zyl_2);

  y2_alt = y2;
  Zyl_2_alt = Zyl_2;
  
  /*
  Serial.print("untere Grenze:");
  Serial.print(Low);
  Serial.print(", ");
  Serial.print("obere Grenze:");
  Serial.print(High);
  Serial.print(", ");
  Serial.print("Daempfung:");
  Serial.print(Daempfung);
  Serial.print(", ");
  Serial.print("Zylinder_1:");
  Serial.print(Zyl_1);
  Serial.print(", ");
  Serial.print("Zylinder_2:");
  Serial.println(Zyl_2);
  */
}

Display angeschlossen

Heute habe ich das Display n die neue Platine angeschlossen. Es funktioniert, aber es muss eine Anpassung an der Platine vom Display vorgenommen werden. Auf der Rückseite befinden sich zwei Lötpads. Hier kann zwischen 5V oder 3,3V gewählt werden indem diese überbrückt werden. In meinem Fall musste ich dies tun, da ich das Display mit 3,3V betreibe.

Zum einfacheren Verkabeln des Displays habe ich mal zwei Bilder gemacht die mit unterschiedlich farbigen Kabeln alles etwas einfacher machen.

Anschlusskabel an der Hauptplatine

Anschluss am Display.

Eine Sache noch. Die Bedienung der oberen Grenze beim „Hineinzoomen“ ist etwas unglücklich, da das Poti falschherum funktioniert. Das wird noch geändert. Wenn ich das getestet habe poste ich hier die zu ändernde Codezeile.

Fortsetzung folgt!

Falls es jemand nachbauen möchte:

Project Homepage with Schematic and PCB

Arduino Code Synchrontester_V006

Hinterlasse einen Kommentar