[能用就行项目] 指纹门禁

事先声明,本项目具有局限性,并不适用于所有类型的门,但一定适用于东北某 211 学生公寓。

开始

寝室的钥匙对我的室友们来说可能是生活中最没用的东西了,就算经历了无数次被关在门外进不去的事情之后他们依旧能把钥匙放的离自己很远。住在门把手旁边位置的我深受其害,每当我玩的真嗨睡的正香的时候室友“咚咚咚轰隆隆”的敲门总是让我不得不去伸手开门。我也不知道我这一个多学期是怎么过来的,反正室友们看起来已经习惯不带钥匙让我开门了。前段时间我找到了一个逃避的方法,那就是在寝室戴上耳机自嗨(也是受室友启发,有的室友戴上耳机就基本是个聋子了),虽然我一直以来戴耳机都能听见寝室的动静,但是自从我换上新买的 Powerbeats3击音K5 之后,我发现戴上耳机就变聋是如此真实,原来耳机隔音效果可以如此棒!咳咳,回到正题,当我错过了好多次室友敲门之后,他们有了新的办法,贡献出一把寝室钥匙放在门上,人来直接上门楣摸钥匙。虽然这个方案效果还行,稍微减轻了我的负担,但是…室友们能摸钥匙摸着摸着把钥匙从门上扫进屋里——是的,他们就这样又被困在门外了(还有连钥匙都懒得摸依旧轰隆隆敲门的我就不想点评了)。当然叭叭了这么多,并不是和室友关系不好,我还是超级爱我的沙雕室友们的呢!
为了拯救懒癌室友们解放我寄几,我决定,动手做一套门禁。

思路

门禁的原材料我已经有一部分了,主要思路框架是单片机+传感器+舵机/电机。目前流行的可行的门禁主要是 RFID 读卡门禁指纹门禁。考虑到室友们日常不带钥匙不带校园卡(我也不知道不带校园卡的是怎么生活的),想让他们带上特别的卡是基本不可能了,所以就这个思路了:指纹门禁
淘了淘宝百了百度,我手上的 Arduino UNO 好像也能整指纹传感器,所以单片机就选 Arduino 了。(我没有钱,恰不起饭,买不起别的单片机呢)(正式项目请不要学我,要考虑成本选择单片机,而不是会什么就用什么)
指纹传感器不太了解,目前看到了这样几款:FPM10A 光学指纹模块 ,工作电源:DC 3.6-6.0V/电流:<120mA/背光颜色:绿色/接口:UART/波特率:9600/安全等级:五级(高)/错误接受率(FAR):<0.001%(安全级别3)/错误拒绝率(FRR):<1.0%(安全级别3)/能够存储127个不同的指纹。FM-70 光学指纹模块,工作电源:DC 3.8-7V/电流:<65mA/背光颜色:绿色/接口:UART/波特率:57600/安全等级:五级(高)/能够存储1000个不同的指纹。FM-206 光学指纹模块。AS608 光学指纹模块,工作电源:DC 3.3V/电流:<60mA。指纹传感器价格基本在 50-150 元之间,感觉区别不大区别应该主要在于工作电压。Arduino UNO 输出是 3.3V/5V 的,我最后选择了 AS608。
舵机选用 9g 舵机,小巧方便。电机如果需要的话就是市面上常用的 130 电机。
确定材料后就是对项目代码的思路了,我的初步思路就是利用 Arduino 读取传感器信号,匹配指纹库,匹配成功则输出舵机运动,利用一定机械结构变转动为往复平动,实现手动开门一样的动作,利用某种结构实现开门动作。
哔哔了这么多,总结一下,就是用最少的钱最简单的方法做指纹门禁。为什么要搞这么麻烦呢?又不是开发来卖钱,只要能用就行嘛!

采购

2019.5.13 材料正在快递赶来的路上...
2019.5.19 材料已经到手, 淘宝 Telesky 旗舰店购买的 AS608 光学指纹模块

门锁
门锁

需求是将这个红色框框的把儿向后一拉,然后门就开了。。。
如果我们用舵机呢,得设计结构使舵机转动转变为平动。那么这么简单的动作设计一堆结构不掉头发吗?答案是否定的,因为头发早已经掉没了哈哈哈啊咳咳,本着“能用就行”的原则,我设计了一套结构,当当当当!

解锁装置
解锁装置

Yep。只有一个电机,控制电机正转反转来拉动绳子,然后套索套住把儿就能用了。至于有同学问好不好使,那当然只有用过才知道咯...
(逃......ε=ε=ε=┏(゜ロ゜;)┛

程控

录入指纹,根据所使用的库 Adafruit/Adafruit-Fingerprint-Sensor-Library 中的示例 enroll 按提示操作录入指纹,点击 这里 传送至该文件的 Github 代码预览。利用 ArduinoIDE 上传示例后,打开端口监视器根据提示操作即可(由于闲着没事就顺便写了个傻瓜示意图,由 "" 括住的是端口提示信息,根据以下动作顺序执行即可录入指纹,提示信息不一样就多试几遍)。

流程示意:
  启动
    |-- 检测到指纹传感器
    |     |-- "Found fingerprint sensor!"
    |         "Ready to enroll a fingerprint!"
    |         "Please type in the ID # (from 1 to 127) you want to save this finger as..."
    |           |-- 输入存储的指纹的数字序号id
    |                 |--  "Enrolling ID #id"
    |                      "Waiting for valid finger to enroll as #id"
    |                        |-- 将手指放入传感器检测窗口
    |                              |-- "Image taken"
    |                                  "Image converted"
    |                                  "Remove finger"
    |                                    |-- 移开手指
    |                                          |-- "Place same finger again"
    |                                                |-- 再次将手指放入传感器检测窗口
    |                                                      |-- "Image taken"
    |                                                          "Image converted"
    |                                                          "Creating model for #id"
    |                                                          "Prints matched!"
    |                                                          "Stored!"
    |                                                            |-- 完成一个指纹录入
    |-- 未检测到传感器
          |-- "Did not find fingerprint sensor :("

录入指纹后即可重新烧录控制程序,这里值得注意的是指纹信息并不存储于单片机中,而是存储于指纹传感器的数据库中,所以不用担心单片机覆盖烧录会丢失指纹的问题。接下来控制程序结构:

#include <Adafruit_Fingerprint.h>   // 引入必需库函数

SoftwareSerial mySerial(2, 3);                                   // 指纹传感器设置
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);   // 指纹传感器设置
int MotorIn1 = 8;                   // 电机引脚,控制正反转
int MotorIn2 = 9;                   // 电机引脚,控制正反转

void setup()
{
    Serial.begin(9600);
    while (!Serial);  // For Yun/Leo/Micro/Zero/...
    delay(100);
    
    // 设置指纹传感器数据传输波特率
    finger.begin(57600);
    
    // 判断指纹传感器连接情况
    if (finger.verifyPassword()) {
        Serial.println("Found fingerprint sensor!");
    } else {
        Serial.println("Did not find fingerprint sensor :(");
        while (1) { delay(1); }
    }
    
    // 读取指纹传感器包含指纹枚数并等待识别
    finger.getTemplateCount();
    Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
    Serial.println("Waiting for valid finger...");
}

void loop()
{
    // 库函数示例:
    // getFingerprintIDez();
    // delay(50);
    // 修改后:
    
    int matchLevel = getFingerprintIDez();
    if (matchLevel >= 100)
        action();
    else {
        Serial.println("matchLevel is too low.");
        delay(50);
    }
    
}

// 获取指纹匹配度的多个函数,使用库函数中 fingerprint 示例即可,注意汉语注释处的修改
uint8_t getFingerprintID() {
    uint8_t p = finger.getImage();
    switch (p) {
        case FINGERPRINT_OK:
            Serial.println("Image taken");
            break;
        case FINGERPRINT_NOFINGER:
            Serial.println("No finger detected");
            return p;
        case FINGERPRINT_PACKETRECIEVEERR:
            Serial.println("Communication error");
            return p;
        case FINGERPRINT_IMAGEFAIL:
            Serial.println("Imaging error");
            return p;
        default:
            Serial.println("Unknown error");
            return p;
    }
    
    // OK success!
    
    p = finger.image2Tz();
    switch (p) {
        case FINGERPRINT_OK:
            Serial.println("Image converted");
            break;
        case FINGERPRINT_IMAGEMESS:
            Serial.println("Image too messy");
            return p;
        case FINGERPRINT_PACKETRECIEVEERR:
            Serial.println("Communication error");
            return p;
        case FINGERPRINT_FEATUREFAIL:
            Serial.println("Could not find fingerprint features");
            return p;
        case FINGERPRINT_INVALIDIMAGE:
            Serial.println("Could not find fingerprint features");
            return p;
        default:
            Serial.println("Unknown error");
            return p;
    }
    
    // OK converted!
    p = finger.fingerFastSearch();
    if (p == FINGERPRINT_OK) {
        Serial.println("Found a print match!");
    } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
        Serial.println("Communication error");
        return p;
    } else if (p == FINGERPRINT_NOTFOUND) {
        Serial.println("Did not find a match");
        return p;
    } else {
        Serial.println("Unknown error");
        return p;
    }   
    
    // found a match!
    Serial.print("Found ID #"); Serial.print(finger.fingerID); 
    Serial.print(" with confidence of "); Serial.println(finger.confidence);
    
    return finger.confidence;       // 注意这里将 finger.fingerID 替换为 finger.confidence 用于主控制程序判断匹配度
}

// returns -1 if failed, otherwise returns ID #
int getFingerprintIDez() {
    uint8_t p = finger.getImage();
    if (p != FINGERPRINT_OK)  return -1;
    
    p = finger.image2Tz();
    if (p != FINGERPRINT_OK)  return -1;
    
    p = finger.fingerFastSearch();
    if (p != FINGERPRINT_OK)  return -1;
    
    // found a match!
    Serial.print("Found ID #"); Serial.print(finger.fingerID); 
    Serial.print(" with confidence of "); Serial.println(finger.confidence);
    
    return finger.confidence;       // 注意这里将 finger.fingerID 替换为 finger.confidence 用于主控制程序判断匹配度
}
// 获取指纹匹配度的多个函数结束

// 用于控制反应的函数
void action(){
    // do something here.
}

调试

 妈耶,这项目太沙雕了。。。有什么可调试的啊...

效果

视频 ~~占位~~ gugu

看到评论区开始想问成品是什么效果,我脑补了一下我的门禁装上去的场面,啊,天呐,不堪入目...所以视频估计得咕咕了
(逃2...

资料

添加新评论

已有 15 条评论

所以你打算给门穿个洞吗 :aru1:

MonsterX MonsterX 回复 @Helo

我是准备用热熔胶给他粘上去的。但是应该会很容易掉。

Helo Helo 回复 @MonsterX

热熔胶粘上去不稳吧,而且电机???我们学校去年改造了计算机学院宿舍的门,支持刷卡进入。配送手环和手机 :aru18:

Helo Helo 回复 @Helo

配上自己的NFC手环

MonsterX MonsterX 回复 @Helo

是啊,所以我不打算弄了,而且指纹识别引用个库好像剩下的什么都不需要花大力气了。毫无技术含量。室友一般不喜欢带开门家伙,管他是钥匙还是卡...
但是你这???学校改造宿舍门还配送手环手机???tql

博主好秀呀QAQ

MonsterX MonsterX 回复 @ZigZagK

:aru87: 沙雕博主石锤…哈哈哈哈哈

那么这个成品出没有呢,我在想,毕业后宿管阿姨会不会找你巴拉巴拉讲一堆

MonsterX MonsterX 回复 @mineolym

嘻嘻嘻那应该不至于,我觉得这个开门结构太简单了。。。甚至十分智障。这篇文章写着写着突然觉得木得营养。

哇 动手能力真的 强 :aru65:

MonsterX MonsterX 回复 @子豪

:aru154: 实际上并没有动手,还只是买了材料而已…

MonsterX MonsterX 回复 @Nroy

捕捉一只咕咕怪!

让我们一起
咕咕咕

MonsterX MonsterX 回复 @c0sMx

:aru140: 一直咕一直爽