TD One

Aus HRW FabLab MediaWiki
Wechseln zu: Navigation, Suche


Der TD One Begleiter für Menschen mit Einschränkungen. Dieser bietet Informationen zur richtigen Zeit am richtigen Ort.

TD One
TD One.jpeg

Entwickler

Anojan Natkuneswaran, Boris Kravcenko, Max Benzler, Alex Wick

Verwendete Programmiersprache

Arduino C/C++

Eingesetzte Software

Arduino IDE

Eingesetzte Hardware


Projektbeschreibung[Bearbeiten]

Prototyp
Plakat für das Projekt TD One


Das Gerät wird an der Wand vor den gefährlichen Bereichen, wie z.B. der Treppe gehängt, um Menschen mit Sehbeeinträchtigung zu warnen. Der Sensor reagiert auf die Bewegungen vor dem Gerät und dient als Schalter. Sobald eine Bewegung ermittelt wird, wird ein Akustisches Signal ausgegeben. Als Signale werden MP3-Dateien genutzt, die auf der SD-Karte gespeichert sind.
Die Als Prototyp entwickelte Variante dient zum Erläutern der lokalen Temperatur. Da es für die private Nutzung vorgesehen ist, gibt es hier den Ruhezeitmodus, während welchem es keine Audiosignale ausgegeben werden. Die Ruhezeit ist als Standard auf 21:00 Uhr bis 9:00 Uhr eingestellt.

Projektidee[Bearbeiten]

Da unser erstes Projekt, den wir nicht geschafft haben rechtzeitig anzufertigen, den Menschen mit Sehbeeinträchtigung dienen sollte, haben wir uns entschieden ein anderes für diese Zielgruppe zu entwickeln. So sind wir auf ein Warnmeldesystem gekommen, das im Beispiel einer privaten Nutzung als ein Wettervorhersager gilt.

Hardware[Bearbeiten]

Kostenaufstellung[Bearbeiten]

Materialliste
Beschreibung Anzahl Kosten
SDHC 8GB 1 3,69 €
Mini MP3 Player DFPlayer Modul 1 6,99 €
Arduino Lautsprecher 3 Watt 8 Ohm 1 5,99 €
Real Time Clock RTC DS3231 I2C Echtzeituhr 1 6,29 €
HC-SR501 Bewegungssensor 1 1,99 €
9V Batterie-Halter 1 3,49 €
Ein-/Aus-Schalter 1 0,27 €
9V Batterie 1 1,20 €
Plastik Gehäuse 1 1,99 €
Gesamtkosten: 31,90 €

Elektronik[Bearbeiten]

System[Bearbeiten]

Systemschema

Das System besteht aus den folgenden Komponenten: Arduino Uno, Bewegungssensor, Echtzeituhr, MP3 Player, Lautsprecher, Batterie-Halter, 9V-Batterie und Schalter.

Bewegungssensor[Bearbeiten]

HC-SR501 Sensor

Sorgt zum Entdecken der Bewegungen im Bereich, in dem die Änderungen der Infrarotwärme in der Umgebung ermittelt werden.
Quelle 1: Tutorium zum Verbinden des HC-SR501-Sensors zum Arduino.

Mini MP3 Player[Bearbeiten]

MP3-TF-16P Player

Ermöglicht das Abspielen der MP3-Dateien, die sich auf der im Player eingebauten Micro-SD-Karte befinden. Das Abspielen der Dateien erfolgt indexweise, wobei der erste Index den wert "1" hat, und der letzte gleich der Anzahl der Dateien ist. Beispielcode zum Erstellen des Player-Objektes und Abspielen einer bestimmten Datei:

DFRobotDFPlayerMini myDFPlayer; // Player-Modul definieren
myDFPlayer.begin(mySoftwareSerial) // Software-artige Kommunikation für den Player-Modul setzen
myDFPlayer.volume(30); // Lautstärke (0-30) setzen
myDFPlayer.play(4); // MP3-Datei mit dem Index "4" abspielen

Quelle 2: Tutorium zum Verbinden des MP3-TF-16P Player-Moduls zum Arduino. Hier wird auch das Anschließen des Lautsprechers berücksichtigt.
Quelle 3: Der Dienst, der zur Umwandlung des Textes in die Sprache und zum nachfolgendeт Speichern als MP3-Dateien verwendet wurde. Hier wurde die Deutschsprachige Stimme "Hans" verwendet.

Lautsprecher[Bearbeiten]

3 Watt 8 Ohm Lautsprecher

Sorgt für die Qualität der Audio-Signale.

Echtzeituhr[Bearbeiten]

RTC-DS3231

Wird zum Ermitteln der aktuellen Zeit verwendet, um anhand dieser dann zu entscheiden, ob es sich im Ruhezeiten-Bereich befindet, während welcher keine akustischen Signal-Ausgaben in der Variante für die private Nutzung erfolgen werden.
Quelle 4: Tutorium zum Verbinden der RTC-DS3231 Echtzeituhr-Moduls zum Arduino.

Batterie-Halter[Bearbeiten]

9V-Batterie-Halter

Das 9V-Batterie-Enthaltende Gehäuse.
Quelle 5: Tutorium zum Verbinden des Batterie-Halter-Moduls zum Arduino. Hier wird auch das Anschließen des Schalters berücksichtigt.

Batterie[Bearbeiten]

9V-Batterie

Die 9V-Batterie gilt als Grundversorgung.

System-Schalter[Bearbeiten]

Ein-/Aus-Schalter

Sorgt zum Ein- und Ausschalten des Systems.

Gehäuse[Bearbeiten]

Gehäuse

Das zum Aufbau des Prototyps verwendete Gehäuse.

Software[Bearbeiten]

Arduino Uno Programmcode[Bearbeiten]

#include "Arduino.h" // Hauptbibliothek für Arduino SDK
#include "SoftwareSerial.h" // Bibliothek zur Software-artigen Kommunikation zwischen den Modulen und dem Arduino-System
#include "DFRobotDFPlayerMini.h" // Bibliothek für den Player-Modul
#include <Wire.h> // Bibliothek zur Kommunikation mit den I2C/TWI-Modulen
#include <RtcDS3231.h> // Bibliothek für den RTC-Modul (Real Time Clock) https://github.com/Makuna/Rtc

#define inputPin 7 // Den Eingabe-Pin für den Bewegungssensor definieren

RtcDS3231<TwoWire> Rtc(Wire); // Real-Time-Clock Module
SoftwareSerial mySoftwareSerial(10, 11); // die Pins 10 und 11 als RX-, TX-Pins entsprechend nutzen
DFRobotDFPlayerMini myDFPlayer; // Player-Modul definieren
void printDetail(uint8_t type, int value); // Funktion zur Ausgabe der Plaer-Meldungen definieren

int temperature = -99; // Variable zum Speichern des Temperatur-Wertes
int pirState = LOW; // Variable zum Speichern des Wertes des Bewegungssensor-Signals
int pirVal = 0; // Variable zum Lesen des Wertes des Bewegungssensor-Signals
static long calibrationTime = 60000; // Zeit für den Bewegungssensor um sich an die Umgebung anzupassen (Wärme des Raumes)
static long notificationInterval = 5000; // Pause zwischen den Erläuterungen (inkl. die Dauer der Erläuterungen selbst)
static unsigned long timer = millis(); // Timer definieren und starten
bool playerOnline = false; // Variable zum Angeben ob das Player-Modul erfolgreich erstellt werden konnte
bool sensorCalibrated = false; // Variable zum Angeben ob der Bewegungssensor sich an die Umgebung anpassen konnte
bool silentModeOn = true; // Variable zum Angeben ob Ruhezeit momentan aktiviert ist oder nicht.
unsigned short silentModeBeginHours = 21; // Zeit (Stunden), wenn die Ruhezeiten anfangen (0-23). Ab diesem Zeitpunkt wird das System stummgeschaltet. Standardwert = 21 Uhr.
unsigned short silentModeBeginMinutes = 0; // Zeit (Minuten), wenn die Ruhezeiten anfangen (0-59). Ab diesem Zeitpunkt wird das System stummgeschaltet. Standardwert = 00 Minuten.
unsigned short silentModeEndHours = 9; // Zeit (Stunden), wenn die Ruhezeiten enden (0-23). Ab diesem Zeitpunkt wird das System Audiosignale ausgeben. Standardwert = 00 Minuten.
unsigned short silentModeEndMinutes = 0; // Zeit (Minuten), wenn die Ruhezeiten enden (0-59). Ab diesem Zeitpunkt wird das System Audiosignale ausgeben. Standardwert = 09 Uhr.

void setup() { // Programmteil, welches beim Starten des Systems ausgeführt wird
  Rtc.Begin(); // RTC (Real Time Clock) starten
  mySoftwareSerial.begin(9600); // Datenrate für Kommunikation mit dem Player über Serial Monitor
  Serial.begin(9600); // Datenrate für Kommunikation über Serial Monitor
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); // aktuelle Datum und Uhrzeit setzen

  if (!Rtc.IsDateTimeValid()) { // prüfen ob Datum und Uhrzeit richtig gesetzt wurde
    if (Rtc.LastError() != 0) { // wenn nicht, prüfen ob es beim RTC schon vorher einen Fehler gab
      // we have a communications error seefor what the number means
      Serial.print("RTC communications error = "); // Fehler melden
      Serial.println(Rtc.LastError()); // Fehler ausgeben; mögliche Fehler: https://www.arduino.cc/en/Reference/WireEndTransmission
    } else { // sonst (es gab keinen Fehler)
      Serial.println("RTC lost confidence in the DateTime!"); // den Fall melden
      Rtc.SetDateTime(compiled); // Datum setzen
    }
  }

  if (!Rtc.GetIsRunning()) { // prüfen ob RTC läuft
    Serial.println("RTC was not actively running, starting now"); // den Fall melden
    Rtc.SetIsRunning(true); // RTC starten
  }

  RtcDateTime now = Rtc.GetDateTime(); // aktuelle Zeit
  if (now < compiled) { // prüfen, ob aktuelle Zeit kleiner als kompilierte Zeit ist
    Serial.println("RTC is older than compile time! (Updating DateTime)"); // Fall melden
    Rtc.SetDateTime(compiled); // Datum und Uhrzeit setzen
  } else if (now > compiled) { // prüfen, ob aktuelle Zeit größer als kompilierte Zeit ist
    Serial.println("RTC is newer than compile time. (this is expected)"); // Fall melden
  } else if (now == compiled) { // sonst (aktuelle und kompilierte Zeiten sind gleich)
    Serial.println("RTC is the same as compile time! (not expected but all is fine)"); // Fall melden
  }

  Rtc.Enable32kHzPin(false); // Standardfrequenz für RTC-Modul setzen
  Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); // Pin deaktivieren

  if (!validBeginEndTimespan(silentModeBeginHours, silentModeBeginMinutes, silentModeEndHours, silentModeEndMinutes)) { //  prüfen ob Ruhezeit-Werte richtig gesetzt sind, wenn nicht - Standardwerte setzen
    Serial.println("Silent mode time has been overriden with default values."); // Fall melden
    silentModeBeginHours = 21; // Anfang der Ruhezeit auf 21:00 Uhr setzen
    silentModeBeginMinutes = 0;
    silentModeEndHours = 9; // Ende der Ruhezeit auf 09:00 Uhr setzen
    silentModeEndMinutes = 0;
  }

  // Player Meldungen
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) { // Software-artige Kommunikation für den Player-Modul setzen
    // Fall melden
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    playerOnline = false; // angeben, dass Player-Modul nicht definiert werden konnte
  } else { // sonst
    Serial.println(F("DFPlayer Mini online.")); // Fall melden
    playerOnline = true; // angeben, dass Player-Modul erfolgreich definiert wurde
  }

  if (playerOnline) { // falls Player-Modul verfügbar ist
    myDFPlayer.volume(30); // Lautstärke (0-30) setzen
    myDFPlayer.play(103); // Erläuterung: "System eingeschaltet."
  }

  pinMode(inputPin, INPUT); // den Bewegungssensor als Eingabe definieren
}

void loop() { // Programteil, welches nach dem Startup-Code ausgeführt wird und sich durchgehend wiederholt

  if (!Rtc.IsDateTimeValid()) { // prüfen ob Datum und Uhrzeit richtig gesetzt wurden, wenn nicht
    if (Rtc.LastError() != 0) { // prüfen ob es beim RTC schon vorher einen Fehler gab
      Serial.print("RTC communications error = "); // Fehler melden
      Serial.println(Rtc.LastError()); // Fehler ausgeben; mögliche Fehler: https://www.arduino.cc/en/Reference/WireEndTransmission
    } else { // sonst (es gab keinen Fehler)
      Serial.println("RTC lost confidence in the DateTime!"); // den Fall melden
    }
  } else { // sonst (wenn das Datum und Uhrzeit richtig gesetzt wurden)
    silentModeOn = silentModeTime(); // Ruhezeiten als wahr oder falsch, abhängig von aktueller Zeit setzen
  }

  if(!sensorCalibrated && millis() - timer > calibrationTime) { // falls der Sensor nicht angepasst wurde, aber die Anpassungszeit nach dem Starten des Systems vorbei ist
    sensorCalibrated = true; // die Variable zum Angeben, dass der Sensor angepasst wurde wahr setzen
    Serial.println("Bewegungssensor wurde angepasst!"); // den Fall melden
    if (playerOnline && !silentModeOn) { // während der nicht-Ruhezeiten auch akustisch melden
      myDFPlayer.play(104); // Erläuterung: "Der Sensor wurde angepasst."
    }
  } else { // sonst
    if(!sensorCalibrated) { // falls der Sensor nicht angepasst wurde, die Dauer bis zum Anpassen melden
      Serial.print("Dauer zum anpassen des Bewegungssensors: ");
      Serial.print(millis() - timer);
      Serial.print(" (");
      Serial.print(calibrationTime);
      Serial.println(")");
    }
  }

  // Bewegungssensor-Aktivität
  if (sensorCalibrated) { // falls der Sensor angepasst wurde
    pirVal = digitalRead(inputPin); // den aktuellen Wert des Signals vom Bewegungssensor ablesen

    if (pirVal == HIGH) { // falls der Pegel hoch ist
      if (pirState == LOW) { // aber vorhin niedrig war
        Serial.println("Bewegungssensor: Bewegung ermittelt!"); // den Fall (Bewegung wurde ermittelt) melden
//        if (playerOnline) {myDFPlayer.play(107);} // akustischen Signal zum Entdecken der Bewegung melden
        pirState = HIGH; // den Pegel hoch setzen

        // Hauptprogramm
        if(playerOnline && sensorCalibrated) { // wenn der Player und der Sensor gefunden waren, der Sensor sich an die Umgebung angepasst hat und geschaltet wird
          if (millis() - timer > notificationInterval) { // und der Wert des Timers größer als vordefinierte Pause zwischen den Erläuterungen beträgt
            RtcTemperature temp = Rtc.GetTemperature(); // wird die Temperatur vom RTC-Modul abgelesen
            temperature = (int) temp.AsFloatDegC(); // und in einen Integer-Wert umgewandelt
            Serial.print("Temperatur: "); // Temperatur melden
            Serial.println(temperature); // und den Wert ausgeben
            if(!silentModeOn) {notifyTemperature(temperature);} // wärend nicht-Ruhezeiten Temperatur akustisch erläutern
          }
        }
      }
    } else { // sonst (der Pegel ist niedrig)
      if (pirState == HIGH) { // aber vorhin hoch war
        Serial.println("Bewegungssensor: Bewegung aufgehört!"); // den Fall (Bewegung wurde aufgehört) melden
//        if (playerOnline) {myDFPlayer.play(106);} // akustischen Signal zum Aufhören der Bewegung melden
        pirState = LOW; // den Pegel niedrigsetzen
      }
    }
  }

  notify(true); // Meldungen ausgeben

  delay(500); // Pause zwischen den Wiederholungen des Schleifen-Codes
}

void printDetail(uint8_t type, int value){ // Player-Fehler-Melder
  switch (type) { // zutreffenden Fall auswerten
    case TimeOut: Serial.println(F("Time Out!")); break; // Zeit ist abgelaufen
    case WrongStack: Serial.println(F("Stack Wrong!")); break; // falsches Stack
    case DFPlayerCardInserted: Serial.println(F("Card Inserted!")); break; // Karte wurde eingesetzt
    case DFPlayerCardRemoved: Serial.println(F("Card Removed!")); break; // Karte wurde entfernt
    case DFPlayerCardOnline: Serial.println(F("Card Online!")); break; // Karte ist aktiv
    case DFPlayerPlayFinished: Serial.print(F("Number:")); Serial.print(value); Serial.println(F(" Play Finished!")); break; // Wiedergabe erledigt
    case DFPlayerError: // Fehler-Fall
      Serial.print(F("DFPlayerError:")); // Fehler melden
      switch (value) { // Fehler auswerten
        case Busy: Serial.println(F("Card not found")); break; // Karte nicht gefunden
        case Sleeping: Serial.println(F("Sleeping")); break; // Schlafmodus ist aktiv
        case SerialWrongStack: Serial.println(F("Get Wrong Stack")); break; // falsches Stack
        case CheckSumNotMatch: Serial.println(F("Check Sum Not Match")); break; // falsches CheckSum
        case FileIndexOut: Serial.println(F("File Index Out of Bound")); break; // falsches Datei-Index
        case FileMismatch: Serial.println(F("Cannot Find File")); break; // Datei konnte nicht gefunden werden
        case Advertise: Serial.println(F("In Advertise")); break;
        default: break; // sonst keine Fehlermeldung
      } break;
    default: break; // sonst keine Meldung
  }
}

void notifyTemperature(int value) { // Audioausgabe

  if (value >= -50 && value <= 50) { // falls der Wert zutrifft (befindet sich im Bereich von -50°C bis +50°C), Temperatur erläutern
    myDFPlayer.play(value + 51); // die zutreffende MP3-Datei abspielen
  } else { // sonst
    myDFPlayer.play(102); // Meldung erläutern: "Es besteht keine Internetverbindung!"
  }

  timer = millis(); // Timer neustarten
}

void notify(bool b) { // textuelle Ausgabe der Meldungen
  if(b) { // falls der Parameter wahr ist
    if(playerOnline) Serial.print("P:ON, "); else Serial.print("P:OFF, "); // Player Status: aktiv | inaktiv
    if(sensorCalibrated) Serial.print("SC:+, "); else Serial.print("SC:-, "); // Bewegungssensor Status: positiv (Anpassung erledigt) | negativ (wird angepasst)
    if(silentModeOn) Serial.println("SM:ON"); else Serial.println("SM:OFF"); // Ruhezeit-Status: aktiv | inaktiv
  }
}

bool validHoursAndMinutes(unsigned short hours, unsigned short minutes) {return hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59;} // Funktion zum Überprüfen der Werte der Zeitangabe auf Richtigkeit (Realität)

bool validBeginEndTimespan(unsigned short beginHours, unsigned short beginMinutes, unsigned short endHours, unsigned short endMinutes) { // Funktion zum Prüfen der Ruhezeiten auf Richtigkeit (Realität)
  return validHoursAndMinutes(beginHours, beginMinutes) && validHoursAndMinutes(endHours, endMinutes) // richtige Zeitangabe für Anfangs- und Endspanne.
      && ((beginHours < endHours) || beginHours == endHours && beginMinutes < endMinutes); // Anfangszeit ist kleiner als Endzeit.
}

bool silentModeTime() { // Funktion zum Angeben ob die aktuelle Zeit sich im Ruhezeit-Bereich befindet
  RtcDateTime now = Rtc.GetDateTime(); // aktuelle Zeit in einer Variable abspeichern
  return (now.Hour() > silentModeBeginHours && now.Hour() < silentModeEndHours) || ((now.Hour() == silentModeBeginHours && now.Minute() >= silentModeBeginMinutes) || (now.Hour() == silentModeEndHours && now.Minute() <= silentModeEndMinutes)); // aktuelle Zeit mit der Ruhezeit vergleichen
}

Erweiterungs-Möglichkeiten[Bearbeiten]

WiFi-Unterstützung[Bearbeiten]

Mithilfe der WiFi-Unterstützung wäre es möglich bestimmte Daten aus dem Internet abzurufen und diese im System entsprechend zu bearbeiten. So könnte man beispielsweise für die private Nutzung das Systems in ein Wettervorhersagesystem umwandeln.

Steuerungs-App für Smartphones[Bearbeiten]

Für die Konfiguration bestimmter Daten per Smartphone-Anwendung, wie die Auswahl und Verbindung zum WLAN-Netzwerk, das Einstellen der Ruhezeiten usw.