Sunday, February 15, 2009

RFID Arduino Door Lock

Back again after a short hiatus...

This project actually looks rather silly and this time I have a video to prove it! A while back I bought an Adafruit Motor Shield (click here for more info) and a couple of servo motors. I was looking around for a quick project when I remembered my old friend the RFID reader (which you will remember from this post). Perhaps because my day job involves the hotel industry, I thought why not have a try at building a door lock?

I am actually rather proud of this one, because I actually set about the design process in a proper organized fashion. I thought about what I wanted it to do and then drew a diagram of what pins I would use then I set about designing the software in a reasonably organized way. I must be getting the hang of this - only a moderate amount of banging my head on my desk!

Without further ado, here is the exciting multimedia part of tonight's presentation!



Now for a couple of quick pictures. This shows the inside mechanism:




And here is the RFID reader on the outside of the door:



Oh no, another poorly drawn Eagle CAD schematic:




Hardwarewise, it is very simple. The only oddity here is that I have actually used the Analog pins of the Arduino as Digital pins. This is done quite simply by calling them pins 14 - 19. Why? This is because the Motor Sheild either uses or covers up most of the usual digital pins. Really, for a simple servo motoro like this, I am not actually using all those digitial pins, and, in fact, I probably don't need the Motor Sheild at all. An Arduino can drive a simple servo without any extra circuitry. However, I wanted to set this up so that a stepper motor could be substituted in later on.

Software

So, here is the code that makes it work:
/* ======== Arduino RFID door lock ============

copyright Chris Armour, Feb 2009

*/

#include <AFSoftSerial.h> //Adafruit soft serial library - slightly modified!
#include <ServoTimer1.h> //Ada Motorshield servo library

// =========Initialize variables and so on =========================//
ServoTimer1 servo1;
AFSoftSerial rfidSerial =  AFSoftSerial(14,15);
//Note that this uses a version of the AFSoftSerial library modified to support pin numbers > 9.
int LEDPin = 16;
int incomingByte[16];
int oldCardNum = 0;
int newCardNum = 0;
int goodCardNum1 = 56;
int goodCardNum2 = 51;
int Angle = 0;
int LockState = 1; //1 = unlocked 0 = locked
int LockLED = 17;
int InButton = 18;
int buttonWas = 0; // The state of the switch (pushed = 1, not pushed = 0) last time we looked
int buttonIs = 0; // Current state of the switch

//==========Setup pins & servo ===============//
void setup() {
Serial.begin(9600);
rfidSerial.begin(9600);
pinMode(LEDPin, OUTPUT);
pinMode(LockLED, OUTPUT);
pinMode(InButton, INPUT);
servo1.attach(10);
servo1.write(Angle);
}

//===========Functions=====================//
void getButton() {
buttonWas = buttonIs; // Set the old state of the button to be the current state since we're creating a new current state.
buttonIs = digitalRead(InButton); // Read the button state
}

void openClose(){ //Evaluates the LockState variable
 digitalWrite(LEDPin, HIGH); //Turns on pass/fail LED
   if (LockState == 1){
     Angle = 180; //Turns servo to UNLOCKED position
     LockState = 0; //toggles Lockstate
     digitalWrite(LockLED,HIGH); //Turns on LockLED to show door UNLOCKED
     }
   else {
     Angle = 0; //turns servo to LOCKED position
     LockState = 1; //toggles lock state
     digitalWrite(LockLED,LOW); //Turns off LockLED to show door LOCKED
     }
   servo1.write(Angle); //Move the servo appropriately
   delay(1000);
   digitalWrite(LEDPin,LOW); //after 1 second, turn off the pass/fail LED
}

//================= Main loop =========================//

void loop() {

getButton();
if((buttonIs==1)&&(buttonWas==0)) { //If the button has been pushed, call openClose to toggle the state of the servo & LEDs.
 openClose();
   }

if(incomingByte[11] > 0){
 oldCardNum = incomingByte[11]; //Sets the value of the last read RFID card to oldCardNum. Just using the 12 digit of the card ID.
}

if(rfidSerial.available() > 0) { //If the AFSoftSerial RX pin reads new incoming data.
 for (int i=0; i <= 16; i++){ //It reads the next 16 characters
     delay(10);
 incomingByte[i] = rfidSerial.read();
     newCardNum = incomingByte[11]; //Pick out ASCII character #12 since it is unique across the 5 cards I have.
      }
  }

if(oldCardNum != newCardNum) {  //Check if a new card # has been received.
  if(newCardNum == goodCardNum1 || newCardNum == goodCardNum2){ //If the new card number equals either of the key cards.
    openClose(); //run the openClose function
   }
else { //If the card isn't a good card, flash the pass/fail indicator 3 times.
  for (int x=0; x <=3; x++){
  digitalWrite(LEDPin, HIGH);
   delay(100);
   digitalWrite(LEDPin,LOW);
   delay(100);
  }
}
Serial.println(newCardNum); //serial output for debugging.
}

}


I am actually rather proud of this code. It uses actual functions for getting the value of the button and for evaluating the lock/unlock state. Of the five RFID cards that I have, two of them are hard coded as "good cards" and the other three trigger the flashing LEDs as "bad cards".

The main thing to note in this software is that the Lady Ada AFSoftSerial library had to be modified to use the Analog Pins (i.e., digital pins in the range 14 to 19). Apparently the AFSoftSerial library is hard coded to work with pins below 13. This is the one time I actually had to ASK SOMEONE for help on something related to the Arduino (in contrast to the Gumstix, which took endless asking to get working!). Anyway, here is a link to the forum posting for those who are curious. It is a simple fix that user mtbf0 came up with, but it was over my head!!

That's enough for this project. This one was fun since it actually moves and potentially does useful work!