Seite 1 von 1

Automatisierte Fruchtungsbox

Verfasst: Freitag, 29. September 2023 20:15
von ohkw
Ich habe die hitzebedingte Pilzzucht-Sommerpause letzte Woche beendet und die nun etwas ausgereiftere Version meiner Fruchtungsbox in Betrieb genommen. Das ganze funktioniert sehr gut und ermöglicht monatelange Aufbewahrung von Kulturen in der Box um die mit der Fruchtung unter verschiedenen Bedingen zu experimentieren, wie z.B. mit meinen Nelkenschwindling-Experimenten die nun gerade in die nächste Runde gehen.
DSC_0864.JPG
Die Steuerung (Arduino Nano) ist jetzt auf einer Platine verlötet und kein Steckboard-Kabelsalat mehr.
Auf der Platine sind neben dem Microcontroller noch folgende Bauteile:

- Ein DC/DC Wandler um vom 24V Netzteil auf 12V zu konvertieren
- Eine Echtzeituhr um Licht und Luftfeuchte tageszeitabhängig zusteuern
- 3 Leistungs-MOSFETs um Lüfter, Nebler und LED Beleuchtung anzusteuern
- Stützkondensatoren für Spannungseingang und 5V Ausgang
DSC_0861.JPG
In der Box befindet sich ein Grove SCD30 Sensor um CO2 Konzentration und Luftfeuchte zu messen (Temperatur kann der auch, ist aber derzeit nicht in Verwendung)
DSC_0866.JPG
Damit man jederzeit bescheid weiß was der Controller gerade tut ist ein LCD Display angeschlossen, welches CO2, Feuchtigkeit, Zeit und was der Controller gerade macht anzeigt (Lüften oder Befeuchten)
DSC_0862.JPG
Der Luftaustausch in der Box erfolgt über einen 10cm (Lochsäge) Lufteinlass bzw. einem solchen Auslass. Beim Auslass ist ein Luftschlauch Kanalverbinder angeklebt (Heißklebepistole) wo mittels Schlauchklemme der Abluftschlauch angebracht ist. An dessen Ende ist ein Edelstahl Tellerventil.
DSC_0865.JPG
Der Lufteinlass ist erfolgt über eine Tupperdose in die ein Staubsauger Hepafilter eingesetzt ist. Im Deckel der Tupperdose ist ein 10cm Loch eingesägt in welchem ein weiterer Kanalverbinder eingeklebt ist ( Stutzen nach außen bzw. unten) Am Kanalverbinder ist ein 120mm PC Lüfter angeschraubt welcher die Luft durch den Filter saugt und nach unten in die Box bläst. Der Tupperdosen Filteraufsatz ist über den Stutzen in das Lufteinlassloch der Box eingesetzt, ist also abnehmbar.
DSC_0863.JPG

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 08. Oktober 2023 00:46
von Nesel
Sehr schöner Aufbau!

Was für LEDs verwendest du da zum beleuchten? Sieht aus wie blaue LED-Stripes aber auf den Fotos wirkt das Blau nicht so tiefblau wie ich es von blauen LEDs kenne.

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 08. Oktober 2023 15:01
von ohkw
Hi, stimmt schon, sind blaue LED Strips SMD5050, 460-465nm
Durch die Plastikbox wirkt das gestreute Licht etwas weicher.

Re: Automatisierte Fruchtungsbox

Verfasst: Samstag, 04. November 2023 11:16
von Leonardo Fiando
Cooles Teil!!! :)
Könnte ich mal einen Einblick in Deinen Sketch und Deinen Schaltplan haben? Es würde mich interessieren wie Du die unabhängige Steuerung der Parameter mit dem Echtzeituhrmodul realisiert hast!
Außerdem würde ich das gerne mal mit meiner Arduino-Steuerung vergleichen:
https://forum.arduino.cc/t/pillzucht-st ... 66?page=18

Was für einen Nebler verwendest Du?

Re: Automatisierte Fruchtungsbox

Verfasst: Samstag, 04. November 2023 11:55
von ohkw

Code: Alles auswählen

#include "Wire.h"
#include "SCD30.h"
#include <LiquidCrystal_I2C.h> 
#include "RTClib.h"

#define FAN 5
//#define FAN_PWM 6 		// BeQuiet 120mm 2,4W (12V)
#define FOGGER 7
#define LED 6

float SENSOR_DATA[3];
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS3231 rtc;
DateTime now;

bool lightOn = false;

float daytimeHumidity = 50.0;
float nighttimeHumidity = 85.0;
float targetHumidity = nighttimeHumidity;
 
#if defined(ARDUINO_ARCH_AVR)
    #pragma message("Defined architecture for ARDUINO_ARCH_AVR.")
    #define SERIAL Serial
#elif defined(ARDUINO_ARCH_SAM)
    #pragma message("Defined architecture for ARDUINO_ARCH_SAM.")
    #define SERIAL SerialUSB
#elif defined(ARDUINO_ARCH_SAMD)
    #pragma message("Defined architecture for ARDUINO_ARCH_SAMD.")  
    #define SERIAL SerialUSB
#elif defined(ARDUINO_ARCH_STM32F4)
    #pragma message("Defined architecture for ARDUINO_ARCH_STM32F4.")
    #define SERIAL SerialUSB
#else
    #pragma message("Not found any architecture.")
    #define SERIAL Serial
#endif
 
 
void setup() {
  pinMode(FAN, OUTPUT);
  //pinMode(FAN_PWM, OUTPUT);
  pinMode(FOGGER, OUTPUT);
  pinMode(LED, OUTPUT);
  lightOn = false;
  digitalWrite(LED, LOW);
  Wire.begin();
  SERIAL.begin(115200);
  scd30.initialize();
  scd30.setAutoSelfCalibration(false);

  lcd.init(); //Im Setup wird der LCD gestartet 
  lcd.noBacklight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight();

  rtc.begin();
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

void ventilate(unsigned long duration) {
  if(SERIAL) {
    SERIAL.print("Ventilating for ");
    SERIAL.print(duration);
    SERIAL.println(" millis.");
  }

  lcd.setCursor(0, 2);
  lcd.print("Ventilating for ");
  lcd.setCursor(0, 3);
  lcd.print(duration/1000);
  lcd.print(" sec ...");

  //analogWrite(FAN_PWM, 255);
  digitalWrite(FAN, HIGH);
  delay(duration);
  //analogWrite(FAN_PWM, 0);
  digitalWrite(FAN, LOW);
}

void moisturize(unsigned long duration) {
  if(SERIAL) {
    SERIAL.print("Moisturizing for ");
    SERIAL.print(duration);
    SERIAL.println(" millis.");
  }

  lcd.setCursor(0, 2);
  lcd.print("Moisturizing for ");
  lcd.setCursor(0, 3);
  lcd.print(duration/1000);
  lcd.print(" sec ...");

  //analogWrite(FAN_PWM, 191);
  digitalWrite(FAN, HIGH);
  delay(200);
  digitalWrite(FOGGER, HIGH);
  delay(duration);
  //analogWrite(FAN_PWM, 0);
  digitalWrite(FAN, LOW);
  digitalWrite(FOGGER, LOW);
}

void printData() {
  SERIAL.print("Carbon Dioxide Concentration is: ");
  SERIAL.print(SENSOR_DATA[0]);
  SERIAL.println(" ppm");
  SERIAL.print("Temperature = ");
  SERIAL.print(SENSOR_DATA[1]);
  SERIAL.println(" ℃");
  SERIAL.print("Humidity = ");
  SERIAL.print(SENSOR_DATA[2]);
  SERIAL.println(" %");

  lcd.setCursor(0, 0);
  lcd.print("CO2: ");
  lcd.print(SENSOR_DATA[0]);
  lcd.print(" ppm");

  lcd.setCursor(0, 1);
  lcd.print("Humidity: ");
  lcd.print(SENSOR_DATA[2]);
  lcd.print("%");

  lcd.setCursor(0, 2);
  lcd.print(now.timestamp(now.TIMESTAMP_TIME));
}
 
void loop() {
  lcd.clear();

  now = rtc.now();
  
  if(!lightOn && now.hour() > 7 && now.hour() < 19) {
    lightOn = true;
    digitalWrite(LED, HIGH);
  } else if (lightOn && (now.hour() < 7 || now.hour() >= 19)) {
    lightOn = false;
    digitalWrite(LED, LOW);
  }

  if(now.hour() >= 20 || now.hour() <= 7) 
    targetHumidity = nighttimeHumidity;
  else 
    targetHumidity = daytimeHumidity;

  if(scd30.isAvailable()) {
    scd30.getCarbonDioxideConcentration(SENSOR_DATA);
    if(SERIAL)
      printData();

    if(SENSOR_DATA[0] > 900) {
      ventilate(180000);
      //moisturize(180000);
    } 
    
    if((targetHumidity - SENSOR_DATA[2]) > 10.0) {
      moisturize(300000);
    } else if ((targetHumidity - SENSOR_DATA[2]) > 5.0) {
      moisturize(180000);
    } else if ((targetHumidity - SENSOR_DATA[2]) > 1.0) {
      moisturize(60000);
    }
  } else {
    if(SERIAL)
      SERIAL.println("SCD30 not available!");
    lcd.setCursor(0, 0);
    lcd.print("SCD30 not available!");
  }

  delay(10000);
  if(SERIAL)
    SERIAL.println("----------------------------------");
}

Schaltplan ist nicht wirklich erwähnenswert. Ich nutze das 24V Netzteil vom Nebler um das ganze zu versorgen. Da hängt der Nebler dran und ein Stepdown Modul um auf 12V zu konvertieren.
Die 12V Schiene ist für den Lüfter, Beleuchtung und V_in vom Controller.
Am I2C Bus sind Echtzeituhr, Sensor und LCD-Panel dran, die über 5V V_out vom Controller versorgt werden.
Licht, Lüfter und Nebler werden über Leistungs-MOSFETs gesteuert die je über ein Pin vom Controller angesteuert werden.
Dazu kommen noch Stützkondensatoren am V_in und V_out des Controllers damit die Spannungspegel stabil bleiben.

Der Nebler ist einfach ein China-Ultraschallnebler in einer Schale Osmosewasser.
Z.B. sowas hier:
https://www.amazon.de/Hangrow-Ultrascha ... 114&sr=8-5

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 05. November 2023 13:09
von Leonardo Fiando
Vielen Dank für die Einblicke in den Sketch und das Erklären des Schaltplanes!

Ich habe die Funktionsweise Deines Sketches oben im selbigen zusammengefasst.

Unsere Sketches unterscheiden sich vor allem in der Hinsicht, dass ich in regelmäßigen Intervallen belüfte, sowie wenn die LF >= 95 % und Du in Abhängigkeit vom CO2- Wert.
Des Weiteren hast Du Licht in deiner Fruchtungsbox, sowie unterschiedliche Richtwerte für die LF an Tag und Nacht. Die unterschiedlichen LF- Richtwerte sind ja wirklich feintuning und bilden das natürliche Habitat von Pilzen bestimmt besser ab, als ein gleichbleibender Wert, würde mich mal interessieren ob sich das wirklich lohnt:). Ansonsten könntest Du das Licht auch einfach mit einer Zeitschaltuhr ein- und ausschalten. Aber wie Du es gelöst hast ist es natürlich besonders elegant;).

Cool, dass der BeQuiet 120mm 2,4W (12V) Lüfter das Edelstahl Tellerventil auslösen kann, mein Arctic P14 (140mm,12 Volt, 1,44 Watt) hat es bei dieser dichten Rückschlagklappe
https://de.ventilatory.net/kpk-125.html ... 3WEALw_wcB
auf jeden Fall nicht geschafft :'(, also habe ich zu einem Rohrlüfter zurückgriffen.

Noch eine Frage: Die Schale mit dem Osmosewasser und dem Ultraschallvernebler, steht die neben den Eimern, oder direkt unter dem Hepafilter in dem Tupperwarebehälter neben dem Lüfter?

Code: Alles auswählen

// Zusammenfassung: 
// Licht an von 8:00 - 18:00 (10 Stunden)
// Belüften für 3 Minuten wenn CO2- Werte über 900 ppm
// unterschiedliche Richtwerte für die LF an Tag und Nacht ( Tag: 50%, Nacht 85%) // Tagzeit von 8:00 bis 18:00, Nachtzeit von 20:00 - 7:00
// Wenn sich die LF um x (1, 5, 10) % vom festgelegten Richtwert unterscheidet, befeuchten für y (1, 3, 5 Minuten) Minuten 

// auf dem LCD werden angezeigt:
// CO2- Konzentration (Zeile 1)
// LF (Zeile 2)
// aktuelle Uhrzeit oder "ventilating for" oder moisturizing for" (Zeile 3)
// x "sec..." ( Zeile 4)

// auf dem seriellen Monitor werden diese Sachen auch angezeigt und ob es einen Fehler beim Auslesen des SCD30 gibt



#include "Wire.h"
#include "SCD30.h"
#include <LiquidCrystal_I2C.h> 
#include "RTClib.h"

#define FAN 5
//#define FAN_PWM 6     // BeQuiet 120mm 2,4W (12V)
#define FOGGER 7
#define LED 6

float SENSOR_DATA[3];
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS3231 rtc;
DateTime now;

bool lightOn = false;

float daytimeHumidity = 50.0; // bei Nacht: LF 50%
float nighttimeHumidity = 85.0; // bei Tag: LF 80%
float targetHumidity = nighttimeHumidity;
 
#if defined(ARDUINO_ARCH_AVR)
    #pragma message("Defined architecture for ARDUINO_ARCH_AVR.")
    #define SERIAL Serial
#elif defined(ARDUINO_ARCH_SAM)
    #pragma message("Defined architecture for ARDUINO_ARCH_SAM.")
    #define SERIAL SerialUSB
#elif defined(ARDUINO_ARCH_SAMD)
    #pragma message("Defined architecture for ARDUINO_ARCH_SAMD.")  
    #define SERIAL SerialUSB
#elif defined(ARDUINO_ARCH_STM32F4)
    #pragma message("Defined architecture for ARDUINO_ARCH_STM32F4.")
    #define SERIAL SerialUSB
#else
    #pragma message("Not found any architecture.")
    #define SERIAL Serial
#endif
 
 
void setup() {
  pinMode(FAN, OUTPUT);
  //pinMode(FAN_PWM, OUTPUT);
  pinMode(FOGGER, OUTPUT);
  pinMode(LED, OUTPUT);
  lightOn = false;
  digitalWrite(LED, LOW);
  Wire.begin();
  SERIAL.begin(115200);
  scd30.initialize();
  scd30.setAutoSelfCalibration(false);

  lcd.init(); //Im Setup wird der LCD gestartet 
  lcd.noBacklight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight();

  rtc.begin();
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

void ventilate(unsigned long duration) { // 
  if(SERIAL) {
    SERIAL.print("Ventilating for ");
    SERIAL.print(duration);
    SERIAL.println(" millis.");
  }

  lcd.setCursor(0, 2); // Zeile 3
  lcd.print("Ventilating for ");
  lcd.setCursor(0, 3); // Zeile 4
  lcd.print(duration/1000);
  lcd.print(" sec ...");

  //analogWrite(FAN_PWM, 255);
  digitalWrite(FAN, HIGH);
  delay(duration);
  //analogWrite(FAN_PWM, 0);
  digitalWrite(FAN, LOW);
}

void moisturize(unsigned long duration) {
  if(SERIAL) {
    SERIAL.print("Moisturizing for ");
    SERIAL.print(duration);
    SERIAL.println(" millis.");
  }

  lcd.setCursor(0, 2); // Zeile 3
  lcd.print("Moisturizing for ");
  lcd.setCursor(0, 3); // Zeile 4
  lcd.print(duration/1000);
  lcd.print(" sec ...");

  //analogWrite(FAN_PWM, 191);
  digitalWrite(FAN, HIGH);
  delay(200);
  digitalWrite(FOGGER, HIGH);
  delay(duration);
  //analogWrite(FAN_PWM, 0);
  digitalWrite(FAN, LOW);
  digitalWrite(FOGGER, LOW);
}

void printData() {
  SERIAL.print("Carbon Dioxide Concentration is: ");
  SERIAL.print(SENSOR_DATA[0]);
  SERIAL.println(" ppm");
  SERIAL.print("Temperature = ");
  SERIAL.print(SENSOR_DATA[1]);
  SERIAL.println(" ℃");
  SERIAL.print("Humidity = ");
  SERIAL.print(SENSOR_DATA[2]);
  SERIAL.println(" %");

  lcd.setCursor(0, 0); // Zeile 1
  lcd.print("CO2: ");
  lcd.print(SENSOR_DATA[0]);
  lcd.print(" ppm");

  lcd.setCursor(0, 1); // Zeile 2
  lcd.print("Humidity: ");
  lcd.print(SENSOR_DATA[2]);
  lcd.print("%");

  lcd.setCursor(0, 2); // Zeile 3
  lcd.print(now.timestamp(now.TIMESTAMP_TIME)); // aktuelle Uhrzeit anzeigen // die Uhrzeit wird überschrieben wenn gerade befeuchtet oder belüftet wird für x Sekunden
}
 
void loop() {
  lcd.clear(); // am Anfang des Loops wird der LCD immer gelöscht

  now = rtc.now();
  
  if(!lightOn && now.hour() > 7 && now.hour() < 19) {
    lightOn = true;
    digitalWrite(LED, HIGH);
  } else if (lightOn && (now.hour() < 7 || now.hour() >= 19)) {
    lightOn = false;
    digitalWrite(LED, LOW);
  }

  if(now.hour() >= 20 || now.hour() <= 7)  // einstellen von Nacht und Tagzeit
    targetHumidity = nighttimeHumidity;
  else 
    targetHumidity = daytimeHumidity;

  if(scd30.isAvailable()) {
    scd30.getCarbonDioxideConcentration(SENSOR_DATA);
    if(SERIAL)
      printData();

    if(SENSOR_DATA[0] > 900) { // wenn CO2- Werte über 900 belüften fur 3 Minuten 
      ventilate(180000);
      //moisturize(180000);
    } 
    
    if((targetHumidity - SENSOR_DATA[2]) > 10.0) { // wenn die LF abweicht um x dann befeuchten für y
      moisturize(300000);
    } else if ((targetHumidity - SENSOR_DATA[2]) > 5.0) {
      moisturize(180000);
    } else if ((targetHumidity - SENSOR_DATA[2]) > 1.0) {
      moisturize(60000);
    }
  } else {
    if(SERIAL)
      SERIAL.println("SCD30 not available!");
    lcd.setCursor(0, 0);
    lcd.print("SCD30 not available!");
  }

  delay(10000);
  if(SERIAL)
    SERIAL.println("----------------------------------");
}

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 05. November 2023 15:29
von ohkw
Die unterschiedlichen Tag Nacht Feuchtigkeiten sollen die nächtliche Taunässe simulieren. War so eine Idee, dass das für den Nelkenschwindling eine Rolle spielen könnte. Kann aber noch nicht sagen ob das wirklich einen Unterschied macht.

Das Tellerventil ist in der Konfiguration immer leicht offen und mehr dazu da einen eventuellen Rückstrom durch Kamineffekt zu bremsen.

Der Nebler steht seitlich neben dem Lufteinlass-Stutzen durch den der Lüfter bläst. Der Lüfter ist beim Befeuchten aus zwei Gründen an, nämlich erstens zum Verteilen des Nebels und zweitens um zu verhindern, dass Feuchtigkeit zum Ventilator und zum Hepa-Filter gelangt.

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 05. November 2023 15:59
von Leonardo Fiando
Der Nebler steht seitlich neben dem Lufteinlass-Stutzen durch den der Lüfter bläst
Also hier? :
ohkw Frage1.jpg
Das Tellerventil ist in der Konfiguration immer leicht offen und mehr dazu da einen eventuellen Rückstrom durch Kamineffekt zu bremsen.
Das heißt dann, das hier tendentiell Trauermücken eindringen könnten?
Können Trauermücken fruchtendem, durchgewachsenem Substrat überhaupt noch etwas anhaben?
Wenn ich es richtig verstehe, sind sie vor allem während des Mycelwachstums eine Gefahr.

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 05. November 2023 16:27
von ohkw
Ja, steht im eck in der Box hinter dem Lüfter.

Trauermücken können eindringen. Die befallen durchwachsene Kulturen und vermehren sich dann... Ein Mückennetz könnte das verhindern.

Re: Automatisierte Fruchtungsbox

Verfasst: Sonntag, 05. November 2023 18:11
von Leonardo Fiando
Alles klar, danke für die Infos! :)