Biometric security toy box

A couple of weeks ago Apple announced the new iPhone 5s with Touch ID, a fingerprint identity sensor that replaces the need for a conventional PIN number or password. It got me thinking… wouldn’t it be cool to make a lockable toy box with fingerprint access for my son’s toy car collection.

At the heart of the system is an Arduino Uno and an Optical Fingerprint Sensor from Adafruit. The box uses a standard hobby servo as the latch to lock and unlock the lid based on the fingerprint detected.

Fingerprints are initially registered directly into the Flash memory of the fingerprint scanner using the free SFG Demo software on a Windows PC – instructions here on Adafruit.

In order to give the box a battery life measured in months or years rather than hours, I used a Pololu SV power switch (I got mine from Proto-Pic) between the battery pack and the Arduino.  This switch allows a standard hardware button to power the Arduino on and off.  But more importantly, a separate logic input on the Pololu allows the Arduino to turn itself off automatically after a predefined timeout in the script.

HornThe locking mechanism is simple but effective: a notch carved out of the standard servo horn hooks round a screw mounted inside the box base.

The servo ‘locks’ at approximately 90 degrees, at which point it is tightly wrapped around the screw. Because the screw head is chamfered, the servo horn gets a really tight grip, pulling the box lid down hard against the base. And because the servo horn is pointing straight down at 90 degrees the box stays ‘locked’ shut even when the servo is turned off.

Here’s the circuit diagram:

Biometric Toy Box Fritzing

The electronics are all housed in the lid of the box, protected by a sheet of 2mm clear acrylic.  This keeps the electronics safe from curious fingers and metal cars, and also helps to keep the parts securely in place.

Here’s the Arduino code:

/***************************************************
  Biometric Toy Box
  by Grant Gibson - http://www.grantgibson.co.uk

  Incorporates code example from Adafruit - see separate info/license below
 ****************************************************/

/***************************************************
  Designed specifically to work with the Adafruit BMP085 Breakout
  ----> http://www.adafruit.com/products/751

  These displays use TTL Serial to communicate, 2 pins are required to
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Servo.h>
#include <Adafruit_Fingerprint.h>
#if ARDUINO >= 100
 #include <SoftwareSerial.h>
#else
 #include <NewSoftSerial.h>
#endif

int getFingerprintIDez();

Servo myservo;
int pos = 0;    		// Store the servo position
int servoLock = 0;		// Whether the servo is currently in locked or open position
int mytimer = 0;		// A timer that is incremented each loop. Turns off device after inactivity.

int speakerOut = 6;	// Piezo buzzer
int printID = -1;	// Variable to store the current finger print identified (indexed from zero)

// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
#if ARDUINO >= 100
SoftwareSerial mySerial(2, 3);
#else
NewSoftSerial mySerial(2, 3);
#endif

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

void setup()
{
  Serial.begin(9600);
  Serial.println("fingertest");

  myservo.attach(10);
  myservo.write(82);

  pinMode(8, INPUT); 	// Logic control of the power switch
  digitalWrite(8, LOW);	// Set Low for power on, High to power off

  pinMode(speakerOut, OUTPUT);

  finger.begin(57600); // set the data rate for the sensor serial port

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1);
  }
  Serial.println("Waiting for valid finger...");

  delay(500);
  myservo.detach();   // Detach the servo to save wear & power
}

void loop()
{
  printID = getFingerprintIDez();
  if(printID >= 0) {
    // Valid fingerprint, now toggle the servo position
    myservo.attach(10);
    if(servoLock == 0) {
      myservo.write(10);
      servoLock = 1;
    } else {
      myservo.write(82);
      servoLock = 0;
    }
    delay(1000);
    myservo.detach();
    mytimer = 0;	    // Reset the timer, device still in use
  } else if (printID == -2) {
    // Bad scan
    analogWrite(speakerOut,100);	// BUZZ!!!!
    delay(500);
    analogWrite(speakerOut,0);
  } else if(printID == -3) {
    // Invalid Finger!
    analogWrite(speakerOut,200);	// Different buzz
    delay(1000);
    analogWrite(speakerOut,0);
  }

  delay(100);
  if(mytimer >= 100) {
    // Device has been idle for 100 loops, turn off by setting the Pololu switch high
    digitalWrite(8, HIGH);
    Serial.println("Power down");
  } else {
    mytimer++;
  }
}

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);

}

// 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 -2;

  p = finger.fingerFastSearch();
  if (p != FINGERPRINT_OK)  return -3;

  // found a match!
  Serial.print("Found ID #"); Serial.print(finger.fingerID);
  Serial.print(" with confidence of "); Serial.println(finger.confidence);
  return finger.fingerID;
}

And the parts list:

  1. Arduino Uno
  2. Optical Fingerprint reader
  3. Pololu power switch SV
  4. Piezo Buzzer
  5. Push button
  6. Hobby servo – I used this one from Hobby King
  7. Wooden box – I bought this one from eBay
  8. Battery holder – I used 1×4 AA and 1×3 AA in series for a total of 10.5V
  9. Solderless breadboard

Building this box was a lot of fun – electronics, woodworking and a bit of programming combined to make something interesting and unique. If you build anything based on this post I’d love to hear about it. Or if you have any questions, please get in touch.

Box closed

Other coverage

Comments are closed.