Come realizzare un sistema per il controllo degli accessi con badge RFID

In questo articolo vedremo come realizzare un sistema per il controllo degli accessi, quello utilizzato spesso per controllare l’arrivo e l’uscita dei dipendenti in un’azienda  (Fig.1).

RFID card
Fig.1 – RFID card

Il progetto in questione si basa su 4 componenti principali:

  1. Codice Java
  2. Database
  3. Arduino Uno
  4. Modulo RFID-RC522

Il codice java non è nient’altro che il software necessario per elaborare i dati provenienti da Arduino e controllare se il badge è abilitato o meno.
Il database invece conterrà i dati dei dipendenti dell’azienda con i relativo codice del badge, e lo storico degli accessi.
Per meglio capire come è fatto il database vediamo la sua struttura, ossia le tabelle da cui è composto:

  • Employees: contiene il nome di tutti i dipendenti dell’azienda con i relativo codice del badge.
  • EmployeesAtWork: contiene la lista dei dipendenti attualmente a lavoro con la relativa ora di ingresso.
  • History: contiene la lista di tutti gli accessi in azienda contenente il nome, la data e un campo che indica l’ingresso o l’uscita del dipendente.

Infine arriviamo alla parte hardware di questo progetto, la scheda Arduino collegata al modulo RFID-RC522 che ci permette di leggere il codice delle card RFID.
Prima di parlare di questo modulo è meglio spendere qualche minuto sul RFID, per capire meglio cos’è e quali sono i suoi utilizzi principali.

La tecnologia RFID

Negli ultimi anni le procedure di identificazione automatica hanno acquisito popolarità nei campi della gestione del lavoro, del magazzino, dell’inventario, della catena di montaggio e delle operazioni di logistica.

Le procedure di identificazione automatica, fornendo informazioni su persone, animali, beni e prodotti in transito, rappresentano al giorno d’oggi una delle principali direzioni di sviluppo.

Gli ormai onnipresenti codici a barre, che in passato hanno rivoluzionato i sistemi di identificazione, si stanno rivelando inadeguati a causa della scarsa capacità di memorizzazione e di programmabilità.

La soluzione migliore sarebbe quella di memorizzare i dati in un chip. Oggi giorno il dispositivo elettronico di archiviazione di dati più diffuso è la smart card (carte telefoniche e bancarie), basate su lettura a contatto di una barra magnetica.

Il contatto meccanico usato in tali carte spesso non è pratico, risulta di gran lunga migliore un trasferimento di dati in modo contactless, ovvero in assenza di contatto, tra il dispositivo di archiviazione ed il suo apposito lettore. Nel caso ideale la potenza richiesta per il funzionamento del dispositivo può essere trasferita dal lettore con tecnologia contactless.
I sistemi RFID attuano quanto descritto, gestendo procedure per lo scambio di energia e di dati. In Fig.2 è presente il sistema di base RFID costituito principalmente da:

  1. Reader
  2. Trasponder o tag
Sistema di base RFID
Fig.2 – Sistema di base RFID

Il primo invia un segnale ai tag che devono essere interrogati, mentre questi ultimi includono un’antenna per la comunicazione, un microchip ed una memoria interna di lettura e scrittura che tiene traccia della storia del prodotto senza alcuna manutenzione o ricarica da fonti di energia: è proprio questa semplicità che sta permettendo a questa tecnologia di affermarsi nei settori industriali e commerciali.

Quando il tag transita attraverso il campo e.m viene attivato il trasferimento dell’informazione, modulando con i dati il segnale radio che viene poi rinviato verso il reader.

Classificazione dei Tag RFID

I tag RFID si suddividono in base all’alimentazione in tre classi:

  1. Tag Attivi
  2. Tag Semi-Passivi
  3. Tag Passivi

I Tag Attivi hanno una fonte di alimentazione indipendente dal reader e la capacità di trasmettere senza essere interrogati. Questi tag possono raggiungere grandi distanze di lettura (100m – 1Km) richiedono però l’uso di una batteria che ne alza i costi e ne riduce l’autonomia.

I Tag Semi-passivi hanno una fonte di alimentazione indipendente dal reader ma trasmettono solo se interrogati. Nei tag Semi-Passivi le distanze di lettura si riducono (decine di metri), anche in questo caso è richiesta una batteria che per l’uso che se ne fa rende i costi medi e garantisce un’autonomia elevata.

I Tag Passivi sono alimentati dalla potenza irradiata dall’antenna del reader quando questa li interroga. Questi tag hanno un range di lettura molto basso (<10m) però l’assenza della batteria ne abbassa i costi notevolmente.

Sono state standardizzate bande di frequenza di utilizzo dalle LF low frequency(125-134 kHz) alle HF high-frequency (13.56 MHz) fino alle UHF (860 MHz) e alle microonde (2.4 GHz e 5.8 GHz).

RFID-RC522

Il modulo RFID RC522 (Fig.3) fa parte della terza categoria, o meglio è la card che si interfaccia con questo modulo che rappresenta un tag passivo. Questo lettore di tessere RFID, basato sul chip MFRC522 della Philips, lavora a 13.56 MHz e permette la lettura e scrittura dei tag .
Per maggiori informazioni su questo modulo potete leggere il relativo datasheet che trovate a questo link http://www.nxp.com/documents/data_sheet/MFRC522.pdf.

Modulo RFID-RC522
Fig.3 – Modulo RFID-RC522

Collegare questo modulo ad Arduino è semplicissimo basta seguire la seguente tabella, scegliendo la colonna in base al tipo di Arduino utilizzato, in questo progetto useremo la versione Uno.

Signal Uno Mega Nano v3 Leonardo/Micro Pro Micro
RST/Reset 9 5 D9 RESET / ICSP-5 RST
SPI SS 10 53 D10 10 10
SPI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
SPI MISO 12 / ICSP-1 50 D12 ICSP-1 14
SPI SCK 13 / ICSP-3 52 D13 ICSP-3 15

Sketch ArduinoBadge

Il codice da caricare su Arduino per realizzare questo progetto è il seguente:

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

#define RST_PIN		9
#define SS_PIN		10


byte readCard[4]; // variable used for write data read of the serial 
String ID; // variable used for write the code of the card RFID
int led = 8; // pin IO used for the led

// Create MFRC522 instance
MFRC522 mfrc522(SS_PIN, RST_PIN);	

void setup() {
  pinMode(led,OUTPUT);          // Define the pin of the led as output
  digitalWrite(led,LOW);        // Set the pin LOW
  Serial.begin(9600);		// Initialize serial communications with the PC
  SPI.begin();			// Init SPI bus
  mfrc522.PCD_Init();		// Init MFRC522
}

void loop() {
  ReadCard();
}

void ReadCard() {
  // Getting ready for Reading PICCs
  if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
    return;
  }
  if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
    return;
  }
  
  // There are Mifare PICCs which have 4 byte or 7 byte UID care if you use 7 byte PICC
  // I think we should assume every PICC as they have 4 byte UID
  // Until we support 7 byte PICCs

  for (int i = 0; i < 4; i++) {
    readCard[i] = mfrc522.uid.uidByte[i];
    ID += String(readCard[i], HEX);
  }

  ID.toUpperCase();
  // Send the ID on the serial port
  Serial.println(ID);
  // When arrive the data, on and off the led
  if (Serial.available() && Serial.read() == 1) {
    digitalWrite(led,HIGH);
    delay(500);
    digitalWrite(led,LOW);
  }  
  ID = "";
  mfrc522.PICC_HaltA(); // Stop reading
}

Come prima cosa notiamo che occorre caricare le seguenti librerie:

#include <SPI.h>; 
#include <MFRC522.h>;

La SPI (Serial Peripheral Interface) è necessaria per permettere la comunicazione tra Arduino e il lettore RFID, mentre la seconda è la libreria contenente vari metodi utili per leggere e scrivere sulla card.

Il codice è abbastanza comprensibile, all’inizio si crea l’istanza dell’oggetto MFRC522 e nel setup viene inizializzata con mfrc522.PCD_Init();
Nel loop viene eseguita la funzione ReadCard() che non fa nient’altro che controllare se c’è un card nelle vicinanza del reader e in caso positivo leggere il suo codice. Per meglio capire come questo sia possibile vediamo alcune parti del codice.

// Getting ready for Reading PICCs 
if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue 
 return; 
} 
if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue 
 return; 
}

Noi vogliamo leggere il codice della card solo se avvicinata al reader e nel caso rimanessimo qualche secondo sopra il lettore non vogliamo leggerla di nuovo, il primo if (! mfrc522.PICC_IsNewCardPresent()) fa proprio questo infatti permette di passare al secondo if solamente se viene posta sopra al reader una nuova card, in caso contrario return ossia viene saltato tutto il codice successivo.

Il secondo if (! mfrc522.PICC_ReadCardSerial()) invece permette la lettura dei dati contenuti nella card tra cui UID (user identifier) che verrà poi letto attraverso questa parte di codice.

for (int i = 0; i < 4; i++) { 
 readCard[i] = mfrc522.uid.uidByte[i]; 
 ID += String(readCard[i], HEX); 
}

Dopo aver letto il codice questo viene inviato sulla seriale per poi essere usato dal codice java per fare le opportune verifiche sul DB, in caso sia abilitato viene inviato ad Arduino il valore “1″ il quale farà lampeggiare il led collegato al pin 8 come si può vedere nel seguente codice.

if (Serial.available() && Serial.read() == 1) { 
 digitalWrite(led,HIGH); 
 delay(500); 
 digitalWrite(led,LOW); 
}

 

Codice Java

Ora siamo pronti per vedere il codice java della classe ArduinoBadge , in particolare vediamo com’è fatto il main.

public static void main(String args[]) throws ClassNotFoundException, SQLException, FileProblemException {

    	ArduinoBadge db = new ArduinoBadge();
        db.ConnectionDB();
		// Save in listPort the list of the ports present
    	db.listPort = ArduinoBadge.listPort();
        
    	// Allow the selection of the serial port to use
    	Scanner s = new Scanner(System.in);
	int chosenPort = s.nextInt();
	s.close();
        SerialPort serialPort = new SerialPort(db.listPort[chosenPort-1]);

        String input = "";
        
        try {
            // Open the serial port
            System.out.println("Port opened: " + serialPort.openPort());
            // Set the serial port parameters
            System.out.println("Params setted: " + serialPort.setParams(9600, 8, 1, 0));
            
            while(true) {
            	if (serialPort.readString()!=null) {
            		// Read the first 7 byte
            		input = serialPort.readString(7); 
            		System.out.println("\nRead: " + input);
                	if (db.CheckBadge(input)) {
                		serialPort.writeByte((byte)1);
                	}
                	System.out.println("\n");
            	}
            }
        }
        catch (SerialPortException ex){
            System.out.println(ex);
        }
}

Possiamo notare subito che viene istanziato un oggetto db di tipo ArduinoBadge con il quale viene richiamato dopo il metodo ConnectionDB(), il quale carica il bridge SQLite, crea la connessione al DB ed infine realizza la struttura delle tabelle, questo grazie al seguente codice.

public void ConnectionDB() throws ClassNotFoundException, SQLException, FileProblemException { 
 
 System.out.println("\n0) Initialization............................."); 
 // Load the bridge for SQLite 
 Class.forName("org.sqlite.JDBC"); 
 // NOTE: for sqlite we don't need the password! 
 conn = DriverManager.getConnection("jdbc:sqlite:files/DB_Badge.db", "root", "root"); 
 
 System.out.println("\n1) Create tables............................\n"); 
 // Create the structur of the tables 
 stmt = conn.createStatement(); 
 String sql = FileUtilities.read(new File("files/CreateDB_Badge.sql")); 
 stmt.executeUpdate(sql); 
 stmt.close(); 
 
} 

Dopo aver realizzato la connessione al DB dobbiamo collegarci alla seriale di Arduino per questo utilizziamo il metodo statico della classe ArduinoBadge listPort(), che permette di stampare su console la lista delle seriali disponibili e ritorna tale lista in un array di stringhe.

Il codice di questo metodo è visibile di seguito.

public static String[] listPort() {	
	// Save in portNames the list of the ports present
	String[] portNames = SerialPortList.getPortNames();
		        
	if (portNames.length == 0) {
		    System.out.println("There are no serial-ports :(");
		    System.out.println("Press Enter to exit...");
		    try {
		        System.in.read();
		    } catch (IOException e) {
		          e.printStackTrace();
		    }
		    return null;
	}

	System.out.println("Choose the port:");
	for (int i = 0; i < portNames.length; i++){
		    System.out.println(i+1 + ": " + portNames[i]);
	}
	return portNames;
}

Dopo aver scelto la porta seriale, aperta e impostato i parametri da utilizzare si arriva al cuore del codice ossia ad un while infinito che permette di ascoltare se ci sono dati sulla porta e in caso positivo di salvare i primi 7 byte e convertirli in stringa.

Alla fine si richiama sull’oggetto db, creato all’inizio, il metodo CheckBadge(input) passandogli in ingresso la stringa letta da Arduino. Come si intuisce dal nome del metodo questo fa un controllo nella tabella Employees per verificare se il badge appartiene ad un dipendente dell’azienda, ed in caso positivo vengono inserito l’accesso del dipendente, con relativa data, sia nella tabella EmployeesAtWork che History, inoltre viene inviato sulla seriale la cirfra “1” che Arduino interpreterà facendo lampeggiare il suo led.
Tutto questo è realizzato nel codice qui sotto.

public boolean CheckBadge(String input) throws ClassNotFoundException, SQLException, FileProblemException {
		
	// Instantiate a Date object
	Date date = new Date();
		
	System.out.println("\n2) Check Badge............................");
	stmt = conn.createStatement();
	String queryFindBadge = "SELECT * FROM Employees WHERE CodBadge = '" + input + "'";
	int id_Employee = 0;
	String nameEmployee = "";
	String sexEmployee = "";

	ResultSet rs = stmt.executeQuery(queryFindBadge);
	if (rs.next()) {
		nameEmployee = rs.getString("Name");
		sexEmployee = rs.getString("Sex");
		id_Employee = rs.getInt("id_Employee");	
		String queryEmployeeAtWork = "SELECT * FROM EmployeesAtWork WHERE id_Employee = '" + id_Employee + "'";
			 
		rs = stmt.executeQuery(queryEmployeeAtWork);
		if (rs.next()) {
			String queryDeleteEmployee = "DELETE FROM EmployeesAtWork WHERE id_Employee = '" + id_Employee + "'";
			stmt.executeUpdate(queryDeleteEmployee);
			String queryHistory = "INSERT INTO History (Name, Status, Date) VALUES('" + nameEmployee + "','OUT','" + date.toString() +"')";
			stmt.executeUpdate(queryHistory);
			System.out.println("Goodbye! " + nameEmployee);
			rs.close();
			stmt.close();
			return true;
		} else {
			System.out.println("Welcome! " + nameEmployee);
			String queryInsert = "INSERT INTO EmployeesAtWork (id_Employee, Date) VALUES('" + id_Employee + "','" + date.toString() +"')";
			String queryHistory = "INSERT INTO History (Name, Status, Date) VALUES('" + nameEmployee + "','IN','" + date.toString() +"')";
			stmt.executeUpdate(queryInsert);
			stmt.executeUpdate(queryHistory);
			rs.close();
			stmt.close();
			return true;
		}
	} else {
		System.out.println("ERROR: Employee with code " + input + " is not present in DataBase");
		rs.close();
		stmt.close();
		return false;
	}
}

Ora che avete visto tutto il codice siete pronti per realizzare il vostro sistema di accesso personale, qui sotto trovate il link per scaricare il progetto.

Download
Download