Arduino Powered Door Opener, Activated by Knocks

by ckolan38 in Circuits > Arduino

185 Views, 3 Favorites, 0 Comments

Arduino Powered Door Opener, Activated by Knocks

Tür fertig_1.1.1.png

Das Knock Knock Projekt ist entstanden um die Menschheit vor ihrer eigenen Vergesslichkeit zu bewahren. Nie wieder wirst du dich aus deiner Wohnung aussperren und deinen teuren Schlüsseldienst rufen müssen. Denn nun reicht ein einfaches Klopfmuster um die Tür zu öffnen als wäre noch jemand in der Wohnung.

Supplies

Für die Konstruktion sind 4 Dinge besonders Wichtig:

  1. Mikrofon Sensor (mit analogem Signal)
  2. Getriebemotor
  3. Pololu DRV8876 Driver Carrier
  4. Arduino

Wir werden aber auch noch andere kleine Teile brauchen:

  1. Widerstände
  2. LED (am besten Rot und Grün)
  3. Buzzer
  4. Knopf

Als erstes haben wir das Mikrofon mit dem man das klopfen aufnehmen kann. Hier haben wir uns für einen simplen Mikrofon Sensor entschieden, da wir keine besonderen Töne aufzeichnen wollen sondern die Schwingung der Tür.

Das nächste Teil ist der Motor, der den Schlüssel drehen wird. Hierbei ist es wichtig einen Motor zu nehmen der stark genug ist um einen Schlüssel zu drehen, dafür muss der Motor eine Kraft um die 1.2Nm haben. Wir haben uns für den 12V 6mm Schneckengetriebemotor von Eckstein geeinigt. Mit seinen 1.4Nm und 100 RPM ist er sowohl stark als auch schnell genug um das Schloss zu öffnen.

Leider ist der Motor alleine nicht steuerbar, weshalb wir uns noch den Pololu DRV8876 Driver Carrier besorgt haben. Hiermit sind wir in der Lage die Stromstärke zu messen, die der Motor gerade zieht und können ihn damit kontrollieren.

Als letztes kommt noch das Herzstück des ganzen. Der Arduino. Auch wenn wir uns hier für eine Knock-off variante entschieden haben kann man diese wenn gewünscht auch mit einem Arduino Uno ersetzen.

Klopfer Erkennen

Der erste Schritt ist die Erkennung eines Klopfens. Hierfür verbindet man die Pins des Mikrofons mit den 5V, GND und A0 Pin des Arduinos.

Als nächstes haben wir Code geschrieben mit dem wir zuerst die eingehende Spannung Filtern, indem wir ein Threshold setzen. Immer wenn dieser Threshold übertreten wird, wissen wir also das ein Klopfer erkannt wurde. Hierbei ist anzumerken, dass auf dem Mikrofon selber eine kleine schraube ist mit der man die Empfindlichkeit einstellen kann. Wir haben die Schraube so gedreht, dass das Mikrofon eine Baseline von ca. 1.7V Output hatte.

Damit wir nicht ewig auf den nächsten Klopfer warten, der vielleicht nie kommt haben wir noch einen Abbruch nach 5 Sekunden eingebaut

long detectKnock(){
  long start = millis();
  while((analogRead(inputPinMic) * (5.0 / 1023.0)) <= thresh){
    if(millis() - start >= 5000){
      return -1;
    }
  }
  return millis();
}


Ein Muster Einlesen

Um das Schloss später mit einem Klopfmuster zu öffnen, müssen wir natürlich erst einmal eins einspeichern.

Der Arduino befindet sich in einem Idle-State bis ein erster Klopfer erkannt wurde. Nun zählt er die Millisekunden bis zum nächsten Klopfer und speichert den Abstand in ein Array.

Hiermit gibt es zwei Probleme:

  1. Wenn der Strom ausfällt und wir den Arduino nicht per Batterie betreiben sind wir ausgeschlossen, da das Array gelöscht ist
  2. Wir wissen nicht ob der Arduino nun wirklich unser Muster eingespeichert hat oder nur Teile davon

Die Lösungen zu diesen Problemen lassen sich zum Glück leicht lösen:

  1. Wir speichern das Muster nicht in einem Array sondern im EEPROM des Arduino
  2. Ausgabe des Musters über eine LED oder Buzzer


Jetzt sollten wir alles haben um den Algorithmus zu schreiben:

Zuerst speichern wir die momentane Zeit sobald wir den ersten Klopfer erkennen. Als nächstes warten wir auf den nächsten Klopfer, sobald wir diesen erkennen berechnen wir die Differenz zwischen den beiden Klopfern und schreiben diese Differenz in den EEPROM. Zu beachten ist hier, dass wir nur Byteweise in den EEPROM schreiben können weshalb wir die Integer-Variable erst zerlegen müssen. Zum Schluss schreiben wir noch zwei mal 255 in den EEPROM um das ende des Musters zu signalisieren.

  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);

    lastStep = currentTime;
  }

  EEPROM.write(i++, 255);
  EEPROM.write(i, 255);
  Serial.println("Finished Pattern now");

Um nun noch das eingespeicherte Muster wieder abzuspielen müssen wir einfach immer wieder zwei Bytes aus dem EEPROM lesen und zu einem delay zusammensetzen mit dem wir dann eine schleife unterbrechen die den Buzzer/LED einschaltet.

  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);
}

Klopfmuster Erkennen

Um das Klopfmuster zu erkennen müssen wir nur nochmal das gleiche tun wie beim Ausgeben des Musters bei der Eingabe. Mit dem Unterschied, das wir dies nun als separate Funktion haben die abbricht, sobald eine Abweichung vom Muster erkannt wird. Wichtig ist hier allerdings zu beachten, dass kein Mensch auf die Millisekunde genau Klopfen kann, weshalb wir hier noch eine Toleranz von 70ms in beide Richtungen eingebaut haben.

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);
  }
}

Alles Zusammen Bündeln

Zum Schluss muss noch alles zusammen gebündelt werden. Das können wir einfach in der loop() machen. Wir checken hier einfach ob ein Knopf gedrückt wurde und aktivieren dann die Aufnahme, sollte das nicht der fall sein gucken wir noch ob geklopft wurde und starten dann den Abgleich mit dem Muster aus dem EEPROM. Sollte der Abgleich erfolgreich sein senden wir ein Signal an das Driver board um den Motor zu starten und das Schloss zu öffnen. Sollte der Abgleich fehlschlagen kann man ein Signal über den Buzzer/LED ausgeben

void loop() {
  float x;

  if(digitalRead(buttonPinIn) == HIGH){
    Serial.println("Recording Pattern now");
    writePattern();
    Serial.println("Finished recording Pattern now");

    //wenn erster knock erfasst wird -> nächsten knock erwarten (matchPattern()) 1.75
  }else if(!((x = (analogRead(inputPinMic) * (5.0 / 1023.0))) <= thresh)){
    if(matchPattern() == 1){
      Serial.println("Opening lock");
      openLock();
      analogWrite(greenLedPin, 60);
    }else{
      analogWrite(redLedPin, 60);
      Serial.println("Wrong pattern");
    }
    delay(5000);
    analogWrite(greenLedPin, 0);
    analogWrite(redLedPin, 0);

    Serial.println("Listening again");
  }
}