Guten Abend,
das hier ist mittlerweile mein zweiter Beitrag und ich hoffe, dass ich mein Thema bzw. mein Problem verständlich rüberbringen kann.
Mein Projekt ist eine automatische Bewässerungsanlage, die je nach gemessener Bodenfeuchtigkeit bewässern soll. Aktuell läuft das als "Zweipunkt Regler" nach folgendem Code:
if (soil < 300) // je kleiner, desto trockener
{
digitalWrite(ledgreen, HIGH);
digitalWrite(4,1); // Relais an
delay(2000); // Pumpe läuft 2 Sekunden
digitalWrite(4, 0); // Relais aus
digitalWrite(ledgreen, LOW);
}
else if (soil > 500) // zu nass, kein Wasser nachgeben
{
digitalWrite (ledgreen, LOW);
}
delay(5000);
}
Zusätzlich geht noch eine grüne LED an, wenn die Pumpe läuft. Das ist mir allerdings zu stumpf und zu ungenau. Deshalb möchte ich einen proportionalen Regler programmieren, der für eine bestimmte Über-/Unterschreitung des Sollwertes (bspw. 50% Feuchtigkeit) um eine proportionale Zeit bewässert. Das hört sich abstrakt an, deshalb versuch ich es mal als Beispiel zu beschreiben:
Sollwert der Feuchtigkeit: 50%
Istwert: 40% ---> Abweichung um 10% (0,1 in Dezimalschreibweise)
Diese Regelabweichung soll jetzt mit einer Konstante multipliziert werden, also mit einer Standardzeit von bspw. 5 sek ---> 5s * 0,1 = 0,5 sek ---> Die Pflanze soll nun also 0,5 sek bewässert werden bzw. die Pumpe soll 0,5 sek laufen.
Mein Plan lautet jetzt:
Ich rechne zunächst mal den Analogwert vom Feuchtigkeitssensor in Prozent und in eine Dezimalzahl um...Die Prozentumrechnung ist erstmal nur für das Datenlogging auf einer SD-Karte...Das Wichtige ist hier also nur die Dezimalzahl, die später mit der Konstante multipliziert wird. Die Umrechnung läuft nach folgendem Code:
void Read_Soilvalue ()
{
soil = analogRead(A1);
per = ( (100 / 1023.0) * soil);
Serial.print("Bodenfeuchtigkeit: ");
Serial.println(per);
}
varout = (per * 0.01);
"per" meint hier die Bodenfeuchtigkeit in Prozent also im Format 10, 20, 25...Deshalb ist per auch als "int" definiert, denn da brauche ich keine Kommastelle. "varout" soll nun die Dezimalzahl werden, weshalb "per" mit 0,01 multipliziert wird. "varout" ist als "float" definiert und kann somit Kommastellen haben (sehe ich das richtig?).
Meine Frage ist jetzt? Wie programmiere ich jetzt einen Regler, der mir die vorhin erklärte Formel berechnet?
Die Formel ist: y = K * e
y (Dauer der Pumpe); K ( Konstante Ausgangszeit bspw. 2 sek); e (errechnete Regeldifferenz in Dezimal)
Wichtig ist vor allem, dass es um die Abweichung vom SOLLWERT (50%) geht. Ich muss es also irgendwie berechnen können, dass 40% einer Abweichung von 10% bzw. 0,1 entspricht...Bisher berechne ich ja nur die Feuchtigkeit in Prozent und in Dezimal, was mir aber nichts bringt...Kann man das mit einer if-Schleife realisieren?
Übrigens: Die fertig berechnete Dauer würde ich dann als eigene Variable definieren und diese in eine delay-Funktion packen, sodass die Pumpe um den errechneten Betrag läuft.
Ihr könnte gerne Fragen stellen falls ihr meine Erklärungen nicht ganz nachvollziehen könnt. Ich schau den ganzen Tag auf meine Notifications! Ich bin für jede Hilfe dankbar!
Für alle die es interessiert kommt jetzt mein vollständiger Quellcode:
#include <SPI.h>
#include <SD.h>
#include "DHT.h" // Bibliothek für den Sensor /Temperatur /Luftfeuchtigkeit
#include <NewPing.h>
#define DHTPIN 7 // Hier die Pin Nummer eintragen wo der Sensor angeschlossen ist
#define DHTTYPE DHT11 // Hier wird definiert was für ein Sensor ausgelesen wird (Typ: DHT11); andere wären bspw. DHT22
File dataFile;
DHT dht(DHTPIN, DHTTYPE); // Das ist ein zwingender Abschnitt, der aus den Protokollen der Bibliothek (DHT.h) hervorgeht..Ich weiß nicht wofür das ist
float h;
float t;
const int chipSelect = 10;
int soil = A1; // Variablendefinition für den Analogen PIN A1 am Arduino -> Pin A1 ist also für "Soil" = den Bodenfeuchtigkeitssensor
int per; // Variablendefinition für die Prozentzahl nach der Berechnung
float varout; // Variablendefinition für die Regeldifferenz in Prozent (Dezimal) für die Berechnung von p
int Relais = 4; // Relais bekommt den Digitalen Pin 4
int ledblue = 9; // Wasserstand zu niedrig
int ledgreen = 8; // Pumpe läuft
void setup()
{
Serial.begin(9600); // Serielle Schnittstelle wird gestartete mit 9600 Baud
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
pinMode(Relais, OUTPUT); // Pin 4 wird als Output gekennzeichnet: Signal AUS dem Arduino IN das Relais
Serial.println("DHT11 Test"); // Serielle Schnittstelle sagt, dass der DHT11 Sensor jetzt initialisiert wird
dht.begin(); // Der DHT11 wird gestartet
Initialize_SDcard();
}
void loop()
{
Read_TempHum();
Read_Soilvalue();
Write_SDcard();
varout = (per * 0.01);
if (soil < 300) // je kleiner, desto trockener
{
digitalWrite(ledgreen, HIGH);
digitalWrite(4,1); // Relais an
delay(2000); // Pumpe läuft 2 Sekunden
digitalWrite(4, 0); // Relais aus
digitalWrite(ledgreen, LOW);
}
else if (soil > 500) // zu nass, kein Wasser nachgeben
{
digitalWrite (ledgreen, LOW);
}
delay(5000);
}
void Read_TempHum ()
{
h = dht.readHumidity(); // Lesen der Luftfeuchtigkeit und speichern in die Variable h
t = dht.readTemperature(); // Lesen der Temperatur in °C und speichern in die Variable t
/* Jetzt kommt ein Teil, der überprüft, ob die ausgegebenen Werte für Luftfeuchtigkeit und Temperatur auch wirklich Zahlen sind.
* Falls nicht, wird ein Fehler an den seriellen Monitor ausgegeben. isnan = is not a number*/
if (isnan(h) || isnan(t))
{
Serial.println("Fehler beim auslesen des Sensors!");
}
else
{
// Nun senden wir die gemessenen Werte an den PC (seriellen Montor)
Serial.print("Luftfeuchtigkeit: ");
Serial.print(h); // Ausgeben der Luftfeuchtigkeit
Serial.print("%\t"); // Tabulator
Serial.print("Temperatur: ");
Serial.print(t); // Ausgeben der Temperatur
Serial.print("°"); // Schreiben des ° Zeichen
Serial.println("C");
}
}
void Read_Soilvalue ()
{
soil = analogRead(A1);
per = ( (100 / 1023.0) * soil);
Serial.print("Bodenfeuchtigkeit: ");
Serial.println(per);
}
void Initialize_SDcard ()
{
if (!SD.begin(chipSelect))
{
Serial.println("Card failed, or not present");
// don't do anything more:
while (1);
}
Serial.println("card initialized.");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
dataFile = SD.open("Soildata.csv", FILE_WRITE);
// if the file is available, write to it:
dataFile.println("Temperature:,Humidity:,Bodenfeuchtigkeit:"); //Write the first row of the excel file
dataFile.close();
}
void Write_SDcard ()
{
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
dataFile = SD.open("Soildata.csv", FILE_WRITE);
// if the file is available, write to it:
if (dataFile)
{
dataFile.print(t); //Store date on SD card
dataFile.print(","); //Move to next column using a ","
dataFile.print(h); //Store date on SD card
dataFile.print(","); //Move to next column using a ","
dataFile.print(per);
dataFile.println(); //End of Row move to next row
dataFile.close(); //Close the file
Serial.println ("SD card writing successful");
}
else
Serial.println("SD card writing failed");
}