Podczas wakacyjnej nieobecności, nasze domowe rośliny, z powodu braku regularnego podlewania i odpowiedniego oświetlenia, narażone są często na uschnięcie. Prezentowany układ (Fig. 1) umożliwia kontrolę podstawowych parametrów wegetacji roślin, t.j. wilgotności gleby i stopnia nasłonecznienia. W zależności od wartości tych parametrów układ umożliwia podjęcie automatycznych akcji nawadniania i/lub doświetlania rośliny. Projekt wykorzystuje tanie i łatwo dostępne komponenty elektroniczne: płytkę prototypową Arduino oraz czujniki, silnik pompy wody i inne.
Projekt wykorzystuje dwa rodzaje czujników: wilgotności oraz nasłonecznienia. Do pomiaru wilgotności gleby wykorzystuje się tzw. higrometry. Są to czujniki rezystancyjne. Tanie sensory dostępne w handlu składają się z dwóch części: małej płytki z elektroniką oraz czujnika złożonego z dwóch elektrod, służącego do kontroli zawartości wody w glebie (Fig. 2). Czujnik posiada potencjometr slużący do regulacji czułości wyjścia cyfrowego oraz diodę LED zasilania oraz diodę LED wyjścia cyfrowego. Układ posiada piny: VCC, GND, oraz dwa sygnały wyjściowe: cyfrowe (D0) oraz analogowe (A0). W handlu znajduje się wiele podobnych czujników np. typu YL-69, HL-69 czy FC-28.
Czujnik umożliwia skorzystanie z dwóch rodzajów sygnałów wyjściowych: cyfrowego (stan niski bądź wysoki) oraz analogowego. Napięcie na wyjściu analogowym czujnika wilgtności zmienia się płynnie w zależności od zawartości wilgoci w glebie. Kiedy gleba jest wilgotna, napięcie wyjściowe jest niskie. Gdy gleba jest sucha, napięcie wyjściowe jest wysokie (Tab. 1). Przetwornik analogowo-cyfrowy układu arduino zmienia to napięcie na odpowiadające mu wartości sygnałów wyrażone w skali od 0-1023. Wartość cyfrowego sygnału wyjściowego uzależniona jest od predefiniowanej wartości progowej. Poniżej niej wartość sygnalu cyfrowego będzie niska (0), a powyżej - wysoka (1). Wartość progową reguluje się za pomocą potencjometra.
| Gleba | Napięcie na wy analogowym | Wartość na wy przetwornika AC Arduino |
|---|---|---|
| sucha | wysokie (np. 4,2V) | 1023 |
| wilgotna | niskie (0V) | 0 |
Jako czujnik oświetlenia wykorzystano fotorezystor. Wykonano dzielnik napięcia, który podłączono do pinu analogowego mierzącego napięcie wyjściowe. Wartość rezystora dobrano eksperymentalnie (około 1,5kΩ).
Elementem odpowiedzialnym za nawadnianie roślin jest silnik (pompa) RS-360SH (Fig. 3). Wymaga ona zasilania 3-12V (do ciągłej pracy rekomendowane jest napięcie 5V 2A). Nie powinno się go podłączać na dłuższy czas do napięcia większego niż 7,5V.
Układ stale dokonuje pomiarów wilgotności gleby i usłonecznienia. Pomierzone wartości z czujników przekazywane są na wejścia analogowe Arduino (kolejno: A0 i A5). Po przeworzeniu, parametry w postaci procentowej są wyświetlane na wyświetlaczu ciekłokrystalicznym Nokia 5110. Pomiary dokonywane są z częstotliwością wyznaczaną za pomocą zmienej MeasurementBreak. W zależności od ustawienia zmiennej NumberOfMeasurements, układ dokonuje zliczeń n pomiarów. Wartości analogowe są sumowane, a następnie obliczana jest z nich średnia arytmetyczna. Wartość uśredniona decyduje o uruchomieniu urządzenia nawadniającego i lampy doświetlającej roślinę. Wartości progowe wilgotności gleby oraz usłonecznienia dobrano eksperymentalnie. W przypadku wilgotności, włączenie przekaźnika następuje wtedy gdy średni pomiar parametru staje się mniejszy bądź równy 850. Spadek wilgotności gleby poniżej wartości krytycznej powoduje załączenie przekaźnika pompy, co uruchamia silnik. Woda zaczyna być pompowana ze zbiornika źródłowego do doniczki. Silnik popmpuje wodę przez okres 3 sek. Po tym czasie pompa zostaje wyłączona i następuje okres 10-sekundowej przerwy, potrzebnej na wsiąknięcie wody i rozprowadzenie jej w przestrzeniach porowych gruntu. Po tym okresie układ przechodzi do trybu wykonania kolejnej serii pomiarów i sytuacja zaczyna się powtarzać. Bezpośrednio po dokonaniu pomiaru wilgotności, układ dokonuje pomiaru usłonecznienia. Aby zapobiec sytuacji ciągłego włączenia oświetlenia w godzinach nocnych, zdarzenie załączenia lampy uzależniono od zaistnienia warunków niepełnego oświetlenia. Jeżeli przeciętny pomiar oświetlenia obliczony jako średnia arytmetyczna z n pomiarów, wskaże wartość z przedziału (700, 850>, mikrokontroler zaświeci lampę. Będzie ona zapalona do momentu kolejnego pomiaru. W praktyce, kolejny pomiar dokonywany jest w warunkach doświetlenia i kolejna uśredniona wartość pomiarów wyłączy lampę. Jeśli w kolejnym okresie czasu warunki pomiarowe światła nie pogorszą się (np. z powodu nocy), światło zostanie ponownie zapalone. Sytuacja zacznie się od tego momentu powtarzać. Wartości chwilowe czujników oraz wartości uśrednione, wysyłane są na port szeregowy.
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#define MeasurementBreak 1000 // time interval between measurements 5min - 300.000ms
#define NumberOfMeasurements 20 // number of measurements to averaging
// Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK, DIN, D/C, CS, RST);
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
int relay_pump = 8; // pin of the pump relay
int relay_light = 10; // pin of the light relay
int moistureValue = 0; // initial values of the measurements of the percent of the moisture
int moisturePercent = 0;
String percentMoistureString = "0";
int stringMoistureLength = 0;
int lightValue = 0; // initial values of the measurements of the percent of the light
int lightPercent = 0;
String percentLightString = "0";
int stringLightLength = 0;
int sum_of_moisture = 0; // initial value of the sum of the moisture measurements
int sum_of_light = 0; // initial value of the sum of the light measurements
int mesurement = 0; // initial value of the measurement item
unsigned long LastTime = 0;
int convertMoistureToPercent(int value) { // function to convert moisture analog values to percent values
int percentMoistureValue = 0;
percentMoistureValue = map(value, 1023, 410, 0, 100);
if (percentMoistureValue > 100)
percentMoistureValue = 100;
return percentMoistureValue;
}
int convertLightToPercent(int value) { // function to convert light analog values to percent values
int percentLightValue = 0;
percentLightValue = map(value, 970, 160, 0, 100);
if (percentLightValue > 100)
percentLightValue = 100;
return percentLightValue;
}
void displayMoisturePercent(int length) { // function to display percent moisture values in Nokia LCD display
switch (length) {
case 1: display.setCursor(58, 5); display.print(percentMoistureString); break;
case 2: display.setCursor(45, 5); display.print(percentMoistureString); break;
case 3: display.setCursor(34, 5); display.print(percentMoistureString); break;
default: display.setCursor(34, 5); display.print(percentMoistureString); break;
}
}
void displayLightPercent(int length) { // function to display percent light values in Nokia LCD display
switch (length) {
case 1: display.setCursor(58, 29); display.print(percentLightString); break;
case 2: display.setCursor(45, 29); display.print(percentLightString); break;
case 3: display.setCursor(34, 29); display.print(percentLightString); break;
default: display.setCursor(34, 29); display.print(percentLightString); break;
}
}
void setup() {
pinMode(relay_pump, OUTPUT); // set the relay_pump pin as an OUTPUT
pinMode(relay_light, OUTPUT); // set the relay_light pin as an OUTPUT
digitalWrite(relay_pump, HIGH); // initialy turn OFF pump relay
digitalWrite(relay_light, HIGH); // initialy turn OFF light relay
display.begin(); // start of the Nokia LCD display
display.setContrast(40); // Nokia LCD display contrast settings
Serial.begin(9600); // start of the serial port
}
void loop() {
unsigned long CurrentTime = millis(); // time from start of the sketch
if (CurrentTime - LastTime > MeasurementBreak) { // if the time of the mesurements is longer than MeasurementBreak value:
LastTime = CurrentTime;
mesurement += 1; // add the current mesurement to the total measurement no
sum_of_moisture += analogRead(A0); // add the current moisture value to the sum of the moisture measurements
sum_of_light += analogRead(A5); // add the current light value to the sum of the light measurements
if (mesurement >= NumberOfMeasurements) {
int mean_moisture = ceil(sum_of_moisture / mesurement);
int mean_light = ceil(sum_of_light / mesurement);
Serial.print("Mean of moisture: "); // send to serial port the string "Mean of moisture: "
Serial.print(mean_moisture); // send to serial port the mean_moisture value
Serial.print(" Mean of light: "); // send to serial port the string "Mean of light: "
Serial.println(mean_light); // send to serial port the mean_light value
if (mean_moisture <= 800) { // if the soil is wet:
digitalWrite(relay_pump, HIGH); // turn OFF of the pump
} else { // if the soil is dry:
digitalWrite(relay_pump, LOW); // turn ON of the pump
delay(3000); // watering 3 sek.
digitalWrite(relay_pump, HIGH);
delay(10000); // wait 10 sec. until a water soaks
}
if ((mean_light > 700) && (mean_light <= 850)) { // if there is too little light (but there is not yet night)-
digitalWrite(relay_light, LOW); // turn OFF of the light
} else { // if there is too much light -
digitalWrite(relay_light, HIGH); // turn ON of the light
}
mesurement = sum_of_moisture = sum_of_light = 0; // reset the variables values calculated in the loops
}
display.clearDisplay(); // clear of the display
display.setTextSize(1); // font size settings to 1
display.setTextColor(BLACK); // display font color settings
display.setCursor(3, 14); // set cursor in column no 3 and row no 14 position
display.print("Wilg."); // write "Wilg" (moisture symbol)
display.setTextSize(2); // font size settings to 2
moistureValue = analogRead(0); // read the moisture value from the analog pin A0
moisturePercent = convertMoistureToPercent(moistureValue);
percentMoistureString = String(moisturePercent);
stringMoistureLength = percentMoistureString.length();
displayMoisturePercent(stringMoistureLength);
display.setCursor(70, 5); // set cursor at the end of the moisture mesurement frame
display.print("%"); // write "%"
display.drawRect(32, 2, 51, 19, BLACK); // draw a rectangle from (x1,y1) to (x2,y2)
display.drawLine(2, 24, 81, 24, BLACK); // draw a line from (x1,x2) to (y1,y2)
display.setTextSize(1); // font size settings to 1
display.setCursor(3, 37); // set cursor in column no 3 and row no 37 position
display.print("Nasl."); // write "Nasl" (light symbol)
display.setCursor(34, 29); // set cursor in column no 34 and row no 29 position
display.setTextSize(2); // font size settings to 2
lightValue = analogRead(5); // read the light value from the analog pin A5
lightPercent = convertLightToPercent(lightValue);
percentLightString = String(lightPercent);
stringLightLength = percentLightString.length();
displayLightPercent(stringLightLength);
display.setCursor(70, 29); // set cursor at the end of the light mesurement frame
display.print("%"); // write "%"
display.drawRect(32, 27, 51, 18, BLACK); // draw a rectangle from (x1,y1) to (x2,y2)
display.drawLine(2, 47, 81, 47, BLACK); // draw a line from (x1,x2) to (y1,y2)
display.display();
Serial.print(mesurement); // send to serial port the masurement no
Serial.print(" ");
Serial.print(analogRead(A0)); // send to serial port the moisture instantaneous value
Serial.print(" ");
Serial.print(analogRead(A5)); // send to serial port the light instantaneous value
Serial.println(" ");
}
}