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:

  • Sensore ad Ultrasuoni (HC-SR04):

    • VCC (alimentazione): 5V.
    • GND (terra): al "-".
    • Trig (Trigger):pin 7.
    • Echo: pin 6.
  • Servomotore:

    • Alimentazione ai 5V
    • Il controllo al pin 10.
  • Fotoresistore:

    • Morsetto 1 a 5V.
    • Morsetto 2 al pin A3 con una resistenza da 1kΩ.
  • Sensore di umidità:

    • VCC (alimentazione): 5V.
    • GND (terra): "-".
    • A0 (uscita analogica): al pin A5.
  • Sensore di temperatura (TMP36):

    • VCC (alimentazione): 5V.
      GND (terra): "-".
      OUT (uscita analogica): al pin A0.
  • Motore DC:

    • Alimentazione 5V.
    • Controllo: al pin 13.
  • Display LCD:

    • VCC (Alimentazione): Collegare a +5V.
    • GND (terra): al "-".
    • VCC: 5V.
    • V0: al secondo pin del potenziometro.
    • RS: al pin 12.
    • RW: al "-".
    • E: al pin 11.
    • DB4: al pin 5.
    • DB5: al pin 4.
    • DB6: al pin 3.
    • DB7: al pin 2.
    • LED (1): al + con una resistenza da 220Ω.
    • LED (2): al "-".

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:

Powered by: FreeFlarum.
(remove this footer)