Mittelwertbildung.... Oder doch was anderes?

Ich hatte ein funktionierendes Programm, nun hab ich einiges umgeschrieben und mitmal geht eine grundlegende Funktion nicht mehr und es liegt meiner Meinung nach vermutlich an der Mittelwertbildung, die (meine ich) vorher genauso ging....

Manchmal gibt er merkwürdigerweise 0 zurück statt den gemittelten Messwert.

Anmerkung:
MinSens ist 0 MaxSens 1023 definiert aktuell weil ich das momentan nicht nutze. Die Messwerte liegen bei 600-700 (getestet). SensReadTimes ist aktuell 50.

int ReadSens(int SensorNr) {
  int Mittelwert = 0;
  for (int i = 0; i < SensReadTimes; i++) {                                                                         // Mittelwert aus Messungen bilden
    delay(0.3);
    Mittelwert = Mittelwert + analogRead(Sens[SensorNr]);
  }
  Mittelwert = Mittelwert / SensReadTimes;
  Mittelwert = map(Mittelwert, 0, 1023, 1023, 0);                                                                   // Wert umdrehen wegen Kapazitiven Sensoren
  if (Mittelwert >= MinCalib && Mittelwert <= MaxCalib) {                                                           // Wenn kein Sensorfehler
    SaveData(SensorNr, Mittelwert);                                                                                 // Sensordaten speichern
    return Mittelwert;
  }
  else {                                                                                                            // Wenn Sensorfehler 0 zurück geben (Error wird in ReadPots gesetzt damit Calib ohne ErrorLED geht)
    return 0;
  }
}

Sicherheitshalber falls ich nen Denkfehler gemacht habe und der Fehler doch woanders liegt hier nochmal alles was dazu gehört....

Manchmal macht CalibrateSens die LED an und beim nächsten Tastendruck wieder aus.
Bei Sensor 2 (Sens[1]) geht sie nie an. Die Tasten-Funktion scheint laut meinem Test vernünftig zu gehen.
Das Aus/An kann nur am Rückgabewert liegen (da steht auch entsprechend wie bei dem Serial.print immer 0 oder ein Messwert beim ersten Sensor (Sens[0]), aber immer 0 beim Zweiten (Sens[1])

#define LEDon 1              // LED an muss HIGH sein
#define LEDoff 0             // LED aus muss LOW sein
#define ButtonPressed 0      // Gedrueckt = LOW
#define ButtonOFF 1          // Nicht gedrueckt = HIGH


const int CalibButton = 9;                                // Button Pin definieren
const int SensReadTimes = 50;
const int AnzSensors = 2;
bool EE_Enable = 0;
const int MinCalib = 0;                                   // Mindest Messwert Sensor (Fehlerschwelle)
const int MaxCalib = 1023;                                // Maximum Messwert Sensor (Fehlerschwelle)

// Datenstrukturen erstellen
struct Sensoren {
  int Calib = 0;                                          // Kalibrationswert
  int StartWetness = 0;                                   // Letzter Messwert vor giessen
  byte SensErr = 0;                                       // Sensorfehlercounter
  bool NeedWater = 0;                                     // Giessen benoetigt flag
  bool PumpOn = 0;                                        // Pumpe an flag
  unsigned long MessTimer = 0;                            // Messabstand Timer
  unsigned long SensLEDTimer = 0;                         // Sens LED Timer
  unsigned long PumpLEDTimer = 0;                         // Pump LED Timer
  int DataWriteAddress = 0;                               // Daten Schreibadresse Sensors
  int SensData[RecordingSize];                            // Daten des Sensors
};
Sensoren Sensor[AnzSensors];  
               
void setup() {
  Serial.begin(115200);

  pinMode(CalibButton, INPUT_PULLUP);                    // gedrueckt, wenn LOW

  // Pumpen und LED's Status definieren und aus, Timer starten
  for (int i = 0; i < AnzSensors; i++) {
    pinMode(Sens[i], INPUT);
    pinMode(Pump[i], OUTPUT);
    pinMode(SensLED[i], OUTPUT);
    digitalWrite(Pump[i], LOW);
    digitalWrite(SensLED[i], LEDoff);
  }
}

void loop() {
  if (ReadCalibButton() == 1) {
    CalibrateAll();
  }
  Serial.print(Sensor[0].Calib);
  Serial.print(" ");
  Serial.println(Sensor[1].Calib);
  delay(200);
}


bool ReadCalibButton() {
  bool ButtonReading = digitalRead(CalibButton);                                                                    // Button auslesen
  if (ButtonReading != LastButtonStatus) {                                                                          // Wenn Button noch bounced resette debounce timer
    DebounceTimer = millis();
  }
  if (millis() - DebounceTimer > DebounceTime) {                                                                    // Wenn debounced auslesen
    if (ButtonReading != ButtonStatus) {                                                                            // Wenn sich der Status geaendert hat
      ButtonStatus = ButtonReading;
      if (ButtonReading == ButtonOFF) {                                                                             // Wenn der neue Status losgelassen ist Kalibration aufnehmen und ins EEpronm schreiben
        LastButtonStatus = ButtonReading;
        return 1;                                                                                                   // Wenn derKalibrationstaster losgelassen wurde 1 zurueckgeben um Daten zu speichern
      }
    }
  }
  LastButtonStatus = ButtonReading;
  return 0;
}

void CalibrateAll() {
  for (int i = 0; i < AnzSensors; i++) {
    CalibrateSens(i);
  }
}

int CalibrateSens(int SensorNr) {
  digitalWrite(Pump[SensorNr], LOW);                                                                                // Pumpe aus
  Sensor[SensorNr].MessTimer = millis();                                                                            // Messtimer resetten
  int Messwert = ReadSens(SensorNr);                                                                                // Calibwert einlesen
  if (Messwert != 0) {                                                                                              // Wenn kein Sensorfehler
    Sensor[SensorNr].StartWetness = 0;
    Sensor[SensorNr].SensErr = 0;
    Err = 0;
    digitalWrite(ErrorLED, RGBoff);
    digitalWrite(SensLED[SensorNr], LEDon);
    Messwert = Messwert - ADC_Differenz;                                                                            // Kalibration veringern, damit nicht gleich gegossen wird, wenn Messwert minimal schwankt
    SaveCalib(SensorNr, Messwert);                                                                                  // Calib Daten speichern
    return Messwert;
  }
  else {                                                                                                            // Wenn Sensorfehler
    SaveCalib(SensorNr, 0);
    digitalWrite(SensLED[SensorNr], LEDoff);
    return 0;
  }
}

int ReadSens(int SensorNr) {
  int Mittelwert = 0;
  for (int i = 0; i < SensReadTimes; i++) {                                                                         // Mittelwert aus Messungen bilden
    delay(0.3);
    Mittelwert = Mittelwert + analogRead(Sens[SensorNr]);
  }
  Mittelwert = Mittelwert / SensReadTimes;
  Mittelwert = map(Mittelwert, 0, 1023, 1023, 0);                                                                   // Wert umdrehen wegen Kapazitiven Sensoren
  if (Mittelwert >= MinCalib && Mittelwert <= MaxCalib) {                                                           // Wenn kein Sensorfehler
    SaveData(SensorNr, Mittelwert);                                                                                 // Sensordaten speichern
    return Mittelwert;
  }
  else {                                                                                                            // Wenn Sensorfehler 0 zurück geben (Error wird in ReadPots gesetzt damit Calib ohne ErrorLED geht)
    return 0;
  }
}

void SaveCalib(int SensorNr, int Calibwert) {
  if (EE_Enable == 1 && SensorNr == 0) {
    for (int i = EEData; i < EEPROM.length(); i++) {                                                                                        // EEProm Datenbereich loeschen
      EEPROM.update(i, 0);
    }
    EEPROM.update(EECalib, map(Calibwert, Calibwert - EEMapSpan, Calibwert + EEMapSpan, 0, 255));                                           // Mappe Kalibration um den Calibwert-Bereich auf 256 und schreibe in EEProm Speicher fuer Kalibration
    EE_Rec_Enable = 1;                                                                                                                      // Aufzeichnung wieder aktivieren - Wird deaktiviert durch Savedata()
  }
  else if (EE_Enable == 0) {
    for (int i = 0; i < RecordingSize; i++) {                                                                                               // Datenbereich loeschen
      SaveData(Sensor[SensorNr].SensData[i], 0);
    }
    Sensor[SensorNr].Calib = Calibwert;                                                                                                     // Schreibe Kalibration in Datenbereich
    Rec_Enable = 1;                                                                                                                         // Aufzeichnung wieder aktivieren - Wird deaktiviert durch Savedata()
  }
}

Edit:
Noch einiges hinzugefügt. Ich hoffe ich hab jetzt nichts wichtiges vergessen....

delay(0.3); funktioniert? delay unterstützt kein Float, sondern nur Ganzzahlen, kommt da wahrscheinlich auf delay(0); hinaus, dadurch ist vielleicht der Zeitabstand der analogen Messungen zu klein (gleich 0 ms)?!

wenn Du kürzere Wartezeiten brauchst verwende delaymicroseconds()

Das hatte ich auch schon im alten script und hat wunderbar funktioniert. man hat auch gesehen, wenn ich weniger als 100ms gemacht hatte war der gelesene Wert falsch, ab 300ms war er ok.

Ich hab eben nochmal was hinzugefügt im 2. Post und Code

Edit: Ich werds ändern, aber das kann eigentlich nichts damit zu tun haben, da es ging und dann müsste er ja zumindest irgendwas anzeigen statt 0

Gorkde:
Das hatte ich auch schon im alten script und hat wunderbar funktioniert. man hat auch gesehen, wenn ich weniger als 100ms gemacht hatte war der gelesene Wert falsch, ab 300ms war er ok.

Wenn du eine Verzögerung von 200 oder 300 ms brauchst, dann schreib delay(200); oder delay(300);

Kann ja sein, dass es den eigentlichen Fehler nicht behebt, ist mir aber eben aufgefallen :wink:

wapjoe:
Wenn du eine Verzögerung von 200 oder 300 ms brauchst, dann schreib delay(200); oder delay(300);

Kann ja sein, dass es den eigentlichen Fehler nicht behebt, ist mir aber eben aufgefallen :wink:

Ich meinte "us", nicht "ms". Und danke für den Tip, dachte es geht so, weil man am Messwert gesehen hatte das es ging.

Gorkde:
Ich meinte "us", nicht "ms". Und danke für den Tip, dachte es geht so, weil man am Messwert gesehen hatte das es ging.

Ok, dann lass dir doch mal den Wert von analogRead(Sens[SensorNr]) seriell ausgeben. Kannst du einen Defekt des Sensors ausschließen?

wapjoe:
Ok, dann lass dir doch mal den Wert von analogRead(Sens[SensorNr]) seriell ausgeben. Kannst du einen Defekt des Sensors ausschließen?

Ja, wie gesagt beide geben den Wert raus der normal ist, so ca 600-700.
Da muss irgendwas in der ReadSens oder der Calib Funktion sein, weshalb er statt dem Messwert 0 zurück gibt.

Ich hab ja auch alle Funktionen umgeschrieben, weil ich jetzt die Struktur benutze und die Sensoren als Array habe, aber ich sehe da keinen Fehler.

Es kann doch nicht so schwierig sein, in die Funktion ein paar Kontrollausgaben ein zu bauen.

Außerdem sind die Funktionen auf Papier durchspielbar.
Dann sieht man doch GENAU was passiert.

Aber ich kann dir schon eins sagen, was mich stört:

Mittelwert = Mittelwert + analogRead(Sens[SensorNr]);

Würde ich auf jeden Fall eher so schreiben:

summe += analogRead(Sens[SensorNr]);

Warum?

  1. kürzer.
  2. es ist an der Stelle eine Summe, und noch lange kein Mittelwert.
  3. summe ist eine Variable, beginnt also mit einem Kleinbuchstaben.

Logisch und konsequent folgt daraus:

Mittelwert = Mittelwert / SensReadTimes; // unschön

mittelwert = summe / SensReadTimes; // besser
Der Grund:
Wenn Variablen während des Programmlaufs ihre Bedeutung ändern, dann hat man einen excellenten Weg gefunden sich selber zu verwirren und sich dabei Frikadellen ans Knie zu nageln.

Am Rande.
Dein geposteter Code kompiliert nicht.
Ist also untestbar.

sketch_aug12b:27:16: error: 'RecordingSize' was not declared in this scope
   27 |   int SensData[RecordingSize];                            // Daten des Sensors
      |                ^~~~~~~~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_aug12b\sketch_aug12b.ino: In function 'void setup()':
sketch_aug12b:38:13: error: 'Sens' was not declared in this scope; did you mean 'Sensor'?
   38 |     pinMode(Sens[i], INPUT);
      |             ^~~~
      |             Sensor
sketch_aug12b:39:13: error: 'Pump' was not declared in this scope
   39 |     pinMode(Pump[i], OUTPUT);
      |             ^~~~
sketch_aug12b:40:13: error: 'SensLED' was not declared in this scope
   40 |     pinMode(SensLED[i], OUTPUT);
      |             ^~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_aug12b\sketch_aug12b.ino: In function 'bool ReadCalibButton()':
sketch_aug12b:59:24: error: 'LastButtonStatus' was not declared in this scope
   59 |   if (ButtonReading != LastButtonStatus) {                                                                          // Wenn Button noch bounced resette debounce timer
      |                        ^~~~~~~~~~~~~~~~
sketch_aug12b:60:5: error: 'DebounceTimer' was not declared in this scope
   60 |     DebounceTimer = millis();
      |     ^~~~~~~~~~~~~
sketch_aug12b:62:18: error: 'DebounceTimer' was not declared in this scope
   62 |   if (millis() - DebounceTimer > DebounceTime) {                                                                    // Wenn debounced auslesen
      |                  ^~~~~~~~~~~~~
sketch_aug12b:62:34: error: 'DebounceTime' was not declared in this scope
   62 |   if (millis() - DebounceTimer > DebounceTime) {                                                                    // Wenn debounced auslesen
      |                                  ^~~~~~~~~~~~
sketch_aug12b:63:26: error: 'ButtonStatus' was not declared in this scope
   63 |     if (ButtonReading != ButtonStatus) {                                                                            // Wenn sich der Status geaendert hat
      |                          ^~~~~~~~~~~~
sketch_aug12b:66:9: error: 'LastButtonStatus' was not declared in this scope
   66 |         LastButtonStatus = ButtonReading;
      |         ^~~~~~~~~~~~~~~~
sketch_aug12b:71:3: error: 'LastButtonStatus' was not declared in this scope
   71 |   LastButtonStatus = ButtonReading;
      |   ^~~~~~~~~~~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_aug12b\sketch_aug12b.ino: In function 'int CalibrateSens(int)':
sketch_aug12b:82:16: error: 'Pump' was not declared in this scope
   82 |   digitalWrite(Pump[SensorNr], LOW);                                                                                // Pumpe aus
      |                ^~~~
sketch_aug12b:88:5: error: 'Err' was not declared in this scope
   88 |     Err = 0;
      |     ^~~
sketch_aug12b:89:18: error: 'ErrorLED' was not declared in this scope
   89 |     digitalWrite(ErrorLED, RGBoff);
      |                  ^~~~~~~~
sketch_aug12b:89:28: error: 'RGBoff' was not declared in this scope
   89 |     digitalWrite(ErrorLED, RGBoff);
      |                            ^~~~~~
sketch_aug12b:90:18: error: 'SensLED' was not declared in this scope
   90 |     digitalWrite(SensLED[SensorNr], LEDon);
      |                  ^~~~~~~
sketch_aug12b:91:27: error: 'ADC_Differenz' was not declared in this scope
   91 |     Messwert = Messwert - ADC_Differenz;                                                                            // Kalibration veringern, damit nicht gleich gegossen wird, wenn Messwert minimal schwankt
      |                           ^~~~~~~~~~~~~
sketch_aug12b:97:18: error: 'SensLED' was not declared in this scope
   97 |     digitalWrite(SensLED[SensorNr], LEDoff);
      |                  ^~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_aug12b\sketch_aug12b.ino: In function 'int ReadSens(int)':
sketch_aug12b:106:42: error: 'Sens' was not declared in this scope; did you mean 'Sensor'?
  106 |     Mittelwert = Mittelwert + analogRead(Sens[SensorNr]);
      |                                          ^~~~
      |                                          Sensor
sketch_aug12b:111:5: error: 'SaveData' was not declared in this scope
  111 |     SaveData(SensorNr, Mittelwert);                                                                                 // Sensordaten speichern
      |     ^~~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_aug12b\sketch_aug12b.ino: In function 'void SaveCalib(int, int)':
sketch_aug12b:121:18: error: 'EEData' was not declared in this scope
  121 |     for (int i = EEData; i < EEPROM.length(); i++) {                                                                                        // EEProm Datenbereich loeschen
      |                  ^~~~~~
sketch_aug12b:121:30: error: 'EEPROM' was not declared in this scope
  121 |     for (int i = EEData; i < EEPROM.length(); i++) {                                                                                        // EEProm Datenbereich loeschen
      |                              ^~~~~~
sketch_aug12b:124:5: error: 'EEPROM' was not declared in this scope
  124 |     EEPROM.update(EECalib, map(Calibwert, Calibwert - EEMapSpan, Calibwert + EEMapSpan, 0, 255));                                           // Mappe Kalibration um den Calibwert-Bereich auf 256 und schreibe in EEProm Speicher fuer Kalibration
      |     ^~~~~~
sketch_aug12b:124:19: error: 'EECalib' was not declared in this scope
  124 |     EEPROM.update(EECalib, map(Calibwert, Calibwert - EEMapSpan, Calibwert + EEMapSpan, 0, 255));                                           // Mappe Kalibration um den Calibwert-Bereich auf 256 und schreibe in EEProm Speicher fuer Kalibration
      |                   ^~~~~~~
sketch_aug12b:124:55: error: 'EEMapSpan' was not declared in this scope
  124 |     EEPROM.update(EECalib, map(Calibwert, Calibwert - EEMapSpan, Calibwert + EEMapSpan, 0, 255));                                           // Mappe Kalibration um den Calibwert-Bereich auf 256 und schreibe in EEProm Speicher fuer Kalibration
      |                                                       ^~~~~~~~~
sketch_aug12b:125:5: error: 'EE_Rec_Enable' was not declared in this scope; did you mean 'EE_Enable'?
  125 |     EE_Rec_Enable = 1;                                                                                                                      // Aufzeichnung wieder aktivieren - Wird deaktiviert durch Savedata()
      |     ^~~~~~~~~~~~~
      |     EE_Enable
sketch_aug12b:128:25: error: 'RecordingSize' was not declared in this scope
  128 |     for (int i = 0; i < RecordingSize; i++) {                                                                                               // Datenbereich loeschen
      |                         ^~~~~~~~~~~~~
sketch_aug12b:129:33: error: 'struct Sensoren' has no member named 'SensData'
  129 |       SaveData(Sensor[SensorNr].SensData[i], 0);
      |                                 ^~~~~~~~
sketch_aug12b:129:7: error: 'SaveData' was not declared in this scope
  129 |       SaveData(Sensor[SensorNr].SensData[i], 0);
      |       ^~~~~~~~
sketch_aug12b:132:5: error: 'Rec_Enable' was not declared in this scope; did you mean 'EE_Enable'?
  132 |     Rec_Enable = 1;                                                                                                                         // Aufzeichnung wieder aktivieren - Wird deaktiviert durch Savedata()
      |     ^~~~~~~~~~
      |     EE_Enable
exit status 1
'RecordingSize' was not declared in this scope

Testest du selber überhaupt, was du hier zeigst?

Sicher teste ich, da bin ich bei nach dem umschreiben, daher habe ich ja den Fehler gefunden und suche die Ursache.

Das sind wie gesagt die Teile des Programms, welche mit dem Fehler zu tun haben und nicht das ganze Programm

Ansonsten braucht man ja noch all die Speicher, Gießroutinen etc.
Das verwirrt doch mehr, als wenn ich gleich nur die relevanten Bereiche posten oder?

Ich kann gern nachher das ganze posten, aber jetzt nach dem Umschreiben auf struct enthält es sicher noch weitere Fehler.

Wie gesagt, dass der Programmcode sicher nicht optimal von der Programmierweise ist und ein erfahrener Programmierer das besser schreiben könnte ist klar, aber ich will es erstmal überhaupt zum laufen kriegen (wegen Eisbaden und so).

Man postet einen kompilierbaren Sketch, in dem das Problem auftritt und alles andere rausgenommen ist.

Wenn man den Sketch auf den fehlerhaften Teil reduziert, springt einem der Fehler meist direkt ins Gesicht.

Wenn er dich nicht direkt anspringt, mach den Rubberduck Test, am besten mit deiner Oma/Freundin/Nachbarin, egal mit wem , eben halt mit jemand der davon keine Ahnung hat.

Bitte begründe nicht, "warum" du irgendwas falsch machst.
Du behinderst damit deine Entwicklung (auch die deines Programms) und frustrierst die Helfer(z.B. mich)
Auf Vorschläge/Kritik mit Rechtfertigung zu reagieren zeigt eher, dass du das nicht ändern willst.

Punkt 1:
Wenn du untestbaren Code postest, dann ist der Code untestbar.
Untestbarer Code erschwert die testbarkeit und damit die Fehlersuche ungemein.
Bis zur Unmöglichkeit.
Ist das in deiner Absicht?

Punkt 2:

Ansonsten braucht man ja noch all die Speicher, Gießroutinen etc.
Das verwirrt doch mehr, als wenn ich gleich nur die relevanten Bereiche posten oder?
Zerhacke den Code in einzeln testbare Teile.
Dann kannst du diese Teile einzeln testen.
Ich behaupte:
Wenn du, mit Fug und Recht, wüsstest, was "relevant" ist, dann hättest du den Fehler schon längst gefunden.

Punkt 3:
Schaffe Übersicht!
Begrenze globale Variablen auf ein Minimum.
Befreie deine Funktionen von globalen Abhängigkeiten.

Punkt 4:
Achte auf deine Datentypen!
Ich zeige dir mal was ich meine:

Die Messwerte liegen bei 600-700
const int SensReadTimes = 50;
int Mittelwert = 0;
700*50= 35000
Passt das in ein int?
Das ist z.B. ein Punkt, welchen du, durch Tests und Kontrollausgaben, sehr gut hättest selber herausfinden können.
Wenn man die falschen Datentypen verwendet, denke ich mal, darf man sich nicht wundern, wenn die Rechenergebnisse nicht den Erwartungen entsprechen.
Entweder ist an der Stelle die Erwartung falsch, oder die Rechnung.

Tipp:
Der ADC kann Werte bis 1023 liefern.
Also muss der Datentype Zahlen bis 1023*50 aufnehmen können, sonst drohen unerwartete Rechenergebnisse.


aber ich will es erstmal überhaupt zum laufen kriegen

Ich rate zu einer langsamen und sorgfältigen Vorgehensweise.

An dieser Stelle mal ein Merksatz:

Wer in die falsche Richtung läuft, braucht sich nicht zu beeilen.

Danke, das ist mir nicht aufgefallen. Komischerweise hat es vorher mit genau der selben Mittelwertbildung funktioniert. Vielleicht war das Zufall.

Danke, das ist mir nicht aufgefallen.

Gerne doch!
Und dass dir das nicht aufgefallen ist, bedeutet doch, dass du da noch gar nicht "denkend" hin geschaut hast.
Dass mir das SOFORT auffällt, liegt daran, dass meine Sinne in dem Punkt recht "scharf" justiert sind.

Komischerweise hat es vorher mit genau der selben Mittelwertbildung funktioniert.

Diese Argumentation solltest du dir selber untersagen.
Denn sie verhindert, dass du da genauer hinschaust.
Sie erschwert dir die Fehlersuche, und das völlig ohne Not.
Und die anderen Mitleser lenkt es auch ab, denn man könnte vermuten, dass du die Funktion getestet hast.

und es liegt meiner Meinung nach vermutlich an der Mittelwertbildung, die (meine ich) vorher genauso ging....

Wenn eine Funktion nur manchmal richtig tut, dann ist sie als kaputt anzusehen.
Da muss man nicht "das tats aber mal" predigen.
Damit kann man sich selber überzeugen und behindern, aber den Fehler behebt es nicht.

Ich meinte ja nur im alten Sketch hatte ich sie so drin, getestet und es lief ohne Probleme, daher ist mir der Fehler nicht aufgefallen.

Dass deine Sinne geschärft sind für sowas liegt sicher daran, dass Du das dauernd machst seit Jahren.

Das ist das selbe wie = / == bei if. Als Anfänger sieht man den Fehler nicht, wenn man aber schon 20x den Fehler gemacht und gesucht hat fällt es einem später sofort auf.

Ich meinte ja nur im alten Sketch hatte ich sie so drin, getestet und es lief ohne Probleme, daher ist mir der Fehler nicht aufgefallen.

Tipp:
Man testet Funktionen nicht in der Anwendung.
Sondern einzeln!
Man lotet die Grenzen aus.
Und diese dokumentiert man dann.

Das ist das selbe wie = / == bei if. Als Anfänger sieht man den Fehler nicht, wenn man aber schon 20x den Fehler gemacht und gesucht hat fällt es einem später sofort auf.

Dann hast du die Warnungen nicht aktiviert!
Sich selber zu blenden ist kein gültiges Argument.

Dass deine Sinne geschärft sind für sowas liegt sicher daran, dass Du das dauernd machst seit Jahren.

Ich sagte schon:

Bitte begründe nicht, "warum" du irgendwas falsch machst.
Du behinderst damit deine Entwicklung (auch die deines Programms) und frustrierst die Helfer(z.B. mich)
Auf Vorschläge/Kritik mit Rechtfertigung zu reagieren zeigt eher, dass du das nicht ändern willst.

Diese Art der Argumentation/Rechtfertigung/Begründung hilft dir nicht aufs Pferd.
Du blockierst dich selber in deinem Lernverhalten damit.

Beispiel:
Ich sage:

Dass mir das SOFORT auffällt, liegt daran, dass meine Sinne in dem Punkt recht "scharf" justiert sind.

Du könntest denken:

Ja, das ist eine gute Idee! Ich werde auch meine Sinne daraufhin schärfen.

Aber du sagst (frei übersetzt):

Klar, dass ich das nicht kann, denn der Combie hat viel mehr Erfahrung.
Schon bist du der positiven, Lösungsorientierten, Ausrichtung des Denkens entkommen.
Und ich bin mir recht sicher, dass du das doch gar nicht willst.