Самодельный биометрический замок с отпечатком пальца на входную гаражную дверь

31.07.2018

Так как у меня нет машины, то мне не нужно везде носить с собой ключи. Из-за этого оказывалось, что я несколько раз оказывался без ключей вне дома и мне приходилось ждать, пока кто-либо из родственников вернётся домой и впустит меня, и в какой-то момент я решил, что нужно что-то с этим сделать и сконструировал самодельный гаражный замок.

В этом проекте я расскажу, как сделать замок с отпечатком пальца на входную дверь.

Шаг 1: Материалы

Вот список необходимых материалов и инструментов.

Электроника:

*Сканер отпечатков пальцев (и коннектор JST)
*Набор LCD (c ATmega328)
*ATtiny85
*NPN-транзистор
*Динамик-пищалка
*Провод для спикера
*Кейс (в шаге 9 будут файлы для 3Д-печати)
*Медная плёнка
*Регулятор напряжения 5V
*Батарейка 9V
*Коннектор для батарейки 9V
*SPDT-выключатель

Для удобства я приложу готовый вишлист на сайте Sparkfun.

Инструмент:

*Паяльник и припой
*Изолента
*Провода и джамперы
*Кусачки / стриппер
*Плата прототипирования
*Разные резисторы
*Винты
*Дрель
*Несколько светодиодов для тестирования
*Плата FTDI 5V
*Пистолет с горячим клеем
*Доступ к 3Д-принтеру
*Опционально: сокет для интегральных схем (8-пиновый для ATtiny и 28-пиновый для ATmega)
*Опционально: еще одна плата Ардуино / конденсатор 10uF (подробности в шаге 5)

Шаг 2: Схема устройства

Приобретённый в Sparkfun LCD-набор шёл с ATmega328, управляющей дисплеем. ATmega328 достаточно мощна и может быть использована не только для управления дисплеем, но и для других задач. Ввиду этого мы можем использовать её вместо Ардуино для коммуникации со сканером отпечатков пальцев и отправки команд на ATtiny85, управления дисплеем и пищалкой.

Чтобы биометрический дверной замок не работал всё время, я встроил в него выключатель, срабатывающий в тот момент, когда кейс закрывается. Если кейс закрыт - питание на девайс не подается, и мы экономим ресурсы батарейки.

Важная заметка: Сканнер отпечатков пальцев работает при напряжении 3.3V, так что я рекомендую использовать разделитель напряжения, который будет преобразовывать сигналы от ATmega к 3.2V. Разделитель напряжения состоит из резистора на 560 Ом между D10 / вторым пином сканера и резистором на 1 КОм между GND / вторым пином сканера.

Распиновка LCD:

*D10 - пин 1 сканера (черный провод)
*D11 - пин 2 сканера (через разделитель напряжения)
*D12 - ATtiny85
*D13 - Пищалка

Распиновка ATtiny85:

*Пин 5 (0 в коде программы) - вход с ATmega
*Пин 3 (4 в коде программы) - транзистор / желтый светодиод
*Пин 7 (2 в коде программы) - светодиод индикации

Заметка: к пину 5 на ATtiny рекомендуется подключить подтягивающий резистор

Шаг 3: Собираем компоненты из LCD-набора

Шаг 4: Собираем схему на плате прототипирования

Размещение компонентов на плате остается за вами, просто старайтесь припаивать провода так, чтобы они смотрели в одну сторону и не заламывались.

После сборки я покрыл верх и низ платы горячим клеем - это закрепило и изолировало элементы схемы. Горячий клей не повредит микросхему.

Как и с основной платой, припаяйте все к плате ATtiny и нанесите горячий клей для закрепления и изоляции компонентов. Регулятор напряжения может очень сильно греться, поэтому будет хорошей идеей не наносить горячий клей на него и поверхности, располагающиеся рядом с ним. Также лучше не покрывать горячим клеем плату ATtiny, ведь вы можете захотеть снять и перепрограммировать её.

Шаг 5: Программирование ATmega328

Как уже говорилось в шаге 2, у ATmega328 достаточно сильный процессор и достаточно пинов для управления LCD, в то время как он управляет другими дополнительными компонентами. Чтобы добиться этого, нужно запрограммировать чип.

Если у вас есть Arduino Uno или Duemilanove, вы можете просто снять с них чип и заменить его тем, который шел в наборе. Либо вы можете найти плату FTDI Basic Breakout (5V) и припаять насадки к её стороне (смотрите картинки в шаге 3)

Также вам нужно будет залить код в режиме "Duemilanove w/ ATmega328".

Код внизу - рабочая программа для проверки работоспособности девайса.

#include "LiquidCrystal.h"
LiquidCrystal lcd(2,3,4,5,6,7,8);
void setup() {
pinMode(9, OUTPUT); //подсветка
pinMode(13, OUTPUT); //пищалка
lcd.begin(16, 2); //16 знаков в ширину, 2 в высоту
digitalWrite(9, HIGH); //включаем подсветку
lcd.print(" Hello world! "); //центрируйте текст при помощи пробелов
delay(2000);
}
void loop() {
//пищалка включается и выключается, её состояние отображается на дисплее
lcd.clear();
lcd.print(" Buzzer is on ");
tone(13, 262, 1000);
delay(1000);
lcd.clear();
lcd.print(" Buzzer is off ");
delay(1000);
}

Шаг 6: Настраиваем сканер отпечатков пальцев

Для коммуникации со сканером я использовал эту библиотеку. Прямая ссылка на скачивание здесь.

Для проверки работоспособности кода загрузите эту программу проверки "миганием".

У сканера отпечатков есть своя встроенная память для хранения данных. Так что после того, как вы убедитесь, что сканер работает, загрузите эту программу, чтобы добавить ваш отпечаток в базу данных под id #0. Откройте последовательную консоль и просто следуйте инструкциям.

Программа мигания светодиода для проверки сканера

/*

Этот простой код включит и выключит светодиод.

Он используется для того, чтобы понять, работает ли коммуникация.

*/
#include "FPS_GT511C3.h"
#include "SoftwareSerial.h"
//Настройка железа - сканер пальцев соединён с:
//цифровым пином 10(arduino rx, fps tx)
//цифроывм пином 11(arduino tx - резистор 560ohm fps tx - резистор 1000ohm - GND)
//это понижает 5v tx примерно до 3.2v и мы не сожжем наш сканер
FPS_GT511C3 fps(10, 11);
void setup(){
Serial.begin(9600);
fps.UseSerialDebug = true; // вы сможете увидеть сообщения на последовательном дебаг-экране
fps.Open();
}
void loop(){
// тест мигания светодиодов для сканера
fps.SetLED(true); // включает LED внутри сканера
delay(1000);
fps.SetLED(false);// выключает LED внутри сканера
delay(1000);
}

Программа регистрации данных в сканер

#include "FPS_GT511C3.h"
#include "SoftwareSerial.h"
//Настройка железа - сканер пальцев соединён с:
//цифровым пином 10(arduino rx, fps tx)
//цифроывм пином 11(arduino tx - резистор 560ohm fps tx - резистор 1000ohm - GND)
//это понижает 5v tx примерно до 3.2v и мы не сожжем наш сканер
FPS_GT511C3 fps(10, 11);
void setup(){
Serial.begin(9600);
delay(100);
fps.Open();
fps.SetLED(true);
Enroll();
}
void Enroll(){
// Тест регистрации
// поиск открытого id
int enrollid = 0;
fps.EnrollStart(enrollid);
// регистрация
Serial.print("Press finger to Enroll #");
Serial.println(enrollid);
while(fps.IsPressFinger() == false) delay(100);
bool bret = fps.CaptureFinger(true);
int iret = 0;
if (bret != false)
{
Serial.println("Remove finger");
fps.Enroll1();
while(fps.IsPressFinger() == true) delay(100);
Serial.println("Press same finger again");
while(fps.IsPressFinger() == false) delay(100);
bret = fps.CaptureFinger(true);
if (bret != false)
{
Serial.println("Remove finger");
fps.Enroll2();
while(fps.IsPressFinger() == true) delay(100);
Serial.println("Press same finger yet again");
while(fps.IsPressFinger() == false) delay(100);
bret = fps.CaptureFinger(true);
if (bret != false)
{
Serial.println("Remove finger");
iret = fps.Enroll3();
if (iret == 0)
{
Serial.println("Enrolling Successfull");
}
else
{
Serial.print("Enrolling Failed with error code:");
Serial.println(iret);
}
}
else Serial.println("Failed to capture third finger");
}
else Serial.println("Failed to capture second finger");
}
else Serial.println("Failed to capture first finger");
}
void loop(){
delay(100000);
}

Шаг 7: Программируем ATtiny85

АTtiny85 - это что-то типа дешевого Ардуино, собранного в одном чипе. ATtiny85 может быть запрограммирована другим Ардуино, включая ATmega328, который есть в нашем наборе LCD. В проекте он используется для запуска очень простых команд: проверить сигнал с ATmega и открыть ворота, если сигнал правильный.

Чтобы запрограммировать его, подключите всё согласно приложенным фотографиям. Затем скачайте необходимые файлы и следуйте этой инструкции.

После загрузки кода, пин 13 на Ардуино (встроенный светодиод) должен загореться, оповещая, что код загружен.

Итоговый код:

//Получает краткий сигнал от основного модуля для закрытия реле
void setup(){
pinMode(2,OUTPUT); //LEd индикации через резистор на 10K
pinMode(4,OUTPUT); //пин странзистора, открывающий гараж
pinMode(0,INPUT); //ввод
delay(500); //даём девайсу время для старта
digitalWrite(2, HIGH); //LED индикации
}
void loop(){
if(digitalRead(0)){ //простой паттерн для переключения транзистора
delay(125);
if(digitalRead(0)==false){
delay(55); //ждём, так как таймер ATtiny не идеален
if(digitalRead(0)){
delay(55);
if(digitalRead(0)==false){
delay(55);
if(digitalRead(0)){
delay(55);
if(digitalRead(0)==false){
digitalWrite(4, HIGH); //транзистор "нажимает" кнопку
delay(1000);
digitalWrite(4,LOW);
digitalWrite(2,LOW);
delay(1000);
digitalWrite(2, HIGH);
}
}
}
}
}
}
}

Шаг 8: Итоговый код

Ниже приложена программа для Ардуино, которую я написал с использованием библиотек сканера и дисплея. Чтобы было понятно, что происходит в каждой части программы, я постарался закомментировать всё наилучшим образом. После загрузки этого кода всё должно заработать и всё что останется сделать - интегрировать систему в дверь.

Предупреждение: если библиотека сканера не работает, то попробуйте использовать старую версию IDE Ардуино.

Код для ATmega238:

#include "LiquidCrystal.h" //библиотека дисплея
#include "FPS_GT511C3.h" //библиотека fps (сканера отпечатков)
#include "SoftwareSerial.h" //используется библиотекой сканера
//Настраиваем пины дисплея и сканера
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8); //распиновка дисплея
FPS_GT511C3 fps(10, 11); //RX, TX
boolean isFinger = false; //true если библиотека fps засечет палец на сканере
//выходные пины
const int buzzerPin = 13;
const int backlightPin = 9;
const int attinyPin = 12;
const String idNames[] =
{
"self","Bro", "Ryan", "Mom", "Dad", "Auntie", "Grandma", "Zeide", "Person", "person", "Thumb"};
void setup(){
//настраиваем выходы
pinMode(buzzerPin, OUTPUT);
pinMode(backlightPin, OUTPUT);
pinMode(attinyPin, OUTPUT);
//для отладки
//Serial.begin(9600);
fps.UseSerialDebug = false; //становится true для отладки fps через последовательный порт
//инициализация библиотек
lcd.begin(16,2);
digitalWrite(backlightPin, HIGH); //подсветка LCD
fps.Open();
fps.SetLED(true); //светодиод на fps
//звук загрузки
for(int i=0; i<30; i++){
tone(buzzerPin, 50+10*i, 30);
delay(30);
}
tone(buzzerPin, 350);
//вывод стартового сообщения
lcd.print("Put your finger "); //команда вывода на экран
lcd.setCursor(0, 1); //устанавливаем курсор на нулевую колонку первой строки
lcd.print(" on the scanner ");
delay(150);
noTone(buzzerPin); //останавливаем стартовый звук
}
void loop(){
//сканируем и распознаём отпечаток, когда приложен палец
waitForFinger();
lcd.clear(); //очищаем экран и устанавливаем курсов в положение 0,0
fps.CaptureFinger(false); //захватываем отпечаток для идентификации
int id = fps.Identify1_N(); //идентифицируем отпечаток и сохраняем id
if(id <= 10){
lcd.print(" Access granted "); //сообщение об успехе
lcd.setCursor(0,1);
//выводим на экран имя когда дверь открывается
String message = " Hey " + idNames[id] + "!";
lcd.print(message);
tone(buzzerPin, 262, 1000);
delay(1500);
//отправляем сигнал для открытия двери
digitalWrite(attinyPin, HIGH); //первый импульс синхронизирует задержку (10ms)
delay(5);
digitalWrite(attinyPin, LOW);
delay(3);
digitalWrite(attinyPin, HIGH); //следующие два - открывают дверь
delay(15);
digitalWrite(attinyPin, LOW);
delay(5);
digitalWrite(attinyPin, HIGH);
delay(10);
digitalWrite(attinyPin, LOW);
delay(1000);
lcd.clear();
lcd.print("Don't forget to ");
lcd.setCursor(0,1);
lcd.print(" shut me off! ");
delay(2000);
waitForFinger(); //нажмите чтобы продолжить запись
while(true){ //сохраняет новый отпечаток
//выводит сообщение на экран
lcd.clear();
lcd.print(centerText("So you want to"));
lcd.setCursor(0,1);
lcd.print(centerText("scan a new one?"));
delay(2000);
//Скопировано и слегка модифицировано из примера регистрации данных:
int enrollid = 11;
//выбираете какой id переписать\создать
//отпустите палец, когда хотите записать id/имя, напечатанное на экране
waitForFinger(); //ждёт, когда будет нажат fps
while(enrollid==11){
for (int i = 1; i1){
lcd.print(i);
enrollid = i-1;
break;
}
}
}
//предупреждение, если в данном слоте уже есть данные
if(fps.CheckEnrolled(enrollid)){
lcd.clear();
lcd.print(" Warning! ID #");
lcd.print(enrollid);
lcd.setCursor(0,1);
lcd.print(" has data. OK? ");
delay(2500);
waitForFinger(); //ждёт, когда будет нажат fps
fps.DeleteID(enrollid); //удаляет данные
delay(100);
}
//Enroll
fps.EnrollStart(enrollid);
lcd.clear();
lcd.print("Place finger to ");
lcd.setCursor(0,1);
lcd.print("enroll #");
lcd.print(enrollid); //выводит id, который был добавлен
waitForFinger(); //ждёт, когда будет нажат fps
//захватывает отпечаток и сохраняет его в память трижды для точности данных
bool bret = fps.CaptureFinger(true); //картинка высокого качества для записи
int iret = 0; //в случае ошибки
if (bret != false){ //первая регистрация
lcd.clear();
lcd.print(" Remove finger ");
fps.Enroll1();
while(fps.IsPressFinger() == true) delay(100); //ждёт пока уберут палец
lcd.clear();
lcd.print(" Press again ");
waitForFinger(); //ждёт, когда будет нажат fps
bret = fps.CaptureFinger(true);
if (bret != false){ //вторая регистрация
lcd.clear();
lcd.print(" Remove finger ");
fps.Enroll2();
while(fps.IsPressFinger() == true) delay(100);
lcd.clear();
lcd.print("Press yet again ");
waitForFinger();
bret = fps.CaptureFinger(true);
if (bret != false){ //третья регистрация
iret = fps.Enroll3();
if (iret == 0){ //проверяет, были ли какие-нибудь ошибки
lcd.clear();
lcd.print(" Success! ");
delay(2000);
beep(); //выключает Ардуино
}
else{ //запускает этот код в случае любой ошибки
lcd.clear();
lcd.print("Fail. Try again ");
delay(1000);
}
}
lcd.clear();
lcd.print(" Failed 3rd "); //ошибка на третьей записи
delay(1000);
}
lcd.clear();
lcd.print(" Failed 2nd "); //ошибка на второй записи
delay(1000);
}
lcd.clear();
lcd.print(" Failed 1st "); //ошибка на первой записи
delay(1000);
}
}
else{
lcd.print("Fingerprint is"); //если отпечаток не распознан
lcd.setCursor(0,1);
lcd.print(" unverified ");
delay(2000);
lcd.clear();
lcd.print("Please try again");
lcd.setCursor(0,1);
lcd.print("Use your pointer"); //pointer - указательный палец (можете использовать любой и заменить это слово)
delay(500);
}
delay(250);
}
void beep(){
//издаёт звуки, чтобы кто-нибудь закрыл кейс
lcd.clear();
lcd.print("Please close the");
lcd.setCursor(0,1);
lcd.print(" case! ");
for(int i=0;i=80 && !fps.IsPressFinger()){
beep();
}
}
timer = 0; //обнуляет таймер как только функция завершится
}
String centerText(String s) { //центрует текст на дисплее, чтобы он лучше смотрелся
while(16-s.length()>1){ //если текст нуждается в центровке
s = " " + s + " "; //равномерно добавляет пробелы с обеих сторон
}
return s;
}

Шаг 9: Напечатанный на 3Д-принтере кейс

Чтобы включить модуль, нужно захлопнуть кейс, запустив выключатель. Как видно на фото выключатель должен подключаться к общему контакту и нормально замкнутому контакту (NC). Приклейте всё к кейсу при помощи горячего клея. Спозиционируйте выключатель с небольшим смещением, чтобы он надавливался более легко.

Шаг 10: Подготовка гаража

Чтобы открывать гараж, я подключил ATtiny85 к кнопке, которая открывала гараж до этого. Вместо физического соединения, ATtiny использует в качестве "кнопки" NPN-транзистор.

Провода нужно измерить и отрезать по нужной длине, оставив немного длины про запас. Затем нужно припаять провода от кнопки к модулю сканера. Затем всё нужно хорошо изолировать.

Чтобы ATtiny внутри гаража получал сигналы от ATmega, находящегося снаружи гаража, я пропустил сквозь стену 3 провода (питание, землю и сигнальный). В гараже была деревянная стойка, через которую я и проделал отверстие.

Наконец, можно привинтить кейс и запустить устройство!

Шаг 11: Тестирование

Этот шаг будет самым весёлым. Используйте встроенную функцию добавления данных, чтобы ваши семья/друзья могли открывать гараж. Затем вы можете создать персональные сообщения для каждого из них! Посмотрите видео для визуального объяснения функционала девайса.

Шаг 12: Делаем устройство портативным

Сканер отпечатков и экран могут быть встроены в коробку или сундук, ведь они работают от батареек. Я временно снял модуль с гаража и совместил его с сервоприводом, чтобы открывать\закрывать свой сундук при помощи пальца.

Заметка: я обнаружил, что 9V батарейки не хватало для одновременной работы девайса и сервопривода, поэтому заменил её на 6 батареек AA. Также хочу заметить, что дизайн моего замка был разработан в ознакомительных целях. Чтобы сделать его более безопасным, я бы рекомендовал использовать более жесткий корпус.

Все изображения в большом разрешении доступны по ссылке