MINT-Bioreaktor Wettbewerb

Leitfaden Wettbewerb

Der Leitfaden gibt euch einen ausführlichen Überblick über die Rahmenbedingungen und Anforderungen zum Wettbewerb und kann hier heruntergeladen werden: Leitfaden-Wettbewerb.pdf

Eine grobe Zusammenfassung bietet auch ein Poster: MINT-Bioreaktor Wettbewerb

Projektskizze

Die Projektskizze dient als Grundlage für die Planung eures Forschungsvorhabens und entscheidet darüber, ob ihr in die nächste Wettbewerbsrunde kommt.

Sie muss bis zum 12.11.2024 per Mail an zentral-freilandmobil@rptu.de eingereicht werden.

Tipp: sowohl der Artikel “Mikrocontroller als Low Cost Technologie” als auch das Beispielposter 2 “Entwicklung eines Low-Cost Photobioreaktors für den MINT-Unterricht” geben Ideen für potenzielle Weiterentwicklungen, die im Rahmen des Wettbewerbs umgesetzt werden können.

Projektskizze.docx

Projektskizze.pdf

Literatur

Die bereitgestellte Literatur soll euch eine Orientierung als mögliche fachliche Grundlage bieten und kann den Ausgangspunkt euer eigenen Literaturrecherche darstellen.

Photobioreaktoren

Mikroalgen

Forschungsbeispiele

MINT-Bioreaktor

In den folgenden interaktiven Erklärvideos wird eine Einführung in die Funktionsweise des MINT-Bioreaktors gegeben sowie der Bau in einer Schritt-für-Schritt-Anleitung dargestellt.

Nach erfolgreicher Installation des MINT-Bioreaktors werden alle Messdaten per WLAN auf folgender Plattform dargestellt: https://photobioreaktor.org

Einführung

Bau

Der Zusammenbau wird zunächst als Zeitraffer dargestellt und danach in acht interaktive Videos aufgeteilt.

Eine zusätzlich bebilderte Anleitung kann hier heruntergeladen werden: Anleitung.pdf

Alle käuflichen Bauteile sind in folgender Liste hinterlegt: Material.xlsx

Alle 3D gedruckten Teile können mit folgenden Dateien selbst gedruckt werden: 3D Druck.zip

Zeitraffer
Schritt 01 – 07
Schritt 08 – 14
Schritt 15 – 17
Schritt 18 – 23
Schritt 24 – 31
Schritt 32- 37
Schritt 38 – 44
Schritt 45 – 51

Installation

Die Installation der Software für den MINT-Reaktor erfolgt über den Microcontroller ESP32. Die Programmierung basiert auf der Programmiersprache für den Arduino Microcontroller.

Die Arduino-Webseite bietet dafür ein Glossar wo alle Funktionen, Variablen und Strukturbefehle, die ein Arduino-Programm enthalten kann, ausführlich erklärt werden.

Das Benutzerhandbuch des Photobioreaktors kann hier heruntergeladen werden: Benutzerhandbuch.pdf

Die Dokumentation des Quellcodes ist eingebettet, kann jedoch auch als HTML hier heruntergeladen werden: Code.html

Zusätzlich werden zwei Konfigurationsdateien benötigt, die hier heruntergeladen werden können: Config.h und MINT-Bioreaktor.ino

Die Dokumentation enthält auf der linken Seite den vollständigen Quellcode und rechts eine zugehörige Beschreibung des jeweiligen Code-Abschnittes. Einige der Beschreibungen lassen sich durch Anklicken aufklappen, um noch detailliertere Informationen zu erhalten.

Um den Quellcode auf den Microcontroller zu installieren, wird das Programm ArduinoIDE benötigt, das hier heruntergeladen werden kann: ArduinoIDE

Photobioreaktor Code-Dokumentation
#include <Arduino.h>

Stellt grundlegende Arduino-Funktionen und -Definitionen bereit. Sollte in jedem Arduino-Sketch enthalten sein.

#include <ArduinoJson.h>
#include <ArduinoJson.hpp>

Ermöglicht JSON-Daten zu verarbeiten.

#include <Wire.h>

Ermöglicht die Kommunikation über I2C-Protokoll.

#include <WiFiManager.h>
WiFiManager wfm;

Verwaltet die WLAN-Verbindung und konfiguriert sie. Erstellen eines Objektes vom Typ WiFiManager mit dem Namen wfm. Dadurch kann man die Funktionen der WiFiManager-Bibliothek mit “wfm.Funktion” aufrufen.

#include <WiFi.h>

Ermöglicht die Verbindung zum drahtlosen Netzwerk.

#include <InfluxDbClient.h>

Ermöglicht die Kommunikation mit einer InfluxDB-Datenbank.

#include <InfluxDbCloud.h>

Ermöglicht die Kommunikation mit InfluxDB Cloud.

#include <HTTPClient.h>
HTTPClient http;

Ermöglicht das Senden von HTTP-Anfragen.

#include <Preferences.h>
Preferences pref

Ermöglicht die Verwendung von dauerhaften Speichereinstellungen.

#include <ezTime.h>
Timezone myTZ

Ermöglicht die einfache Verwendung von Zeit- und Datumsservices.

//Photobioreactor Library
#include <Photobioreactor.h>
Photobioreactor pb

Enthält viele wichtige, eigens für den Reaktor definierte Hilfsfunktionen.

#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

Definition eines Makro SERIAL, das auf Serial oder SerialUSB je nach Board-Architektur (SAMD oder nicht) verweist. Dieses Makro wird später im Code verwendet, um auf ein Objekt für die serielle Kommunikation zu verweisen. Ziel ist, die Auswahl zwischen Serial und SerialUSB je nach Board-Architektur zu ermöglichen..

//TEMP

#include <OneWire.h>
#include <DallasTemperature.h>

Ermöglicht die Kommunikation mit Temperatursensoren der Dallas-Reihe.

//Define InfluxDB

#include "Config.h" //You can change your InfluxDB Instance here

Sie enthält Konfigurationsvariablen für die Verbindung zur InfluxDB-Datenbank.

InfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, InfluxDbCloud2CACert);
Point sensor("SampleData");
  • Die InfluxDB-Instanz wird verwendet um eine Verbindung zur InfluxDB-Datenbank herzustellen und Daten in sie zu schreiben. Die Parameter in der Klammer werden aus der Config.h Datei geladen.
  • Die Point-Instanz wird verwendet, um Datenpunkte zu repräsentieren, die in die InfluxDB-Datenbank geschrieben werden sollen. “SampleData” ist der Name des Datenpunkts, der in der Datenbank erstellt und gespeichert wird.
//TDS

const int tdsSensorPin = 35;
const int VREF = 3.3; // analog reference voltage(Volt) of the ADC
int analogBuffer[0]; // store the analog value in the array, read from ADC

  • Definieren des Pin 35 an dem die Daten des TDS-Sensors ausgelesen werden.
  • Festlegen der Referenz-Spannung des Analog-Digital-Umsetzers des TDS-Sensors zur Berechnung des Messwertes.
  • Erstellen eines Arrays zur Zwischenspeicherung des analogen Messwertes des TDS-Sensors.

//Relay
const int heatPin = 14;
const int stirrerPin = 13;
const int lightPin = 12;

//Water Level I2C
const int I2C_SDA_PIN = 27;
const int I2C_SCL_PIN = 25;
int lowData[8] = {0};
int highData[12] = {0};
const byte NO_TOUCH = 0xFE;
const int THRESHOLD = 100;
const int ATTINY1_HIGH_ADDR = 0x78;
const int ATTINY2_LOW_ADDR = 0x77;
const int statusLED = 33;
int reconnectAttempt = 0;

  • Pins für die Daten- und Taktleitung des I2C-Busses (SDA und SCL).
  • Arrays der Daten, die vom Wasserstandssensor für den unteren und oberen Teil des Behälters gelesen werden.
  • Schwellenwerte ab dem ein Wasserstands-Messabschnitt als solcher gemessen wird.
  • Adressen der zwei ATTINY-Mikrocontrollern, die zur Steuerung des Wasserstandssensors verwendet werden.
  • Setzen der StatusLED auf Pin 33.
  • Variable für die Anzahl der Verbindungsversuche.

//TEMP
#define ONE_WIRE_BUS 32
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

  • Definieren der Pinnummer an die der Datenpin des DS18B20-Temperatursensors angeschlossen ist.
  • Erstellen einer DallasTemperature-Instanz mit der zuvor erstellten OneWire-Instanz zur Kommunikation des Sensors über den zuvor definierten Pin des OneWire Bus.

//Trigger for Reset
const int RESET_TRIGGER = 26;
int buttonState = 0;
int lastButtonState = 0;
int startPressed = 0;
int endPressed = 0;
int holdTime = 0;
int idleTime = 0;

  • Setzen der Pinnummer des Reset-Knopfs auf 12.
  • Variablen welche die Zeitpunkte speichern, an denen der Taster gedrückt und losgelassen wird (start & end).
  • Variable welche die Zeitdauer speichert, für die der Taster gedrückt wurde (“hold”).
  • Variable welche die Zeitdauer speichert, für die der Taster nicht gedrückt wurde (“idle”).

//Time Intervall for Data Transfer
bool dataSent = false;
int previousMinute = -1;

  • Die erste Variable speichert den Zustand (true/false), ob Daten an den Server gesendet wurden. Initial auf “false” gesetzt.
  • Die zweite Variable speichert den Zeitstempel der vorherige Minute. Initial -1 damit beim ersten Durchlauf des Codes Daten unabhängig von der tatsächlichen aktuellen Minute gesendet werden können.

//HalfHourly Time Sync
unsigned long previousMillisSync = 0;
unsigned long previousMillisPrint = 0;
const unsigned long intervalSync = 1800000;
const unsigned long intervalPrint = 60000;

  • Variable für Zeitpunkt des letzten Synchronisierungsvorgangs.
  • Variable für Zeitpunkt des letzten Druckvorgangs im seriellen Monitor.
  • Intervall zwischen zwei Synchronisierungsvorgängen.
  • Intervall zwischen zwei Druckvorgängen.

// Box für Zieltemperatur
WiFiManagerParameter(“MaxTemp_Text”, “Maximale Temperatur”, “32”, 2);
// Box für Minimaltemperatur
WiFiManagerParameter(“MinTemp_Text”, “Minimale Temperatur”, “25”, 2);
// Box für Abstand zwischen Rühren
WiFiManagerParameter(“IntervalStirrer_Text”, “Zeit zwischen den Rührvorgängen in Minuten”, “30”, 4);
// Box für Rührdauer>
WiFiManagerParameter(“DurationStirrer_Text”, “Dauer eines Rührvorgangs in Minuten”, “1”, 4);
// Box für Licht an
WiFiManagerParameter(“LightOn_Text”, “Uhrzeit (0-23) zum anschalten des Lichts”, “8”, 2);
// Box für Licht aus
WiFiManagerParameter(“LightOff_Text”, “Uhrzeit (0-23) zum abschalten des Lichts”, “20”, 2);

void.setup() {

Das void.setup() ist eine spezielle Funktion in Arduino-Programmen. Sie wird automatisch einmal ausgeführt, wenn das Arduino-Board eingeschaltet oder zurückgesetzt wird.

Serial.begin(115200);

Die Baud-Rate gibt die Übertragungsgeschwindigkeit für die serielle Kommunikation an. Die Einheit für die Baudrate ist Baud, was die Anzahl der Signalwechsel pro Sekunde bedeutet.

pref.begin(“Prefs”,false);
if (pref.getBool(“namebool”) == false)
{
int reactorNumber = (int)random(100000, 999999);
String reactorNameGenerated = String("ESP32_" + String(reactorNumber));
pref.putString("reactorNameUser", reactorNameGenerated);
pref.putBool("namebool",true);
Serial.println("Reaktorname: ");
Serial.println(reactorNameGenerated);
}

Der Reaktorname wird aus "ESP32_" und einer zufällig generierten Zahl erzeugt. Anschließend wird der Status des Namen "namebool" mit der Preference-Library auf true gesetzt. Zuletzt wird der generierte Reaktorname im seriellen Monitor ausgegeben.

WiFiManagerParameter Token_Text_Box("Token_Text", "Name des Reaktors", pref.getString("reactorNameUser").c_str(), 20);
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
pinMode(heatPin, OUTPUT);
pinMode(stirrerPin, OUTPUT);
pinMode(lightPin, OUTPUT);
pinMode(RESET_TRIGGER, INPUT_PULLUP);
pinMode(2, OUTPUT);
pinMode(statusLED, OUTPUT);
pinMode(tdsSensorPin, OUTPUT);
//initialise TEMPsensor
sensors.begin();
wfm.addParameter(&Token_Text_Box);
wfm.addParameter(&MaxTemp_Text_Box);
wfm.addParameter(&MinTemp_Text_Box);
wfm.addParameter(&IntervalStirrer_Text_Box);
wfm.addParameter(&DurationStirrer_Text_Box);
wfm.addParameter(&LightOn_Text_Box);
wfm.addParameter(&LightOff_Text_Box);
if (digitalRead(RESET_TRIGGER) == LOW)
{
Serial.println("HARDRESET");
pref.putBool("setupbool", false);
pref.putBool("namebool", false);
pref.clear();
wfm.resetSettings();
pb.blinkLEDs(1, 500);
ESP.deepSleep(10000000*10000000); //Sleep until Reset
}

Falls der Reset-Button gedrückt wurde, wird ein harter Reset ausgeführt mit Rücksetzen der Reaktornamen- und WifiManager-Einstellungen. Anschließend wird der ESP32 in den Tiefschlafmodus versetzt. Er stoppt die Ausführung des Codes und verbraucht sehr wenig Strom. Nach Ablauf des Zeitintervalls wird der Mikrokontroller wieder aktiviert und beginnt die Ausführung des Codes.

//Try to connect with Wifi network
wfm.setWiFiAutoReconnect(true);
wfm.setConnectRetries(10);
wfm.setConfigPortalTimeout(300);

  • Automatisches Wiederverbinden mit Wifi aktivieren.
  • Festlegen der Verbindungsversuche auf 10.
  • Festlegen des Timeout aus dem Konfigurationsportal auf 5 Minuten.

bool res = wfm.autoConnect(pref.getString("reactorNameUser").c_str());

Hierbei wird der zuvor erstellte "reactorNameUser" aus der Preference-Library als Schlüssel benutzt und der Zustand (true/false) in der Variable res abgespeichert.

if (!res)
{
waitForSync();
myTZ.setLocation("Europe/Berlin");
if (pref.getBool("resetbool") == false)
{
pref.putString("MinTemp",MinTemp_Text_Box.getValue());
pref.putString("MaxTemp", MaxTemp_Text_Box.getValue());
pref.putString("IntervalStirrer", IntervalStirrer_Text_Box.getValue());
pref.putString("DurationStirrer", DurationStirrer_Text_Box.getValue());
pref.putString("LightOn", LightOn_Text_Box.getValue());
pref.putString("LightOff", LightOff_Text_Box.getValue());
pref.putBool("resetbool", true);
}

Hierbei wird der zuvor erstellte "reactorNameUser" aus der Preference-Library als Schlüssel benutzt und der Zustand (true/false) in der Variable res abgespeichert.

if (pref.getBool("setupbool") == false)
{
pref.putString("reactorNameUser", Token_Text_Box.getValue());
pref.putBool("setupbool", true);
pb.blinkLEDs(10, 20);
}
}
String reactorNameUser = pref.getString("reactorNameUser");
const char* Reaktorname = reactorNameUser.c_str();
Serial.print("Your Reactor is called: ");
Serial.println(Reaktorname);
sensor.addTag("Reaktorname", Reaktorname);
//Write one initial Point for initial User Feedback
pb.addSensorData();
pb.writeSensorData();
}
void.loop() {

Die void.loop() ist ein spezielle Funktion in Arduino-Programmen. Der Code innerhalb der Funktion wird kontinuierlich wiederholt solange das Board mit Strom versorgt wird.

if (Wifi.status() == WL_CONNECTED)
{
Serial.println("Connected with Wifi!");
pb.setStatusLEDsHigh();
pb.checkResetButton(); // Check Button State and initialize Reset
pb.halfHourlySyncDeviceTime(); // Update Current Time
pb.printValues();

  • Kurzes Aufblinken der Status-LED.
  • Überprüfen des Status des Reset-Buttons.
  • Aktualisiert die Gerätezeit (alle 30 Minuten).
  • Ausgabe der aktuellen Sensormesswerte und Parameter.

// Control the Parameters
pb.controlWaterTemp();
pb.controlStirring();
pb.controlLight();
//Write Points
int currentHour = myTZ.hour();
int currentMinute = myTZ.minute();

if(currentMinute != previousMinute){
dataSent = false;
previousMinute = currentMinute;
}

delay(10);
if(((currentHour == 0 && currentMinute == 0) ||
(currentHour == 6 && currentMinute == 0) ||
(currentHour == 14 && currentMinute == 15) ||
(currentHour == 18 && currentMinute == 0)) &&
(!dataSent))
{
pb.addSensorData();
pb.writeSensorData();

// Set flag to true to indicate that the data has been sent
dataSent = true;
previousMinute = myTZ.minute();
delay(10);
}
}
else
{

  • Abrufen und Schreiben der aktuellen Sensordaten in die InfluxDB.
  • Sendestatus auf true setzen.
  • Aktualisieren der vergangenen Minute.

pb.setStatusLEDsLow();
wfm.disconnect();
if(wfm.getWiFiIsSaved()) wfm.setEnableConfigPortal(false);
wfm.autoConnect("AP");
wfm.autoConnect(pref.getString("reactorNameUser").c_str());

Serial.println("No WiFi");
}
Serial.print(".");
delay(100);
}

  • Verbindung zum WLAN wird getrennt.
  • Falls Wifi-Daten gespeichert sind, wird das Konfigurationsportal deaktiviert.
  • Versuch mit einem AccessPoint zu verbinden.
  • Erneuter Versuch sich mit dem zuvor gespeicherte WLAN zu verbinden.
  • Ausgabe der Meldung "No Wifi." im seriellen Monitor.

Poster

Für die Gestaltung des wissenschaftlichen Posters stehen drei verschiedene Vorlagen in jeweils vier unterschiedlichen Farbkombinationen bereit. Zudem bietet der Leitfaden zur Gestaltung von wissenschaftlichen Postern weitere Orientierung.

Leitfaden_RPTU-Forschungsposter

Forschungsposter_klassisch.pptx

Forschungsposter_modern_quer.pptx

Forschungsposter_innovativ.pptx

Zur Orientierung können hier zwei Beispielposter heruntergeladen werden:

Beispielposter_1.pdf

Beispielposter_2.pdf