Arduino κλειδαριά με κωδικοποιημένο σύστημα χτύπων
Για να φτιάξουμε μια κλειδαριά με κωδικοποιημένο σύστημα χτύπων είναι αναγκαίο να δούμε τα 2 προηγούμενα άρθρα (Μέρος 1ο, Μέρος 2ο). Στο προηγούμενο άρθρο ορίσαμε τις σταθερές και μεταβλητές που χρησιμοποιούνται από το πρόγραμμα. Ακόμα δημιουργήσαμε και το κυρίως κομμάτι του κώδικα που εκτελείται από το Arduino Board.
Πάμε τώρα να παρακολουθήσουμε την κατασκευή των συναρτήσεων που χρησιμοποιήθηκαν από το κυρίως κομμάτι του κώδικα. Η δουλειά αυτών των συναρτήσεων είναι να ανιχνεύουν τα διάφορα μοτίβα χτυπημάτων που δημιουργεί ο χρήστης. Τα αποθηκεύουν σε μονοδιάστατους πίνακες και τα συγκρίνουν με το μυστικό χτύπημα αναφοράς έτσι ώστε να τεθεί σε λειτουργία το μοτέρ και να ξεκλειδώσει τελικώς η πόρτα.
Arduino κλειδαριά με κωδικοποιημένο σύστημα χτύπων: Η συνάρτηση που βάζει σε λειτουργία το μοτέρ.
H παρακάτω συνάρτηση έχει φτιαχτεί ώστε να τυπώνει στην σειριακή οθόνη ένα μήνυμα κάθε φορά που καλείται. Ακόμα βάζει σε λειτουργία το μοτέρ για μικρό χρονικό διάστημα και αναβοσβήνει τους λαμπτήρες LED για να ειδοποιήσει τον χρήστη πως η πόρτα ξεκλείδωσε.
//Συνάρτηση για να ξεκλειδώνει η πόρτα void triggerDoorUnlock(){ Serial.println("Door unlocked!"); int i=0; // Βάλε σε λειτουργεία το μοτέρ. digitalWrite(motor, HIGH); digitalWrite(greenLed, HIGH); delay (lockTurnTime); //Κόψε το ρεύμα από το μοτέρ. digitalWrite(motor, LOW); // Αναβόσβησε το πράσινο LED για οπτική επικοινωνία με την χρήστη. for (i=0; i < 5; i++){ digitalWrite(greenLed, LOW); delay(100); digitalWrite(greenLed, HIGH); delay(100); } }
Arduino κλειδαριά με κωδικοποιημένο σύστημα χτύπων: Η συνάρτηση που ελέγχει τα μοτίβα χτύπων.
Η παρακάτω συνάρτηση πραγματοποιεί αναγωγή του χρόνου που μεσολαβεί μεταξύ των χτύπων από ένα διάστημα που έχει ως ελάχιστο το 0 και ως μέγιστο την μεγαλύτερη χρονική απόσταση (μεταξύ 2 χτύπων) που προέκυψε στο τρέχον μοτίβο χτυπημάτων σε ένα διάστημα αναφοράς που θέσαμε εμείς και έχει ως ελάχιστο το 0 και ως μέγιστο το 100.
Η παραπάνω διαδικασία συμβαίνει για λόγους κανονικοποίησης των διαστημάτων που μεσολαβούν μεταξύ 2 χτύπων. Ακόμα αυτή η συνάρτηση ελέγχει κάθε διάστημα με βάση το αντίστοιχο του μυστικού κωδικού για να διαπιστώσει αν το τρέχων μοτίβο χτύπων αντιστοιχεί με αυτό του μυστικού κωδικού και επιστρέφει false κάθε φορά που αντιλαμβάνεται πως η παραπάνω συνθήκη δεν είναι αληθής.
//Συνάρτηση για τον έλεγχο //του τρέχοντος χτυπήματος. //Επιστρέφει false κάθε φορά //που το τρέχον μοτίβο χτυπημάτων //δεν αντιστοιχεί στις προϋποθέσεις. boolean validateKnock(){ int i = 0; int currentKnockCount = 0; int secretKnockCount = 0; int maxKnockInterval = 0; for (i = 0; i<maxKnocks; i++){ if(knockReadings[i] > 0){ currentKnockCount++; } if(secretCode[i] > 0){ secretKnockCount++; } if(knockReadings[i] > maxKnockInterval){ maxKnockInterval = knockReadings[i]; } } if (newSecretCode==true){ for (i=0;i<maxKnocks;i++){ //κάνε αναγωγή της τιμής του τρέχοντος χτυπήματος // από το διάστημα 0 μέχρι την μέγιστη καθυστέρηση //μεταξύ 2 χτύπων στο διάστημα 0 μέχρι 100. secretCode[i]= map(knockReadings[i],0, maxKnockInterval, 0, 100); } digitalWrite(greenLed, LOW); digitalWrite(redLed, LOW); delay(1000); digitalWrite(greenLed, HIGH); digitalWrite(redLed, HIGH); delay(50); //Επανέλαβε το παρακάτω για όλα τα χτυπήματα //Αναβόσβησε τα LED κάνοντας την αντίστροφη διαδικασία //από την γραμμή 230΄με σκοπό να δει ο χρήστης αν το μοτίβο του //μυστικού κωδικού που αποθηκεύτηκε αντιστοιχεί σε αυτό // που μόλις χτύπησε. for (i = 0; i < maxKnocks ; i++){ digitalWrite(greenLed, LOW); digitalWrite(redLed, LOW); if (secretCode[i] > 0){ delay( map(secretCode[i],0, 100, 0, maxKnockInterval)); digitalWrite(greenLed, HIGH); digitalWrite(redLed, HIGH); } delay(50); } //Επέστρεψε false. return false; } //Αν το σύνολο των χτύπων του τρέχοντος μοτίβου //δεν είναι ίσο με αυτό του μυστικού κωδικού //τότε επέστρεψε false. if (currentKnockCount != secretKnockCount){ return false; } int totaltimeDifferences=0; int timeDiff=0; //Επανέλαβε για το μέγιστο αριθμό χτυπημάτων. for (i=0;i<maxKnocks;i++){ knockReadings[i]= map(knockReadings[i],0, maxKnockInterval, 0, 100); //Αποθήκευσε στην μεταβλητή timeDiff την απόλυτη τιμή της διαφοράς χρόνου μεταξύ //του τρέχοντος χτυπήματός και του χτυπήματος που αντιστοιχεί στο //στο μυστικό κωδικό. timeDiff = abs(knockReadings[i]-secretCode[i]); //Αν αυτή η διαφορά είναι μεγαλύτερη από την τιμή που θέσαμε //ως μέγιστη επιτρεπτή διαφορά τότε επέστρεψε false. if (timeDiff > rejectValue){ return false; } //Αποθήκευσε στην μεταβλητή totaltimeDifferences το σύνολο //τον τιμών που θα λαμβάνει η μεταβλητή timeDiff για κάθε //φορά που θα επαναλαμβάνεται αυτή η λούπα. totaltimeDifferences += timeDiff; } //Αν το πηλίκο της διαίρεσης της συνολικής διαφοράς χρόνου μεταξύ //του μυστικού κωδικού και του τρέχοντος χτυπήματός είναι μεγαλύτερο //από το ποσοστό που έχουμε θέσει τότε επέστρεψε false. if (totaltimeDifferences/secretKnockCount>averageRegectValue){ return false; } return true; }
Arduino κλειδαριά με κωδικοποιημένο σύστημα χτύπων: Η συνάρτηση που καταχωρεί τα μοτίβα χτύπων.
Η παρακάτω συνάρτηση είναι υπεύθυνη για την καταχώρηση του μυστικού μοτίβου χτύπων αναφοράς καθώς και του τρέχοντος μοτίβου.
void listenToSecretKnock(){ //Τύπωσε στην σειριακή οθόνη. Serial.println("knock starting"); int i = 0; //Άδειασε τον πίνακα που αποθηκεύει //το τρέχον μοτίβο χτυπημάτων. for(i = 0; i < maxKnocks; i++){ knockReadings[i] = 0; } int currentKnockNumber = 0; //Αποθήκευσε την ώρα που ξεκίνησε //το καινούριο μοτίβο χτυπημάτων. int startTime = millis(); int now = millis(); digitalWrite(greenLed, LOW); //Αν έχει πατηθεί το κουμπί //τότε σβήσε το κόκκινο LED. if(newSecretCode==true){ digitalWrite(redLed, LOW); } //Επανέλαβε do{ piezoValue = analogRead(piezo); if(piezoValue >= threshold){ Serial.println("knock."); now=millis(); //Αποθήκευσε του χρόνους μεταξύ των χτυπημάτων //στο πίνακα που κρατάει το τρέχον μοτίβο. knockReadings[currentKnockNumber] = now-startTime; currentKnockNumber ++; startTime=now; digitalWrite(greenLed, LOW); if(newSecretCode==true){ digitalWrite(redLed, LOW); } delay(knockFadeTime); digitalWrite(greenLed, HIGH); if(newSecretCode==true){ digitalWrite(redLed, HIGH); } } now = millis(); }while ((now-startTime < knockComplete) && (currentKnockNumber < maxKnocks)); if (newSecretCode==false){ //Αν το τρέχον μοτίβο χτυπημάτων είναι ίδιο με το //μοτίβο του μυστικού κωδικού τότε ξεκλείδωσε την πόρτα. if (validateKnock() == true){ triggerDoorUnlock(); } //Αλλιώς γράψε στην σειριακή οθόνη και αναβόσβησε το //κόκκινο LED. else { Serial.println("Secret knock failed."); digitalWrite(greenLed, LOW); for (i=0;i<4;i++){ digitalWrite(redLed, HIGH); delay(100); digitalWrite(redLed, LOW); delay(100); } digitalWrite(greenLed, HIGH); } } //Αλλιώς else { //Τσέκαρε τα χτυπήματα validateKnock(); Serial.println("New lock stored."); digitalWrite(redLed, LOW); digitalWrite(greenLed, HIGH); for (i=0;i<3;i++){ delay(100); digitalWrite(redLed, HIGH); digitalWrite(greenLed, LOW); delay(100); digitalWrite(redLed, LOW); digitalWrite(greenLed, HIGH); } } }