Gießanlage - Code macht Probleme

Hallo Allerseits !

Zu allererst : ich bin blutiger Anfänger, also erwartet nicht zu viel !

Zu meinem Problem: Bin gerade dabei mir eine Gießanlage für ein paar Pflanzen zu bauen. Das Gehirn bildet ein Arduino Nano. Alle fünf Sekunden wird aus 5 Messwerten ein Mittelwert errechnet und dann auf eine SD-Karte geschrieben. Ist die Feuchtigkeit kleiner als 60% soll an Pin 2 ein Relais geschaltet werden, welches wiederrum eine Wasserpumpe in gang bringt.

Das ganze habe ich auch schon soweit verkabelt und geschrieben. Nur will das irgendwie nicht richtig… Die eingestellten Zeiten stimmen auf einmal überhaupt nicht mehr und die Pumpe fängt an im Dauerbetrieb zu laufen.
Könntet ihr evtl mal über den Sketch drüberschauen ob euch Probleme auffallen ?

Vielen Dank sschonmal !

#define Data A0
#include <SD.h>
int analogPin = 1;
int var;
int vari;
float SensorValue = 0;
float feuchtigkeit = 0;
float feucht[5];
const int chipSelect = 9;

void setup()
{
Serial.begin(9600);
pinMode(A0, INPUT);
Serial.print(“Initializing SD card…”);
pinMode(2,OUTPUT);
pinMode(10, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println(“Card failed, or not present”);
return;
}
Serial.println(“card initialized.”);
}

void loop()
{
SensorValue = analogRead(Data);

feucht[1] = analogRead(Data);
delay(1000);
feucht[2] = analogRead(Data);
delay(1000);
feucht[3] = analogRead(Data);
delay(1000);
feucht[4] = analogRead(Data);
delay(1000);
feucht[5] = analogRead(Data);

feuchtigkeit = (feucht[1] + feucht[2] + feucht[3] + feucht[4] + feucht[5])/5;

var = feuchtigkeit;
vari = (100-((100/1023.0)*feuchtigkeit));

Serial.print(“Bodenfeuchte: “);
Serial.print(vari);
Serial.println(” %”);
Serial.println(var);

if(vari < 60)
{digitalWrite(2,HIGH);
delay(5000);
digitalWrite(2, LOW);
}
{ var = analogRead(Data);
vari = (100-((100/1023.0)*var));

File dataFile = SD.open(“datalog.txt”, FILE_WRITE);

if (dataFile) {
dataFile.println(var);
dataFile.close();
}
}
delay(1000);

}

float feucht[5];
...
feuchtigkeit = (feucht[1] + feucht[2] + feucht[3] + feucht[4] + feucht[5])/5;

Dein Feld geht von feucht[0] bis feucht[4], daher gibt es feucht[5] nicht.

Grudsätzliches "Problem" bzw. Gedankenfehler deiner Lösung: "Alle fünf Sekunden wird aus 5 Messwerten ein Mittelwert errechnet und dann auf eine SD-Karte geschrieben. Ist die Feuchtigkeit kleiner als 60% soll an Pin 2 ein Relais geschaltet werden, welches wiederrum eine Wasserpumpe in gang bringt.".

Du misst wirklich jede 5 Sekunden die Feuchtigkeit von der Erde um zu ermitteln, ob die Pflanze Wasser braucht? Keine Ahnung was für Pflanzen du da hast und ob du die dafür extra auf ne Heizung gestellt hast - aber das wäre nicht mal ein Interval was ich für die Temperatur+Luftfeuchtigkeit bei einer Wetterstation nehmen würde. Eine normale Zimmerpflanze bekommt bei mir jede 5-8 Tage einen Schluck wasser. Das sind also mind. 100 Stunden zwischen Gießvergängen. Wenn du jetzt jede 12 Stunden - also zwei mal am Tag - die Feuchtigkeit messen würdest, wird keiner Pflanze etwas passieren. Reichen würde es jede 24 Stunden. Außer die Pflanzen stecken in Fingerhüten auf einer Heizung. Dann brauchen diese ggf. täglich etwas Wasser ;)

Zwei Sachen die mir noch auffielen:

  • Wiederholungen kann man sehr eleganz und übersichtlich mit Schleifen lösen :slight_smile:
  • “/ 5” = Interger bzw. Ganzzahl. Da es sich eindeutig um Float/Double handelt, musst du “/ 5.0” teilen

for(int i;i++;i<4)
{
feucht = analogRead(Data);

  • SumFeucht += feucht*
    * delay(1000);*
    }
    feuchtigkeit = SumFeucht / 5.0;

AlphaRay: Grudsätzliches "Problem" bzw. Gedankenfehler deiner Lösung: "Alle fünf Sekunden wird aus 5 Messwerten ein Mittelwert errechnet und dann auf eine SD-Karte geschrieben. Ist die Feuchtigkeit kleiner als 60% soll an Pin 2 ein Relais geschaltet werden, welches wiederrum eine Wasserpumpe in gang bringt.".

Du misst wirklich jede 5 Sekunden die Feuchtigkeit von der Erde um zu ermitteln, ob die Pflanze Wasser braucht? Keine Ahnung was für Pflanzen du da hast und ob du die dafür extra auf ne Heizung gestellt hast - aber das wäre nicht mal ein Interval was ich für die Temperatur+Luftfeuchtigkeit bei einer Wetterstation nehmen würde. Eine normale Zimmerpflanze bekommt bei mir jede 5-8 Tage einen Schluck wasser. Das sind also mind. 100 Stunden zwischen Gießvergängen. Wenn du jetzt jede 12 Stunden - also zwei mal am Tag - die Feuchtigkeit messen würdest, wird keiner Pflanze etwas passieren. Reichen würde es jede 24 Stunden. Außer die Pflanzen stecken in Fingerhüten auf einer Heizung. Dann brauchen diese ggf. täglich etwas Wasser ;)

Das mit den 5 Sekunden war eher zu testzwecken, auf lange Sicht wird es ein sehr viel längerer Zeitraum sein. :)

agmue: float feucht[5]; ... feuchtigkeit = (feucht[1] + feucht[2] + feucht[3] + feucht[4] + feucht[5])/5;

Dein Feld geht von feucht[0] bis feucht[4], daher gibt es feucht[5] nicht.

Also sollte das deiner Meinung nach so aussehen ? :

float feucht[4];
...
feuchtigkeit = (feucht[0] + feucht[1] + feucht[2] + feucht[3] + feucht[4])/5.0;

[4] = 0, 1, 2 und 3 :) Musst das schon bei [5] lassen. Und wenn du das mit der Schleife machst, wie von mir vorgeschlagen, dann fällt die Zeile sowieso kürzer aus. Hatte das in der Schleife schon als SumFeucht drin :)

Dein Script macht genau was du sagst.

Wenn die feuchtigkeit unter 60 dann giessen. Nur steigt die Feuchtigkeit dann ja nicht sofort an. Und daher läuft das dann etwas länger.

Dein Code ist auch grausam zu lesen, da du variablen doppelt benutzt. Zuerst wird die Variable vari errechnet, verglichen, Pumpe ausgelöst bei bedarf, dann die vari neu berechnet direkt aus dem Analogwert (ohne 5x aufzusummieren) und dieser Inhalt auf die SD-Karte geschrieben.

Keine Kommentare was du in den jeweiligen Zeilen machst. Irgendwo etwas zusammencopiert von dem du nicht weist was es genau macht. Und dann noch variablen mit var und vari zu benennen und mehrfach zu benutzen, ist die Basis für 100h Fehlersuche.

Teste doch erstmal wie deine Sensoren überhaupt funktionieren. Steck ihn in Erde, lass den Wert mal im seriellen Monitor alle 10sec neu schreiben und giese mal ein bischen. Dann bau dir eine Zeitverzögerung ein nach dem giessen. Und erst wenn das mal klappt, bringe die SD-Karte ins Spiel.

Jacques-123: Also sollte das deiner Meinung nach so aussehen ? :

float feucht[4];
...
feuchtigkeit = (feucht[0] + feucht[1] + feucht[2] + feucht[3] + feucht[4])/5.0;

Nein, wenn Du fünf Elemente nutzen möchtest, mußt Du auch ein Feld mit fünf Elementen anlegen:

float feucht[5];  // Ein Feld mit fünf Elementen feucht[0] bis feucht[4]
...
feuchtigkeit = (feucht[0] + feucht[1] + feucht[2] + feucht[3] + feucht[4])/5.0;

Ich melde mich auch mal wieder zurück !

Habe über das was chefin gesagt hatte mal ein wenig nachgedacht und die ganze sacht von Grund auf neu gestaltet und mich langsam herangetastet. Dabei kam dann schlussendlich folgender Sketch raus :

#include <SD.h>                                                 // Einlesen der SD-Karten Datenbank
#define Spannung A0                                             // Am Analog Input A0 wird eine Spannung gemessen
float Feuchtigkeit = 0;                                         // Wert für die Feuchtigkeit vareiert, beginnt bei 0
const int Pumpe = 2;                                            // Pumpe wird mit Pin 2 geschalten
const int Kartenauswahl = 9;                                    // Karte wird mit Pin 9 angesteuert

void setup()
{
  Serial.begin(9600);
  
  pinMode(A0, INPUT);                                           // A0 ist Input   
  pinMode(2, OUTPUT);                                           // 2 ist Output
  pinMode(10, OUTPUT);                                          // Für SD-Datenbank
  
  Serial.print("Initialisiere SD Karte...");                    // Karte wird überprüft
  if (!SD.begin(Kartenauswahl)) {
    Serial.println("Karte defekt oder nicht vorhanden");
    return;
    }
  Serial.println("Karte initialisiert.");

}

void loop()
{
  Feuchtigkeit = analogRead(Spannung);                          // Feuchtigkeitssensor an A0 wird ausgelesen
  
  
  Serial.print("Bodenfeuchte: ");                               // Feuchtigkeit wird am Seriellen Monitor dargestellt
  Serial.print(Feuchtigkeit);
  Serial.println(";");

  if(Feuchtigkeit > 600)                                        // Pumpe wird bei zu niedriger Feuchtigkeit für 5sec gestartet
   {digitalWrite(Pumpe,HIGH);
   delay(5000);
   digitalWrite(Pumpe, LOW);
   }

  else
   {digitalWrite(Pumpe, LOW);
   }
   
  File Datei = SD.open("datalog.txt", FILE_WRITE);              // Zur Überwachung wird jeder Wert auf der SD-Karte abgelegt
  
  if (Datei) {
    Datei.println(Feuchtigkeit);
    Datei.close();
    }
  else {
    Serial.println("Error beim Öffnen der datalog.txt");
    }

  delay(10000);                                                 // Wiederholung alle 10 sec
  
}

Was meint ihr zu diesem hier ? Läuft bei mir nun einwandfrei !

Dein Code ist ein grausiger Bandwurm. Gewöhne dir bitte an, für alle wesentlichen Aufgaben (Sensor lesen, Relais an/aus, Zeit abearten usw.) einzelne Funktionen zu schreiben. Dann enthält der zentrale Loop nur noch deren Aufrufe … und das Ganze wird wesentlich übersichtlicher.

qualidat: Dein Code ist ein grausiger Bandwurm. Gewöhne dir bitte an, für alle wesentlichen Aufgaben (Sensor lesen, Relais an/aus, Zeit abearten usw.) einzelne Funktionen zu schreiben.

Na ja, prinzipiell richtig.

void loop() {
   int Feuchtigkeit = analogRead(Spannung); 
   schaltePumpe(Feuchtigkeit);
   schreibeSD(Feuchtigkeit);
   delay (10000);  // 10 sec Pause
}

Aber 21 Codezeilen würde ich jetzt nicht als "grausigen Bandwurm" bezeichnen. Eher als Tip für die Zukunft ... 8)

Mein Kommentar wäre eher:

  pinMode(A0, INPUT);      // A0 ist Input  überflüssig   pinMode(2, OUTPUT);      // 2 ist Output  pinMode (Pumpe, OUTPUT); wäre besser

aber das ist nicht der Rede wert.

Das grausigste am ganzen Sketch sind die vielen fürchterlich langen Unterbrechungen durch die delay(). Das geht gar nicht. Ich wundere mich, das dieses nicht als allererstes bemängelt wurde. Dein arduino arbeitet doch gar nicht der steht nur still :-)

Dein arduino arbeitet doch gar nicht der steht nur still :-)

Was soll er denn sonst machen? Für eine Garten-Giessanlage sind 10 sec ziemlich hektisch. Das ist nur zum bequemen Testen so schnell. Wenn nichts anderes interaktives ausser dem Reset-Taster existiert, ist das schon OK.

Wenn doch ( "Und wie kriege ich jetzt ein LCD mit Menu-Tasten dazu?" ) hast du natürlich recht.

maverick1509: Das grausigste am ganzen Sketch sind die vielen fürchterlich langen Unterbrechungen durch die delay(). Das geht gar nicht. Ich wundere mich, das dieses nicht als allererstes bemängelt wurde. Dein arduino arbeitet doch gar nicht der steht nur still :-)

Nun mach mal delay nicht schlechter als es ist.

Für den Anfänger ist es gut umsetzbar und wenig Fehlermöglichkeiten. Man muss lediglich die Nachteile klar machen. Und die sind das während des delays NICHTS anders geht und gemacht wird. Aber wenn nichts anderes passieren soll derweilen ist delay genau richtig.

Ich sehe das auch mal so: die welche den Arduino designed haben und die IDE sind keine Vollpfosten. Sie wissen also schon auch welche Nachteile delay hat. Ja, wenn sie wollten könnten sie delay sogar so umgestalten das man ein bool delay () draus machen könnte und true zurück geben, wenn die Zeit abgelaufen wäre. Um dann die Dinge zu machen, die man nach ablauf der Zeit machen will.

Haben sie aber nicht. Und entfernt haben sie delay auch nicht. Also darf man getrost davon ausgehen, das es viele sinnvolle Möglichkeiten gibt etwas mit delay zu machen. Aber auch viele sinnlose oder völlig fehlerhafte Möglichkeiten.

Sehe ich anders, ein delay ist für mich zur Fehlersuche beim programmieren da und hat in einem normalen Programmablauf nichts zu suchen.

Ja, das sehen viele anders. Und als erfahrener Programmierer sollte millis() so flüssig vom Finger laufen wie Delay.

Viele sind aber Anfänger und andere, dazu zähle ich mich auch, benutzen das was am schnellsten den zweck erfüllt. Ich bastel zb gerade ein Spaßgimmick. Mein Chef hat einen kleinen Tick, er erklärt uns gerne das die Russfilter und die Regeneration absoluter Krampf sind beim Diesel. Und das hören wir jedesmal wenn sein Russfilter kurz vor der Autobahnabfahrt anfängt zu regenerieren und er dann eine Abfahrt weiter fährt deswegen. Weil von Abfahrt bis Büro nur noch 1km sind.

Nun bekommt wer eine HDD-Regeneration an seinen neuen PC. Gelasertes Beschriftungsschild, eingelassene LED, Schild in der Einschubblende versenkt(mit Fräser 1,3mm rausgehobbelt). Und ein Arduino der alle paar std die LED anwirft und per Zufall blinken lässt. Und beim Start auch noch eine kleine Melodie abspielt.

Alles per delay. Weil ich keinen Nerv hab für die 10 Zeiten die ich da benötige millis() und Variablen zu benutzen. Wofür? Es läuft nichts parallel, LED an, Melodie abspielen, LED nach Zufall mehrmals an und aus.

Lediglich eine Funktion wird per Millis gelöst. Das Zufallsblinken geht für 5 Minuten. Diese 5 Minuten überschneiden sich mit den Blinkereien und den Zufallszeiten fürs Blinken. und nur da muss ich millis benutzen. Weder ist die Codelänge noch die Verarbeitungszeit hier relevant, somit ist das meine persönliche Faulheit delay zu benutzen statt millis.

Wie gesagt: wer weis wie es geht, kann beides nutzen und sich nur dann mehr arbeit machen wenn es nötig ist. Anfänger verhaken sich gerne wenn Dinge erst in Abhängigkeit passieren dürfen. Und der Code wird um viele größer und damit unübersichtlicher, wenn ich IMMER millis() benutze. Das DU es ausschliesslich nutzt, ist völlig OK und hat für dich keinen Nachteil. Für mich schon (Faulheit und Übersicht)

Das Problem sind Beispielprogramme, die mit möglichst wenig Code irgend was zeigen wollen. Da ist dann gern mal der Einfachheit halber ein delay() drin, um nicht vom Eigentlichen abzulenken.

Die Demo ist wunderschön, lässt sich eben nur schwer mit einer anderen Geschichte kombinieren, wenn man nur Copy&Paste kann.

Ein Arduino mit seinem sketch, der genau macht was er soll, ist ok. Auch wenn im sketch delay() drin vorkommt. Oder auch wenn man das Verhalten mit einem NE555 und/oder wenigen Logik-IC hingekriegt hätte. (Das ist eine andere Sportart)