Introduction

Hi! This will be my tenth and final blog for the Design for a Cause challenge. It was a fun journey with a lot of things I've tried for the first time, from the fingerprint sensor to the RFID module. In the last 9 blogs I've covered everything regarding the build and general process of going through with this project. My initial plan with which I stuck till the end is to construct a device that will pick a key for us, depending on the door that we approached. I didn't manage to add all of the features I intended in the first place but on the other side, added some other features which I haven't planned for in the beginning. In this blog I will be covering the coding and the assembly of the first working prototype. Before I begin with coding the project I need to connect all of the modules that I covered in the past weeks during the challenge.

 

 

Breadboard prototype

It's time to fill up the breadboard with everything we have! Here is the list of things I need to connect to the Arduino:

 

  1. Battery voltage meter
  2. Mini servo
  3. Capacitive fingerprint sensor (GROW R302)
  4. Vibration sensor moudle (SW420)
  5. Buzzer
  6. RFID module (RC522)
  7. Button
  8. 3.3 V regulator
  9. LED-s

 

I've covered in detail the wiring for each of the modules in my previous blogs which I'll link below. One thing that's worth pointing out is that I've changed the baudrate on the fingerprint module using my PC to 9600. I needed to do this since the RFID module runs at 9600. To change the baudrate, all we need to do is go to the demo software which I talked about and choose 9600 in the drop down menu.

After picking the baudrate, we should be greeted with a message on the top saying we successfully changed the baudrate for the module. On to the breadboard now! To try and be as efficient as possible and to minimize troubleshooting that I need to I went and connected the modules one by one, coding them as I go, following my old blogs. This way I could determine from the start if something isn't working, and the whole process went pretty smooth, since we got all of the modules to work on their own already. In the end the breadboard ended up looking like this.

 

 

There isn't much to talk about here, the modules that had to be connected first were the fingerprint sensor and the RFID shield, since they required specific pins on the board, as for the rest, I was just filling up the digital and analog pin places as I needed to, just had to leave a pwm pin for the servo. Here is the wiring for the RFID and fingerprint module.

 

RFID module:

  1. 3.3V on RC522 --- 3.3V on Arduino Uno
  2. RST on RC522 --- Pin 6 on Arduino MKR1000
  3. GND on RC522 --- GND on Arduino MKR1000
  4. MISO on RC522 --- MISO on Arduino MKR1000 (Pin 10)
  5. MOSI on RC522 --- MOSI on Arduino MKR1000 (Pin 8)
  6. SCK on RC522 --- SCK on Arduino MKR1000 (Pin 9)
  7. SDA (SS) on RC522 --- Pin 7 on Arduino MKR1000

 

Fingerprint module:

  1. Red wire on the module --- 5V on the Arduino
  2. Black wire on the module --- GND on the Arduino
  3. Yellow wire on the module --- RX Pin on the Arduino (13 on the MKR1000)
  4. White wire on the module --- TX Pin on the Arduino (14 on the MKR1000)

 

Code

Now we got the part that will tie everything together, the code. The decision to go step by step with this was really worth it. I started with the fingerprint sensor trying out too see if it works, pulling out the information if the finger is detected or not and then continued on to a button and the RFID module and so on. Since I had all of the codes for different modules ready to go pretty much, it was a lot of moving stuff around, with adding some new stuff to tie everything up nicely. Here is the end code:

 

#include <Adafruit_Fingerprint.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>




#define mySerial Serial1


constexpr uint8_t RST_PIN = 6; 
constexpr uint8_t SS_PIN = 7;
MFRC522 mfrc522(SS_PIN, RST_PIN);


int finger_found=0,t1,t2,key=0,tag_found=0,t3,t4,k=0,battery_level=0,percentage=0;
const float k_battery=11.0/600;
float voltage;


const float max_v=5.00;
const float min_v=4.00;


const int key1=60;
const int key2=90;
const int key3=115;


Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);


Servo servo;


void setup()  
{
  pinMode(4,OUTPUT); //Mechanical buzzer
  pinMode(A2,OUTPUT); //Buzzer
  pinMode(A3,INPUT);  //Battery meter
  pinMode(A4,OUTPUT); //Red LED
  pinMode(A5,OUTPUT); //Yellow LED
  pinMode(A6,OUTPUT); //Green LED
  pinMode(0,INPUT); //Button
  pinMode(1,OUTPUT); //Servo transistor
  pinMode(5,INPUT); //Vibration sensor module
  
  
  Serial.begin(9600);
  SPI.begin();
  mfrc522.PCD_Init();
  mfrc522.PCD_DumpVersionToSerial();
  servo.attach(2);
  servo.write(90);
  delay(100);


  analogWrite(A2,0);
  analogWrite(A4,0);
  analogWrite(A5,0);
  analogWrite(A6,0);
  
  finger.begin(9600);
  
  
  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...");
}


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.fingerID;
}


// 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);
  finger_found=1;
  return finger.fingerID; 
}


void vibration_module_triggered()
{
  int x=0;
  t3=millis();
  t4=millis();
  while(t4-t3<=25000)
  {
    analogWrite(A2,1000);
    x = button_interrupt(150);
    if(x) {
      k=0;
      analogWrite(A2,0);
      return;}
    analogWrite(A2,0);
    x = button_interrupt(50);
    if(x)
    {
      k=0;
      return;
    }
    t4=millis();
    }
  }


int button_interrupt(int t)
{
  int t_start, t_end;
  t_start=millis();
  t_end=millis();


  while(t_end-t_start<=t)
  {
  if(digitalRead(0)==HIGH)
  {
    return 1;
    Serial.println("Button interrupt");
    }
    t_end=millis();
  }
     
  return 0;
  
  }




void success()
{
  Serial.println("Success protocol");
  analogWrite(A4,0);
  analogWrite(A5,0);
  analogWrite(A6,0);
  analogWrite(A6,1000);
  analogWrite(A2,1000);
  delay(150);
  analogWrite(A6,0);
  analogWrite(A2,0);
  delay(100);
  analogWrite(A2,1000);
  analogWrite(A6,1000);
  delay(150);
  analogWrite(A6,0);
  analogWrite(A2,0);
  delay(100);
  return;
  }


void fail()
{
  Serial.println("Failure protocol");
  analogWrite(A4,0);
  analogWrite(A5,0);
  analogWrite(A6,0);
  analogWrite(A2,1000);
  analogWrite(A4,1000);
  delay(500);
  analogWrite(A4,0);
  analogWrite(A2,0);
  return;
  }


void battery()
{
  battery_level=analogRead(A3);
  if(battery_level>=30)
  {
    voltage = k_battery*battery_level;
    }
    else
    {
      voltage=0;
      }


   //percentage=map(voltage,min_v,max_v,0,100);
   percentage=(voltage-min_v)*100/(max_v-min_v);
   Serial.println(voltage);
   Serial.println(percentage);


   if(percentage>=65)
   {
    analogWrite(A4,1000);
    analogWrite(A5,1000);
    analogWrite(A6,1000);
    }
    else if(percentage<60 && percentage>=30)
    {
      analogWrite(A6,0);
      analogWrite(A5,1000);
      analogWrite(A4,1000);
      }
      else if(percentage<30 && percentage>=10)
      {
        analogWrite(A6,0);
        analogWrite(A5,0);
        analogWrite(A4,1000);
        }
        else if(percentage<10)
        {
          analogWrite(A6,0);
          analogWrite(A5,0);
          analogWrite(A4,1000);
          delay(150);
          analogWrite(A4,0);
          delay(150);
          analogWrite(A4,1000);
          delay(150);
          analogWrite(A4,0);
          delay(150);
          }
  }


void loop()                    
{
  battery();
  k=0;
  if(digitalRead(5)==HIGH && k==0)
  {
    k++;
    delay(50);
    while(digitalRead(5)==HIGH)
    {
      k++;
      delay(50);
      }
    }
  
  if(k>=5)
  {
    Serial.println(k);
    Serial.println("Fall detected!");
    vibration_module_triggered();
    k=0;
    }
  
  if(digitalRead(0)==HIGH && finger_found==0)
  {
    Serial.println("Waiting for fingerprint");
    t1=millis();
    t2=millis();
    while(t2-t1<=30000)
    {
      getFingerprintIDez();
      delay(50);    
      if(finger_found==1)
        {
          Serial.println("Fingerprint detected and found");
          success();
          break;
        } 
      t2=millis();       
      }
      if(t2-t1>=30000)
      {
        fail();
        Serial.println("No finger detected");
        }
    }


    if(finger_found)
    {
      Serial.println("Initiating search for RFID tag");
      t1=millis();
      t2=millis();
    while(t2-t1<=30000)
    {
      
    if ( ! mfrc522.PICC_IsNewCardPresent())
    {
      return;
      }


  
    if ( ! mfrc522.PICC_ReadCardSerial()) 
    {
      return;
      }


    //Tag 1
    if (mfrc522.uid.uidByte[0] == 0xa0 && mfrc522.uid.uidByte[1] == 0xe4 && mfrc522.uid.uidByte[2] == 0x7b && mfrc522.uid.uidByte[3] == 0x4d){
     key=1;
     tag_found=1;
     Serial.println("Found tag 1");
     break;
      }


    //Tag 2
    if (mfrc522.uid.uidByte[0] == 0xf0 && mfrc522.uid.uidByte[1] == 0x45 && mfrc522.uid.uidByte[2] == 0x75 && mfrc522.uid.uidByte[3] == 0x4d){
     key=2;
     tag_found=1;
     Serial.println("Found tag 2");
     break;
      }


    //Tag 3
    if (mfrc522.uid.uidByte[0] == 0xd0 && mfrc522.uid.uidByte[1] == 0x9f && mfrc522.uid.uidByte[2] == 0x78 && mfrc522.uid.uidByte[3] == 0x4d){
     key=3;
     tag_found=1;
     Serial.println("Found tag 3");
     break;
      }   
      t2=millis();
        } 
        if(t2-t1>30000)
        {
          fail();
          Serial.println("Failed to find a tag");
          }
          }  


    if(finger_found && tag_found)
    {
      Serial.println("Moving the servo");
      delay(50);
      
      switch(key)
      {
        case 1:
            servo.write(key1);
            Serial.println("Servo moved to position 1");
            success();
            break;
         case 2:
            servo.write(key2);
            Serial.println("Servo moved to position 2");
            success();
            break;
         case 3:
            servo.write(key3);
            Serial.println("Servo moved to position 3");
            success();
            break;
        }


      
      }
   
    k=0;
    finger_found=0;
    tag_found=0;
    
}

 

The code is pretty straight forward. The whole interface for the device is one button. When the device is turned on, if we want it to choose a key, we start by pressing the button which initiates the fingerprint sensor for 30 seconds, if it recognizes the finger within those 30 seconds, we will be greeted with a double beep sound and the green LED flashing. If however there is no fingerprint detected we will be greeted with a single long beep and the red LED. The fingerprint sensor turns off after that until we press the button again. If the fingerprint was recognized we go into the next stage which is recognizing the tag, I put a timer of 30 seconds here as well, since I feel a person can grab the device as they approach the door. During the tag recognition section the module is scanning for a RFID tag, if it finds the tag that it knows it will depending on the ID know what value to forward to the rest of the program. One idea I had is to maybe add a couple of "fake tags" for security reasons. We would have 2 tags on the door for example, one would choose the key and the other one would trigger the alarm-buzzer on the device. This would in no shape or form completely secure the user, but in case of rushed attempt I think it could be useful. Continuing on, when we have the information we need for the key, all we need to do is rotate the servo depending on what the information is. And after that's done the program finished, waiting for the next button press. While it waits for the button press, I've added a couple of features, battery monitoring and fall detection. The fall detection is mostly a proof of concept since it needs to rest of the system to be powered on for it to trigger the buzzer, the way I would like it is to be able to work even if the rest of the device is shut down to save battery life. The battery meter updates through every cycle and has 4 different levels, all three LED-s, yellow and red, red and blinking red when the battery goes underneath 10%. There is one more thing that I didn't try adding but would be a big bonus, and that's is adding npn transistors for powering the RFID module and the servo, though it would require more pins. That would be the basic operation of the breadboar prototype, and here is a video of it working!

 

Test

 

Next phase for this is assembling it all onto the device that I've been making for the past couple of weeks, so let's get to it!

 

Assembly

Now that we know everything is working as it should, all that's left is to mount everything onto the device piece by piece, while this sounds much easier than the coding, it turned out way harder in fact. This is the last day for project submissions so I didn't have time to desolder all of the pins from the Arduino, so I stick with them and used jumper wires, which unfortunately made the device unusable with only one hand. Here are some of the pictures of how the assembly went.

 

 

{gallery} Assembly

Battery: The battery fit perfectly on the side of the spring holder and I glue the charging circuit right behind it

RFID module: I mounted the RFID module on the bottom plate of the key holder, since it's the easiest to put against a tag that's attached to a door

Arduino: I had to mount the Arduino on the other side of the spring holder, there really wasn't any suitable space for that would leave the connectors free for me to connect the wires

Fingerprint module: I mounted the fingerprint module also underneath, next to the RFID module

Wires: A giant bulk of wires on top of the Arduino, there is nothing I can do for this since this is all dependant on the position of the Arduino. A little cable management would help a little, but I don't want to risk bending any of the wires and damaging anything in the process

Charging circuit: The charging circuit fit snugly next to the servo without causing any issues to the movement of the servo

 

 

That would be it for the assembly. I would say it went smooth, but I was doing it in a really big hurry so I had a few problems along the way. The biggest one being using the wrong wire from the fingerprint module, and completely forgetting to connect the ground wire to the buzzer, but when I sorted out those things, everything worked as it should. All that's left to do is test it out and that would be it.

 

 

First Test

 

 

In the first video I tried out the device for the first time without external power with everything mounted to it, everything works as it did on the breadboard tests, except the yellow and green LED-s which I think I messed up when trying to add  another feature without testing. As for the second video, I mounted one of the tags with double sided sticky tape to the door of the shed/boiler room. It worked as I hoped it would! I left a few things unused in the code such as a pin declared for the servo transistor. The plan was to use transistors to cut the power off of the servo and RFID module until they are needed to be used to save power.

 

Previous blogs

This is my tenth and final blog for this challenge, in it I just went past through all of the components and coding, I covered all of that separately in my other blogs which all can be found here:

 

  1. Fingerprint Skeleton Key - Concept - Design for a Cause Challenge - Blog Post #1
  2. Fingerprint Skeleton Key - Slider mechanism part 1 - Design for a Cause Challenge - Blog Post #2
  3. Fingerprint Skeleton Key - RFID Module - Design for a Cause Challenge - Blog Post #3
  4. Fingerprint Skeleton Key - Capacitive Fingerprint Module - Design for a Cause Challenge - Blog Post #4
  5. Fingerprint Skeleton Key - Feedback for the user - Design for a Cause Challenge - Blog Post #5
  6. Fingerprint Skeleton Key - Slider mechanism part 2 - Design for a Cause Challenge - Blog Post #6
  7. Fingerprint Skeleton Key - Key Picking Mechanism Part 1 - Design for a Cause Challenge - Blog Post #7
  8. Fingerprint Skeleton Key - Vibration Sensor Module & Battery - Design for a Cause Challenge - Blog Post #8
  9. Fingerprint Skeleton Key - Key Picking Mechanism Part 2 - Design for a Cause Challenge - Blog Post #9

 

Upgrades

There are a few different upgrades I would do this. First and most importantly, I would be using a 3D printer for the most parts and changing the design a bit. Would experiment with different types of springs and stuff like that to try and get the device as compact as possible. I love how good the fingerprint sensor and the RFID module work but would probably add some kind of a mechanical lock for the device if the finger is not recognized. Since the makerspace opened again, I will probably be there regularly and trying to work on this project again in the free time. I want to make an everyday usable version of this.

 

 

Summary

I set out to build a device that would help with choosing a right key for the user. I finished up with a proof of concept that, while not finished on the outside, works pretty smoothly when it comes to functionality. While of course there always things that I would like to change, I can say I am thrilled how it turned out and that it actually does what I want it to do. This challenge was a really fun journey with a lot of new things for me like the fingerprint and RFID sensors. I will for sure continue to work on this in in my free time, because I would really like to have a device like this in my backpack. Even though the design challenge is over, I'll for sure post an update when I finish up the device! Thank you a lot to everyone who followed my journey through this design challenge and for all of the comments along the way. Thank you for reading the blog, hope you liked it!

 

Milos