[PROJEKT] Sejf otwierany odciskiem palca oparty o Arduino
Podłączenie czujnika do Arduino
Przed podłączeniem czujnika należy się upewnić, że prędkość transmisji ustawiono na 9600.
Czujnik linii papilarnych SEN0348 | Arduino Pro Mini |
GND (przewód czerwony) | GND |
RX (przewód czarny) | 3 |
TX (przewód żółty) | 2 |
VIN (przewód zielony) | VCC |
IRQ (przewód niebieski) | Nie podłączone |
3.3V (przewód biały) | VCC |
Podłączenie programatora do Arduino Pro Mini:
Arduino Pro Mini | Konwerter USB–UART ZL5USB |
RX | TX |
TX | RX |
DTR (Reset) | DTR |
VCC | +3V |
GND | GND |
Rys. 14. Skaner linii papilarnych i konwerter USB-UART podłączone do Arduino Pro Mini
Instalowanie biblioteki DFRobot_ID809.h
W artykule [KROK-PO-KROKU] Arudino – jak zaimportować biblioteki? szczegółowo opisaliśmy proces importowania nowych bibliotek do środowiska Arduino. Jeśli nie opanowałeś jeszcze tego procesu, skorzystaj z tego poradnika. Biblioteka DFRobot_ID809.h, którą wykorzystamy do obsługi czytnika jest dostępna w sekcji Do pobrania.
Inicjalizacja czujnika linii papilarnych
Nadszedł czas na napisanie programu obsługującego czujnik linii papilarnych. Najpierw trzeba dołączyć do programu biblioteki SoftwareSerial.h i DFRobot_ID809.h
#include <SoftwareSerial.h> #include <DFRobot_ID809.h>
Następnie należy do stałej FPSerial przypisać wirtualny port Serial1. Dzięki przypisaniu w instrukcji #define można łatwo podmienić go później na fizyczny interfejs UART Kolejna instrukcja przypisuje do stałej LED numer portu, do którego podłączona jest dioda.
#define FPSerial Serial1 #define LED 13
Teraz trzeba stworzyć obiekt Serial1 typu SoftwareSerial. Jako argumenty podamy numery portów, które pełnią rolę wyprowadzeń odpowiednio RX i TX. Następnie należy stworzyć obiekt czujnika linii papilarnych.
SoftwareSerial Serial1(2, 3); DFRobot_ID809 fingerprint;
W funkcji setup() trzeba ustawić port LED jako port wyjściowy, a następnie stan portu jako niski. Dioda podłączona do tego portu będzie się świecić w przypadku błędu komunikacji z czujnikiem.
pinMode(LED, OUTPUT); digitalWrite(LED, LOW);
Następnie należy zainicjalizować interfejs FPSerial z prędkością 9600 baud oraz obiekt fingerprint z argumentem FPSerial.
FPSerial.begin(9600); fingerprint.begin(FPSerial);
Po zainicjalizowaniu program będzie sprawdzał czy wszystko przebiegło pomyślnie, a w przypadku błędu zapali diodę.
if(fingerprint.isConnected() == false) digitalWrite(LED, HIGH);
Funkcja setup() powinna więc w tym momencie wyglądać następująco
void setup() { pinMode(LED, OUTPUT); digitalWrite(LED, LOW); FPSerial.begin(9600); fingerprint.begin(FPSerial); if(fingerprint.isConnected() == false) digitalWrite(LED, HIGH); }
W funkcji loop() należy dodać funkcję ctrlLED, która pozwala sterować diodami wbudowanymi w czytnik. Funkcja przyjmuje trzy parametry.
Parametr pierwszy – tryb pracy LED wybieramy z dostępnych:
- eBreathing,
- eFastBlink,
- eKeepsOn,
- eNormalClose,
- eFadeIn,
- eFadeOut,
- eSlowBlink.
Parametr drugi – kolor diody LED. Dostępne wartości:
- eLEDGreen,
- eLEDRed,
- eLEDYellow,
- eLEDBlue,
- eLEDCyan,
- eLEDMagenta,
- eLEDWhite.
Parametr trzeci to liczba mignięć diodą. Podanie wartości 0 spowoduje ciągłe miganie.
Przykładowo ustawię tryb „oddychania”, kolor niebieski, a także miganie ciągłe.
fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0);
Pełen kod do inicjalizacji czujnika
Cały kod powinien więc wyglądać następująco
#include <SoftwareSerial.h> #include <DFRobot_ID809.h> #define FPSerial Serial1 #define LED 13 SoftwareSerial Serial1(2, 3); DFRobot_ID809 fingerprint; void setup() { pinMode(LED, OUTPUT); digitalWrite(LED, LOW); FPSerial.begin(9600); fingerprint.begin(FPSerial); if(fingerprint.isConnected() == false) digitalWrite(LED, HIGH); } void loop() { fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0); }
Natomiast efekt działania programu powinien wyglądać tak:
Rys. 15. Skaner linii papilarnych po inicjalizacji
Dodawanie wzorców
Kolejnym krokiem będzie dodanie wzorców odcisków palców. Najpierw należy zdefiniować wartość COLLECT_NUMBER jako 3. Jest to liczba mówiąca ile razy trzeba zeskanować odcisk, aby dodać wzorzec. Wartość można zmienić na inną liczbę całkowitą z zakresu od 1 do 10.
#define COLLECT_NUMBER 3
Następnie trzeba dodać funkcję enroll(), która ma za zadanie tworzyć nowe wzorce. W funkcji najpierw należy dodać zmienną i oraz przypisać jej wartość 0.
int i = 0;
Potrzebna będzie również zmienna ID, której należy przypisać numer pierwszego pustego wzorca. W tym celu można skorzystać z funkcji getEmptyID().
int ID = fingerprint.getEmptyID();
Następnie należy sprawdzić czy funkcja getEmptyID() nie zwróciła błędu. W przypadku wykrycia błędu należy zapalić diodę i zatrzymać wykonywanie programu.
if (ID == ERR_ID809) { digitalWrite(LED, HIGH); while (1); }
W pętli while o warunku i < COLLECT_NUMBER należy umieścić funkcję ctrlLED z argumentami, które spowodują szybkie miganie diod w kolorze magenta. W warunku if należy pobrać odcisk palca, a także sprawdzić czy wynik funkcji nie jest równy kodowi błędu. Posłuży do tego funkcja collectionFingerprint przyjmująca jako argument czas, po którym pomiar ma być przerwany. Jeżeli udało się pomyślnie pobrać odcisk palca, ustawimy diody w tryb powolnego migania kolorem żółtym, a także zwiększymy wartość i o 1. Następnie (nadal w pętli while) należy dodać jeszcze jedną pętlę while, która będzie sprawdzać czy palec nadal jest przyłożony do czujnika i czekać, dopóki nie zostanie on zdjęty. Zastosowanie pętli typu while zamiast for ma na celu zapewnienie, że zostaną poprawnie zeskanowane trzy odciski. W przypadku pętli for funkcja collectionFingerprint zostałaby wykonana zawsze trzy razy, niezależnie od tego czy wykonała się poprawnie, czy też zwróciła kod błędu.
while (i < COLLECT_NUMBER) { fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDMagenta, 0); if ((fingerprint.collectionFingerprint(10)) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eSlowBlink, fingerprint.eLEDYellow, 0); i++; } while (fingerprint.detectFinger()); }
Po zeskanowaniu trzech odcisków należy utworzyć wzorzec za pomocą funkcji storeFingerprint(), która jako argument przyjmuje numer pustego wzorca. Warto od razu sprawdzić, czy operacja przebiegła pomyślnie i jeżeli tak, to zasygnalizować to za pomocą na przykład zapalenia diod na zielono.
if (fingerprint.storeFingerprint(ID) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); delay(1000); fingerprint.ctrlLED(fingerprint.eNormalClose, fingerprint.eLEDBlue, 0); delay(1000); }
Pełen kod funkcji enroll
Cała funkcja enroll powinna więc wyglądać następująco
void enroll() { int i = 0; int ID = fingerprint.getEmptyID(); if (ID == ERR_ID809) { digitalWrite(LED, HIGH); while (1); } while (i < COLLECT_NUMBER) { fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDMagenta, 0); if ((fingerprint.collectionFingerprint(10)) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eSlowBlink, fingerprint.eLEDYellow, 0); i++; } while (fingerprint.detectFinger()); } if (fingerprint.storeFingerprint(ID) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); delay(1000); fingerprint.ctrlLED(fingerprint.eNormalClose, fingerprint.eLEDBlue, 0); delay(1000); } }
Funkcję enroll należy wykonać w pętli loop.
void loop() { fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0); enroll(); }
Teraz trzeba wgrać program i dodać wzorzec przynajmniej jednego palca.
Rys. 16. Dodawanie wzorców do bazy
Identyfikacja
Kolejnym krokiem jest dodanie do programu identyfikacji odcisku palca – sprawdzenia czy aktualnie odczytany odcisk znajduje się w bazie. Poprawne dopasowanie zeskanowanego odcisku do zapamiętanego wzorca sygnalizowane jest zapaleniem diody na zielono, natomiast brak dopasowania – na czerwono.
Pierwszym krokiem jest rezygnacja z wywołania funkcji enroll() w pętli loop, a także inicjalizacja zmiennej ret, która będzie przechowywać wynik identyfikacji.
//enroll(); int ret;
W kolejnej linii pętli loop powinna być dodana wcześniej funkcja ctrlLED ustawiająca miganie diod na niebiesko.
fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0);
Następnie należy dodać warunek if który zeskanuje odciski i sprawdzi, czy skanowanie przebiegło pomyślnie.
if ((fingerprint.collectionFingerprint(0)) != ERR_ID809)
Jeżeli udało się pobrać odcisk, należy zasygnalizować to zmieniając kolor diod na żółty i zaczekać aż palec zostanie zdjęty z czujnika. Można tego dokonać za pomocą pętli while z warunkiem detectFinger().
fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDYellow, 3); while (fingerprint.detectFinger());
Do zmiennej ret należy przypisać wynik funkcji search dopasowującej zeskanowany odcisk do zapamiętanych wzorców. Następnie za pomocą warunku if należy sprawdzić czy wartość zmiennej jest niezerowa. Jeżeli wartość zmiennej nie jest równa zeru, to oznacza, że udało się odnaleźć pasujący wzorzec. Można to zasygnalizować zapalając diodę na zielono. Natomiast jeżeli wartość jest równa zeru, to nie udało się znaleźć wzorca. Można to zasygnalizować zapalając LED na czerwono.
ret = fingerprint.search(); if (ret != 0) { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); } else { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDRed, 0); }
Na koniec w pętli loop należy dodać opóźnienie 1000 ms. W naszym przypadku można skorzystać z funkcji delay(), gdyż nie wpłynie to negatywnie na działanie programu. Jednak jeżeli w programie znalazłaby się obsługa innych czujników, warto zastąpić delay() licznikiem programowym, który będzie działał w trybie nieblokującym.
delay(1000);
Cała funkcja loop powinna wyglądać następująco:
void loop() { int ret; fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0); if ((fingerprint.collectionFingerprint(0)) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDYellow, 3); while (fingerprint.detectFinger()); ret = fingerprint.search(); if (ret != 0) { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); } else { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDRed, 0); } } delay(1000); }
Efekt działania programu powinien natomiast wyglądać tak:
Rys. 17. Identyfikacja odcisków palców
Dodawanie odcisków po identyfikacji
Możliwość dodawania nowych wzorców bez konieczności przeprogramowywania urządzenia umożliwi łatwe i wygodne zarządzanie dostępem do sejfu. Aby zabezpieczyć skarbonkę przed niepożądanym dodaniem nowych wzorców, należy funkcję enroll() wywołać dopiero po zeskanowaniu zapisanego odcisku. Aby rozróżnić samo otwieranie sejfu oraz dodawanie nowych odcisków, można skorzystać z dodatkowego przycisku, który wciśnięty podczas skanowania po poprawnej weryfikacji uruchomi funkcję dodawania do bazy nowych odcisków palców.
Najpierw należy podłączyć przycisk do Arduino zgodnie z poniższą tabelką.
Przycisk | Arduino |
Styk A | GND |
Styk B | 12 |
Rys. 18. Zestaw z dołączonym przyciskiem typu microswitch
Następnie należy przypisać do stałej Button numer portu, do którego podłączony jest przycisk.
#define Button 12
W funkcji setup należy ustawić port Button jako wejściowy z podciągnięciem do zasilania (pull-up), co pozwoli wyeliminować stany nieustalone.
pinMode(Button, INPUT_PULLUP);
W pętli loop w warunku if (ret != 0) należy dodać warunek sprawdzający czy przycisk jest wciśnięty. Jeśli tak, to należy wywołać funkcję enroll; jeżeli nie to jedynie zapalić diodę na zielono.
if (ret != 0) { if(digitalRead(Button)==0) enroll(); else fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); }
W tym przypadku program sprawdza czy w momencie zdjęcia palca z czujnika przycisk jest wciśnięty, dzięki czemu nie ma potrzeby niwelacji drgań styków przycisku.
Cały program powinien w tym momencie wyglądać następująco
#include <Servo.h> #include <DFRobot_ID809.h> #define FPSerial Serial1 #define LED 13 #define Button 12 #define COLLECT_NUMBER 3 SoftwareSerial Serial1(2, 3); DFRobot_ID809 fingerprint; void enroll() { int i = 0; int ID = fingerprint.getEmptyID(); if (ID == ERR_ID809) { digitalWrite(LED, HIGH); while (1); } while (i < COLLECT_NUMBER) { fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDMagenta, 0); if ((fingerprint.collectionFingerprint(10)) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eSlowBlink, fingerprint.eLEDYellow, 0); i++; } while (fingerprint.detectFinger()); } if (fingerprint.storeFingerprint(ID) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); delay(1000); fingerprint.ctrlLED(fingerprint.eNormalClose, fingerprint.eLEDBlue, 0); delay(1000); } } void setup() { pinMode(LED, OUTPUT); pinMode(Button, INPUT_PULLUP); digitalWrite(LED, LOW); FPSerial.begin(9600); fingerprint.begin(FPSerial); if (fingerprint.isConnected() == false) digitalWrite(LED, HIGH); } void loop() { int ret; fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDBlue, 0); if ((fingerprint.collectionFingerprint(0)) != ERR_ID809) { fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDYellow, 3); while (fingerprint.detectFinger()); ret = fingerprint.search(); if (ret != 0) { if(digitalRead(Button)==0) enroll(); else fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDGreen, 0); } else { fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDRed, 0); } } delay(1000); }
Po wgraniu program powinien działać w następujący sposób:
Rys. 19. Dodawanie wzorców do bazy