In questa guida vedremo come creare una serra automatizzata usando Arduino e C++.
Vediamo il funzionamento della serra con un semplice esempio, supponiamo di avere una pianta che richiede condizioni specifiche per sopravvivere o banalmente degli ortaggi fuori stagione e vogliamo che temperatura e umidità siano perfette in modo completamente automatico.
Quando avviamo la serra il display LCD ci darà il benvenuto e da qui inizia il monitoraggio:
- Sensore a ultrasuoni:
- Monitora la distanza da un punto di riferimento come il terreno o la superficie dell'acqua.
- In base alla distanza misurata il servo controlla la valvola dell'irrigazione.
- Se il livello d'acqua è basso la valvola si apre completamente, se è medio si posiziona a metà, se è alto si chiude completamente.
- Luminosità:
- Con un fotoresistore si misura l'intensità della luce nell'ambiente.
- Se l'illuminazione è insufficiente si accende la lampadina.
- Sensore di umidità:
- L'umidità viene misurata e nel display verrà visualizzato il messaggio corrispondente in base al suo valore.
- Sensore di temperatura:
- Ci permette di misurare costantemente la temperatura nell'ambiente.
- Se la temperatura è troppo elevata <25°C, entrerà in gioco il sistema di ventilazione con il motore DC.
Materiali:
- Arduino Uno R3
- Sensore di distanza ad ultrasuoni
- Lampadina
- Motore CC
- LCD 16 x 2
- Sensore di umidità del terreno
- Micro Servo
- Sensore di temperatura [TMP36]
- 250 kΩ Potenziometro
- 220 Ω Resistenza
- 1 kΩ Resistenza
- Fotoresistore
Collegamenti:
Componenti principali:
Codice:
Iniziamo a scrivere il codice, dichiariamo le librerie necessarie (Servo e LiquidCrystal), le variabili e i pin utilizzati.
Nel setup()
inizia la comunicazione seriale collegando il servo al pin 10 e configurando i pin come input o output e impostiamo il display LCD con un messaggio di benvenuto.
Nel loop()
(la funzione principale del programma) richiamiamo measureAndDisplaySensors()
, vediamole tutte.
Per la misurazione della distanza abbiamo la funzione measureDistance()
dove Il tempo viene convertito in distanza grazie alla velocità del suono (circa 0.034 cm/µs) e diviso per 2 per contare andata e ritorno.
Per controllare il servomotore in base alla distanza viene chiamata la funzione controlServoBasedOnDistance()
.
Se la distanza è inferiore a emptyDistance
il livello d'acqua è vuoto quindi il servo viene regolato per aprire la valvola. Quando la distanza è compresa tra emptyDistance
e fullDistance
il livello d'acqua è considerato medio e il motore servo si posiziona a metà e così via finché non verrà riempito completamente.
Per la luminosità usiamo una funzione chiamata measureLightSensor()
che tramite pinLightSensor
legge il dato preso dal fotoresistore e confrontandosi con una soglia MIN_THRESHOLD
si comporta di conseguenza (se è inferiore si accende con pinBulb
).
La vera funzione che controlla la lampadina è controlBulbBasedOnLight()
, se succede l'esatto opposto la lampadina viene spenta.
Per la misurazione dell'umidità c'è la funzione measureSoilHumidity()
che legge i valori di pinSoilHumidity
.
La temperatura viene misurata con temperatureFunction()
dal pin pinTMP36
, e convertita in °C con convertTemperature()
return (TMP36Reading * 5.0 / 1023.0 - 0.5) * 100.0;
.
Anche il motore DC viene regolato in base alla temperatura, in particolare con controlDCMotorBasedOnTemperature()
, la ventola si attiverà solo al superamento della temperatureLimit
in modo da ventilare l'ambiente.
#include <Servo.h>
#include <LiquidCrystal.h>
Servo myServo;
LiquidCrystal lcd(12,11,5,4,3,2);
const int pinTMP36=A0;
const int pinSoilHumidity=A5;
const int pinLightSensor=A3;
const int pinDCMotor=13;
const int pinTrig=7;
const int pinEcho=6;
const int pinBulb=8;
const int servoMin=0;
const int servoMax=180;
const float emptyDistance=100.0;
const float fullDistance=280.0;
const float optimalTemperatureMin=18.0;
const float optimalTemperatureMax=24.0;
const float temperatureLimit=25.0;
const int MIN_THRESHOLD=300;
bool fanActive=false;
void setup(){
Serial.begin(9600);
myServo.attach(10);
pinMode(pinBulb,OUTPUT);
pinMode(pinTrig,OUTPUT);
pinMode(pinEcho,INPUT);
lcd.begin(16,2);
lcd.print("Serra EHF!");
lcd.setCursor(0,1);
lcd.print("Benvenuto!");
delay(2000);
}
void loop(){
measureAndDisplaySensors();
}
void measureAndDisplaySensors(){
measureSensors();
showDistance();
}
void showDistance(){
float distance=measureDistance();
displayDistance(distance);
controlServoBasedOnDistance(distance);
delay(2000);
}
void controlServoBasedOnDistance(float distance){
lcd.setCursor(0,1);
if (distance>=1&&distance<=emptyDistance){
lcd.print("Livello: Vuoto");
controlServo(servoMax);
} else if (distance>emptyDistance&&distance<=fullDistance){
lcd.print("Livello: Medio");
controlServo((servoMax+servoMin) / 2);
} else if (distance>fullDistance) {
lcd.print("Livello: Pieno");
controlServo(servoMin);
} else {
lcd.print("Fuori range");
controlServo((servoMax+servoMin) / 2);
}
}
void displayDistance(float distance){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Distanza: ");
lcd.print(distance);
}
void controlServo(int angle){
myServo.write(angle);
delay(500);
}
void measureSensors(){
temperatureFunction();
humidityFunction();
lightFunction();
}
void lightFunction(){
int reading = measureLightSensor();
displayLightReading(reading);
controlBulbBasedOnLight(reading);
delay(2000);
}
void controlBulbBasedOnLight(int reading){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Luminosita': ");
lcd.print(reading);
if (reading<MIN_THRESHOLD){
digitalWrite(pinBulb, HIGH);
lcd.setCursor(0,1);
lcd.print("Lampadina: ON");
} else {
digitalWrite(pinBulb,LOW);
lcd.setCursor(0,1);
lcd.print("Lampadina: OFF");
}
}
void displayLightReading(int reading) {
Serial.print("Lettura sensore di luce: ");
Serial.println(reading);
}
void humidityFunction(){
int humidity = measureSoilHumidity() / 10;
displayHumidity(humidity);
delay(3000);
}
void displayHumidity(int humidity){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Umidita': ");
lcd.print(humidity);
lcd.print("%");
lcd.setCursor(0, 1);
lcd.print(humidity<=50 ? "Umidita': Bassa" : "Umidita': Adeguata");
}
int measureSoilHumidity(){
return analogRead(pinSoilHumidity);
}
void temperatureFunction(){
int tempReading=analogRead(pinTMP36);
float tempCelsius=convertTemperature(tempReading);
displayTemperature(tempCelsius);
controlDCMotorBasedOnTemperature(tempCelsius);
delay(3000);
}
void displayTemperature(float tempCelsius) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temperatura: ");
lcd.print(tempCelsius);
lcd.setCursor(0, 1);
Serial.print("Lettura temperatura: ");
Serial.println(tempCelsius);
}
void controlDCMotorBasedOnTemperature(float tempCelsius) {
if (tempCelsius>temperatureLimit&&!fanActive) {
activateDCMotor();
fanActive = true;
} else if (tempCelsius<=optimalTemperatureMax&&fanActive) {
deactivateDCMotor();
fanActive=false;
}
}
void activateDCMotor(){
digitalWrite(pinDCMotor,HIGH);
}
void deactivateDCMotor(){
digitalWrite(pinDCMotor,LOW);
}
float convertTemperature(int TMP36Reading){
return (TMP36Reading * 5.0 / 1023.0 - 0.5) * 100.0;
}
float measureDistance(){
digitalWrite(pinTrig,LOW);
delayMicroseconds(2);
digitalWrite(pinTrig,HIGH);
delayMicroseconds(10);
digitalWrite(pinTrig,LOW);
long duration=pulseIn(pinEcho,HIGH);
return duration * 0.034 / 2;
}
int measureLightSensor(){
return analogRead(pinLightSensor);
}
Schema elettrico:
Link utili: