Introduction: KnockKnock - Open Your Door by Knocking
Es gibt heutzutage viele Arten von Authentifizierung. Während das Passwort am häufigsten verwendet wird, gab es schon in analogen Zeiten das Klopfmuster. Warum nicht Türen damit öffnen?
Wir haben uns vorgenommen ein Modul zu bauen, dass Klopfmuster an der Tür erkennt und die Tür bei Übereinstimmung öffnet, indem der Schlüssel umgedreht wird.
Supplies
- Arduino
- Motor - V-TEC 12V DC 6mm Antriebswelle Schneckengetriebemotor 100RPM
- Control Board - Pololu DRV8876
- Mikrofon (Sensor)
- Case - 3D Print
- Tür (inkl. Schloss)
- Lautsprecher
Step 1: Klopfer Erkennen
Problem: Geringer Rausch-Signal-Abstand,
Lösung: Empfindlichkeit des Mikrofons erhöhen und feinjustieren
Wir haben zu dritt verschiedene Module getestet (z.B: Piezzoelement) zum erkennen von Klopfen und haben uns für das Mikrofonmodul entschieden. Wir haben den Analogausgang des Mikrofons verwendet, welcher 0-5V sendet, statt dem Digitalausgang, der ab einem bestimmten Schwellenwert 5v sendet, um die Werte auszulesen. Dadurch können wir in der Software flexibler mit dem Signal arbeiten und es dort feinjustieren. Die Empfindlichkeit des Signals konnte an dem Modul mit einer Schraube eingestellt werden.
Mit einem Rauschboden von ca. 2V und dem Klopfen dass bis 2.5V ging hatten wir eine Ausgangsposition um Klopfer zu erkennen. Je empfindlicher das Mikrofon eingestellt wurde, desto höher war der Rauschboden, aber auch der Rausch-Signal-Abstand. Die maximale Dauer eines Klopfers, also der Klangschwingungen eines Klopfers über dem Threshold, haben wir mit 50ms delay nach einer Erkennung festgelegt. Dadurch wurde ein Klopfer nicht als mehrere erkannt, man kann aber auch kein double-time mehr klopfen.
Diese Logik haben wir in die Funktion detectKnock geschrieben, welche in einer While-Schleife wartet und entweder den Zeitstempel des erkannten Klopfers in ms zurückgibt oder nach 5 Sekunden abbricht und das mit der Rückgabe von -1 angibt.
long detectKnock(){
long start = millis();
while((analogRead(inputPinMic) * (5.0 / 1023.0)) <= thresh){
if(millis() - start >= 5000){
return -1;
}
}
return millis();
}
Step 2: Klopfmuster Erkennen
Problem: Klopfmuster geht bei Neustart oder Stromabbruch verloren
Lösung: Klopfmuster im nichtflüchtigen EEPROM speichern
Problem: Wurde das eingegebene Klopfmuster richtig erkannt?
Lösung: Ausgabe des gespeicherten Musters mit LED bzw. Lautsprecher nach dem einspeichern
Wir haben Klopfmuster als Zeit in ms zwischen Klopfern in einem Array gespeichert. Um Klopfmuster abzugleichen haben wir die jeweilige Zeit zwischen den Eingabeklopfern mit den gespeicherten Zeiten verglichen und jeweils eine feste Fehlerzeit zugelassen. Meine Idee, es zu ermöglichen Klopfmuster in verschiedenen Geschwindigkeiten zu klopfen, indem ein Skalierungsfaktor erkannt und auf die Delays mulitpliziert wird, haben wir nicht umgesetzt.
Diese Logik haben wir in die Funktion writePattern bzw. matchPattern geschrieben.
writePattern speichert die Zeiten in ms von detectKnock als Array in den EEPROM-Speicher. Dabei werden einfach die Keys ab 0 aufwärts verwendet. Ein Klopfer als int wird dabei in zwei bytes aufgeteilt und belegt damit zwei Keys. Mit 1024 bytes Speicherplatz könnten somit theoretisch 512 Klopfer gespeichert werden. Um das Ende eines Klopfmusters zu markieren, wird am Schluss zwei Bytes mit dem Wert 255 abgespeichert.
void writePattern(){
Serial.println("Writing Pattern now");
long lastStep = detectKnock();
delay(50);
if(lastStep == -1){
Serial.println("No knock detected resuming with old one");
return;
}
long currentTime;
int i = 0;
//detect knock at the end of loop to wait for the next
while((currentTime = detectKnock()) != -1){
delay(50);
int difference = currentTime - lastStep;
byte second = (byte) (difference & 0xFF);
byte first = (byte) ((difference >> 8) & 0xFF);
Serial.print(first);
Serial.print(" ");
Serial.println(second);
EEPROM.write(i++, first);
EEPROM.write(i++, second);
//TODO vielleicht ein delay hinzufügen
lastStep = currentTime;
}
EEPROM.write(i++, 255);
EEPROM.write(i, 255);
Serial.println("Finished Pattern now");
Um zu überprüfen, ob das Klopfmuster richtig erkannt wurde, wird es noch einmal ausgegeben über ein LED bzw. einen Lautsprecher.
i = 0;
int allowedDifference = 0;
byte first;
byte second;
do{
delay(allowedDifference);
analogWrite(ledPin, 60);
delay(50);
analogWrite(ledPin, 0);
first = EEPROM.read(i++);
second = EEPROM.read(i++);
allowedDifference = 0;
allowedDifference |= first; // Set the high byte
allowedDifference = allowedDifference << 8; // Shift the high byte to the left by 8 bits
allowedDifference |= second;
}while(first != 255);
} //writePattern end
matchPattern list diese gespeicherten Zeiten aus und vergleicht sie jeweils mit der letzten Zeit aus detectKnock abzüglich Fehlertoleranz. Falls die Zeit in der Toleranz liegt, wir die Schleife wiederholt, sodass entweder wegen einer falschen Zeit false zurückgegeben wird oder die zwei Bytes mit Wert 255 gelesen werden und true zurückgegeben wird.
int matchPattern(){
long lastStep = millis();
delay(50);
long currentTime;
int i = 0;
int tolerance = 70;
byte first = EEPROM.read(i++);
byte second = EEPROM.read(i++);
while((currentTime = detectKnock()) != -1){
int allowedDifference = 0;
allowedDifference |= first; // Set the high byte
allowedDifference = allowedDifference << 8; // Shift the high byte to the left by 8 bits
allowedDifference |= second;
Serial.print((currentTime - lastStep));
Serial.print(" ");
Serial.println(allowedDifference);
if((currentTime - lastStep) <= (allowedDifference - tolerance) ||
(currentTime - lastStep) >= (allowedDifference + tolerance)){
return 0;
}
lastStep = currentTime;
first = EEPROM.read(i++);
second = EEPROM.read(i++);
if((first == 255) && (second == 255)){
return 1;
}
delay(50);
}
}
Step 3: Schlüssel Umdrehen
Problem: Wann ist die Tür auf?
Lösung: Verwendung des Control Boards um hohen Stromfluss zu erkennen.
Problem: Wie kann die Tür abgeschlossen werden?
Lösung: Wäre freidrehender Motor und Schloss mit der Möglichkeit auf beiden Seiten ein Schlüssel reinzustecken (hatten wir nicht). Oder Motorsansteuerung von außerhalb. Abschließen von innen (Sichtkontakt zur Tür) mit Fernbedienung ist möglich.
Um die Tür bei übereinstimmenden Klopfmustern dann auch zu öffnen, haben wir einen Motor entsprechend programmiert und mit einem Haken in den Schlüssel im Schloss eingehakt. Über ein Control Board konnten wir erkennen wann der Motor gegen einen Widerstand stieß und nicht mehr weiter drehte um daraus zu schließen, dass das Schloss offen ist.
Step 4: Zusammenbauen
An einer Testtür haben wir schließlich alle verlöteten Komponente angebracht in einem 3D-gedruckten Case.
Mit einem Knopf kann die Musteraufnahme gestartet werden, zwei LEDs zeigen mit rot und grün an, ob ein Muster richtig oder falsch war und ein Lautsprecher gibt, zusätzlich zu weiteren Sounds, noch das eingespeicherte Muster einmal aus.
Step 5: Anwendungsablauf
Zuerst kann nach dem drücken des Knopfes ein Klopfmuster eingespeichert werden. Durch die Lautsprecherausgabe kann man erkennen, ob das Muster richtig aufgenommen wurde.
Daraufhin kann man aus der Tür gehen und sie schließen. (Abschließen funktioniert noch nicht)
Wenn man wieder eintreten will, kann man mit dem vorher gespeicherten Muster an die Tür klopfen und sie öffnet sich automatisch.