Open top menu
quinta-feira, 25 de abril de 2013

Hoje vou apresentar o hardware de um projeto de controle de acesso de colaboradores baseado em Arduino, RFID e Ethernet, futuramente vou postar uma versão da WEBAPI e site de gerenciamento dos acessos.

Para liberação de acesso o usuário aproxima o cartão RFID, o hardware realiza a leitura do número do cartão e acessa a WEBAPI de validação, se o cartão for válido, retorna o status de liberação com o nome do usuário cadastrado no sistema.

Vamos ver um video e fotos do projeto:


Protótipo do equipamento


Detalhe das conexões


Cada local de acesso é cadastrado com um código e as coordenadas de localização, possibilitando em tempo real acompanhar em um mapa todas as entradas e saídas dos colaboradores nos locais cadastrados.


API de acesso 
Request:

http://SERVIDOR/api/acesso/CODIGOCLIENTE/CODIGOEQUIPAMENTO/NUMEROCARTAORFID


SERVIDOR: IP ou DNS do servidor com WEBAPI publicada.
CODIGOCLIENTE: Codigo fixo do cliente, serve para agrupar os locais e usuários.
CODIGOEQUIPAMENTO: Código de identificação único do hardware, atráves dele é cadastrada as coordenadas para identificação do local do acesso.
NUMEROCARTAORFID: Número do cartão RFID.


Response:
<XML>|STATUS NOMEUSUARIO|</XML>
|: Caracter que identifica o início do retorno de validação do acesso
STATUS: Status da validação do acesso
NOMEUSUARIO: Nome do Usuário
|:Caracter que identifica o término do retorno de validação do acesso


Exemplo do acesso
O que é RFID?
Identificação por radiofrequência ou RFID (do inglês "Radio-Frequency IDentification" ) é um método de identificação automática através de sinais de rádio, recuperando e armazenando dados remotamente através de dispositivos denominados etiquetas RFID.

Uma etiqueta ou tag RFID é um transpondedor, pequeno objeto que pode ser colocado em uma pessoa, animal, equipamento, embalagem ou produto, dentre outros. Contém chips de silício e antenas que lhe permite responder aos sinais de rádio enviados por uma base transmissora. Além das etiquetas passivas, que respondem ao sinal enviado pela base transmissora, existem ainda as etiquetas semi-passivas e as ativas, dotadas de bateria, que lhes permite enviar o próprio sinal. São bem mais caras que do que as etiquetas passivas.
RFID: utiliza transponders ( os quais podem ser apenas lidos ou lidos e escritos) nos produtos, como uma alternativa aos códigos de barras, de modo a permitir a identificação do produto de alguma distância do scanner ou independente, fora de posicionamento. Tecnologia que viabiliza a comunicação de dados através de etiquetas com chips ou transponders que transmitem a informação a partir da passagem por um campo de indução. (ex: muito usado em pedágio "sem parar").

by Wikipedia


Conexões do projeto:

Lista de Componentes:
  • Arduino Mega 2560
  • Arduino Ethernet Shield
  • Arduino Rele Shield *
  • Regulador de tensão LM7805.
  • Leitor RFID ID-12 Innovations
  • Cartões RFid
  • Fonte chaveada 12V x 3A
  • LCD 40 Colunas x 4 Linhas (pode ser usado LCD com 2 linhas)
  • Buzzer
  • Rabicho de alimentação para fonte
  • Fios, barras de terminais e termoretráteis para conexão
* A montagem do rele shield foi apresentada no post Construindo um Relé Shield






Pode ser substuido por Arduino 5V Relay module





Código fonte do Arduino:
/*

Sergio de Miranda e Castro Mokshin
26/04/2013

Todos os direitos reservados

*/

#include 
#include 
#include 

#define PIN_SAIDA_BUZZ 49

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// assign an IP address for the controller:
byte ip[] = { 
  192,169,1,20 };
byte gateway[] = {
  192,168,1,1}; 
byte subnet[] = { 
  255, 255, 255, 0 };

byte server[] = {  74, 86, 188 ,173 }; 

char serverName[] = "dns.servidor.api"; //trocar pelo DNS API Web
EthernetClient client;

char tagRFID[10];
boolean lastConnected = false;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int rele1 = 22;
char validacaoTag;
char nomeTag[20];
int indexretornoServer;
boolean inicioretornoServer;

int KEY1 = 26;
int KEY2 = 28;
int KEY3 = 30;
int KEY4 = 32;
int localKEY1 = 0;
int localKEY2 = 0;
int localKEY3 = 0;
int localKEY4 = 0;


void setup() {
  
  pinMode(rele1, OUTPUT);  
  digitalWrite(rele1, HIGH); 

  indexretornoServer = 0;
  inicioretornoServer = false;
  
  lcd.begin(20, 4);
  lcd.print("Me Encontre         ");
  lcd.setCursor(0, 1);
  lcd.print("                    ");
  lcd.setCursor(0, 2);
  lcd.print("Iniciando Sistema   ");
  
  Serial.begin(9600);
  delay(1000);
  Serial.println("connecting...");
  
   if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    while(true);
  }
  
  aguardandocomandos();    
  
}


void loop()
{    
  verificacartao();  
  lastConnected = client.connected();   
}

void verificacartao(){
  
  byte i = 0;
  byte val = 0;
  byte code[6];
  byte checksum = 0;
  byte bytesread = 0;
  byte tempbyte = 0;
   
  if(Serial.available() > 0) {      
    if((val = Serial.read()) == 2) { 
      bytesread = 0; 
      while (bytesread < 12) {     
        if( Serial.available() > 0) { 
          
          lcd.setCursor(0, 1);
          lcd.print("                   ");
          lcd.setCursor(0, 2);
          lcd.print("Buscando Dados     ");
          lcd.setCursor(0, 3);
          lcd.print("                   ");
            
          val = Serial.read();          
          if (bytesread < 10)
          {
            tagRFID[bytesread] = val;
          }
                    
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) { 
            break;   
          }
   
          if ((val >= '0') && (val <= '9')) {
            val = val - '0';
          } else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }
          
          if (bytesread & 1 == 1) {
            code[bytesread >> 1] = (val | (tempbyte << 4));
            if (bytesread >> 1 != 5) {               
              checksum ^= code[bytesread >> 1];      
            };
          } else {
            tempbyte = val;                          
          };

          bytesread++;                               
        } 
      } 

      if (bytesread == 12) {
        tagRFID[10] = '\0';
        validaAcesso();
      }            
      bytesread = 0;
    }
  }

  
}

void validaAcesso() 
{
  Serial.println(tagRFID);
  if (client.connect(serverName, 80)) {
    Serial.println("connected");
    client.print("GET /api/acesso/INNER/0001/"); //INNER é o codigo do cliente e 0001 o código do Equipamento
    client.print(tagRFID); 
    client.println(" HTTP/1.0");
    client.println("Host: dns.servidor.api"); //trocar pelo DNS API Web
    client.println(); 
  } 
  else {
    Serial.println("connection failed");
    Serial.println();
    lcd.setCursor(0, 1);

    lcd.print("Erro durante acesso ");
    lcd.setCursor(0, 2);
    lcd.print("Tente novamente     ");

  }

  inicioretornoServer = false;
  indexretornoServer = 0;
  
  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read(); //gets byte from ethernet buffer
    Serial.print(c);
    if (c == '|')
    {
      inicioretornoServer = !inicioretornoServer;
      indexretornoServer = 0;
    }
    
    if (inicioretornoServer)
    {    
      //Serial.println(indexretornoServer);          
      //Serial.println(c); 
      if(indexretornoServer == 1)
      {
            validacaoTag = c;            
      }
      else if(indexretornoServer >= 2 && indexretornoServer <= 22)      
      {
          nomeTag[indexretornoServer-2] = c;            
      }      
      indexretornoServer++;
      //Serial.println(indexretornoServer);          
    }  
  }

  Serial.println(" ");    
  Serial.print("Validacao: ");    
  Serial.print(validacaoTag);    
  Serial.println(" ");    
  Serial.print("Nome: ");    
  Serial.print(nomeTag);    
  
  lcd.setCursor(0, 1);
  lcd.print("                    ");
  lcd.setCursor(0, 2);
  lcd.print(nomeTag);
  lcd.setCursor(0, 3);

  if(validacaoTag == 'E'){
    digitalWrite(rele1, LOW);
    lcd.print("Entrada Registrada  ");}    
    
  if(validacaoTag == 'S'){
    digitalWrite(rele1, LOW);    
    lcd.print("Saida Registrada    ");}

   if(validacaoTag == 'X'){
    lcd.print("Cartao sem Acesso   ");}   

  Serial.println();
  Serial.println("disconnecting.");
  Serial.println("==================");
  Serial.println();


  delay(1000);  
  digitalWrite(rele1, HIGH);
  delay(500);  
  client.stop(); //stop client
  aguardandocomandos();  
}


void consultacartaoserver(){
   
  lcd.setCursor(0, 1);
  lcd.print("Consultando dados   ");   
  lcd.setCursor(0, 2);
  lcd.print("      Aguarde       ");   
    
  Serial.print("Cartao: ");
  Serial.println(tagRFID); 
  
  
  int thisData;
  thisData = 12234;


  
}

void aguardandocomandos(){
  lcd.setCursor(0, 1);
  lcd.print("                    ");
  lcd.setCursor(0, 2);
  lcd.print("Passe o Cartao      ");   
  lcd.setCursor(0, 3);
  lcd.print("                    ");


}


Fluxo de Operação

Código Fonte
O código fonte da API  e site de administração e localização está disponível no github.


Tagged

24 comentários :

  1. Boa noite Sergio, gostei muito do seu projeto e meu TCC eh muito parecido.
    A diferença eh que tenho que abrir um portão automatico e verificar no site o fluxo dos tags rfid.
    terias como me ajudar?

    ResponderExcluir
    Respostas
    1. O projeto já está preparado para integração com um portão automático, quando um cartão é autorizado, o circuito aciona o relé por um tempo programado. O site, infelizmente eu não posso disponibilizar o código fonte.

      Excluir
  2. Boa tarde Sérgio, no caso do site, vc quer quanto para disponibilizar o código?
    O meu TCC não tem nenhum foco na criação do site.
    Com certeza irei modificar muita coisa.
    O seu site tem acesso a qual banco de dados?

    ResponderExcluir
    Respostas
    1. Boa Tarde!

      O site é educacional, não comercializo código fonte de projetos.

      Desculpe.


      Excluir
    2. Boa noite Sérgio,

      Consegui fazer um sistema parecido, porém fiz com apenas duas tags.
      Queria colocar mais 4 tags, mas da seguinte forma:
      3 tags para identificar carros e as outras 3 tags identifica pessoas.
      O sistema só aceita a liberação do acesso, após 2 tags (distintas: carro e pessoa) forem válidos.
      o trecho do código segue abaixo, mas esse código não está dando certo. Tem como vc dar uma olhada e ver no que pode ajudar?
      ///////////////////////////////////
      //Verifica todos os tags
      ///////////////////////////////////

      if(strlen(tag) == 0) return; //se vazio, não verifica

      if(compareTag(tag, tag_carro))
      { // se é carro
      Serial.println("TAG 1");
      LCD.setCursor(0,1);
      LCD.print(" OCS 4616 ");
      carro_ok = 1;

      }else if(compareTag(tag, tag_pessoa))
      //se é pessoa
      Serial.println("TAG 2");
      LCD.setCursor(0,1);
      LCD.print(" Igor ");
      pessoa_ok = 1;

      if(compareTag(tag, tag_carro1))
      { // se é carro
      Serial.println("TAG 3");
      LCD.setCursor(0,1);
      LCD.print(" OSP 5408 ");
      carro_ok = 1;

      }else if(compareTag(tag, tag_pessoa1))
      { //se é pessoa
      Serial.println("TAG 4");
      LCD.setCursor(0,1);
      LCD.print(" Marcio ");
      pessoa_ok = 1;
      }
      else
      {// senão é nenhum dos dois escreve na serial
      Serial.println("Tag Inválido!");
      LCD.setCursor(0,1);
      LCD.print(" Tag Inválido ");
      carro_ok = 2;
      pessoa_ok = 2;
      }
      }

      Excluir
  3. Olá Sergio acho muito legal seu projeto assim como sua iniciativa e tudo mais.

    Comecei com Arduino a pouco tempo entretanto já programo a mais. Em um dos projetos que tive realizando com Arduino me deparei com a dificuldade em estar enviando varias variáveis ao Arduino ao mesmo tempo e o mesmo identificar o que é cada variável, seja via PHP ou C#.

    Pesquisei bastante na internet e esse projeto foi o que achei de mais próximo pois pelo que imagino na validação de acesso você precisa em algum momento retornar para o Arduino os dados e informações.

    Um exemplo que posso lhe dar é o controle de um LED RGB via PHP, aonde eu envio o código das cores obtidos para Arduino, no caso cada cor possui um código diferente, mas o Arduino não sabe diferenciar qual código é de cada cor. Outro exemplo é o de enviar dados de 3 sensores simultaneamente e saber de qual sensor no Arduino e cada dado enviado.

    Não sei se ficou claro mas ficarei grato se puder ajudar.

    Obrigado.

    ResponderExcluir
    Respostas
    1. Hércules, não ficou muito claro.
      Mas pelo que entendi, sua dificuldade é receber variaveis no arduino?
      Voce pode configurar como WebClient ou WebServer, precisa identificar qual implementação atende seu projeto.
      No meu caso, está implmentando como WebClient. Consumo uma WEBAPI Rest escrita em .NET (poderia sem em PHP, Java, etc) e essa API recebe o numero do cartao, valida e devolve um status.
      A partir da linha while(client.connected() && !client.available()) delay(1); //waits for data
      eu faço o tratamento e atualizo a variavel validacaoTag com o retorno.

      Excluir
    2. Sergio obrigado pela atenção.
      Pois então a dificuldade se encontra justamente em receber varias variáveis simultaneamente no Arduino já que não existe uma forma de eu identificar qual é cada variavel que eu enviei para o arduino sendo assim uma dificuldade no tratamento delas no arduino.

      Excluir
    3. Hercules,

      Nesse projeto eu recebo 2 variáveis, o status da validação e nome do Usuário, voce pode adaptar para enviar e receber mais variáveis.

      Response:
      |STATUS NOMEUSUARIO|
      |: Caracter que identifica o início do retorno de validação do acesso
      STATUS: Status da validação do acesso
      NOMEUSUARIO: Nome do Usuário
      |:Caracter que identifica o término do retorno de validação do acesso

      Excluir
  4. Bom dia Sergio. Estou desenvolvendo um sistema de controle para alunos e professores de uma escola municipal de música de minha cidade. Gostaria, se possível, da sua indicação do material para estudo. Se puder indicar eu agradeço.

    ResponderExcluir
  5. É no método valida acesso que enviar o ID para o web server ?Como faço para enviar para uma pagina php/jsp para capturar o valor da ID ?Ótimo tutorial.

    ResponderExcluir
    Respostas
    1. Fala Wilton, Boa Noite!
      No projeto eu precisava armazenar o histórico de acessos, a API apenas inseria um registro de localização e data do usuário no banco de dados e a página mostrava a última localização.

      Excluir
  6. Onde encontro esta API, seria possível compartilhar ?
    Obrigado.

    ResponderExcluir
    Respostas
    1. Boa tarde! A API e gerenciador foram desenvolvidos em .NET. Liberei o código fonte no github, o link foi disponibilizado no fim do artigo.

      Excluir
  7. Bom dia meu caro!
    Pelo que entendi o sistema depende da comunicação em rede para funcionar. Caso a rede pare ou a internet pare de funcionar, o que ocorreria na porta? Ninguém conseguiria acessar a porta e a mesma ficaria fechada (ou o inverso)?
    Abraço

    ResponderExcluir
  8. bom trabalho pessoal, estou com projeto parecido de controle de acesso ao terminal via senha e digitar endereços,( pontos de envio de mercadoria), para um sistema, cada ponto tem sua IHm SIMILAR.Esses terminais tem dez I/O, e se conectam em rede a um CLP central.Gostaria de usar um processador ARM TM4C-12XX que tem facilidades para redes Canopen e Ethernet sem shields.
    Alguem teria interesse de me ajudar?

    ResponderExcluir
  9. Opa gostaria de saber se este projeto está atualizado ou se tem outro? A fonte de 12 3A eu posso trocar por uma de 12V 5A ?

    ResponderExcluir
  10. Sergio existe a possibilidade de fazer isso com uma shield com gprs? qual a função que eu chamaria o fluxo web pelo arduino?

    ResponderExcluir
  11. Boa noite Sergio!
    Estou desenvolvendo um sistema muito semelhante ao seu, para realizar o controle de acesso de alguns laboratórios, utilizando como site de gerenciamento o GLPI!
    Estou enviando a tagRFID, em formato Json, para uma API que futuramente irá realizar as consultas no banco do GLPI!
    Contudo estou tentando retornar de minha API para o meu Arduíno, somente TRUE ou FALSE, estou tendo dificuldades com este retorno, não entendo se meu erro se encontra na API ou em meu código do Arduíno!
    Deixo meu código do Arduíno e da API abaixo!
    Desde já agradeço pelo seu auxilo se possível!
    Dividi meu código Arduíno por arquivos, é a maneira que consigo estruturar meu pensamento!

    ResponderExcluir
  12. Arquivo sketchAPI-GLPI
    #include
    #include
    /* Typical pin layout used:
    -------------------------------------------------
    MFRC522 Arduino Arduino
    Reader/PCD Uno/101 Mega
    Signal Pin Pin Pin
    -------------------------------------------------
    RST/Reset RST 9 5 || 8 using Ethernet Shield - WHITE
    SPI SS SDA(SS) 10 53 - BLUE
    SPI MOSI MOSI 11 / ICSP-4 51 - YELLOW
    SPI MISO MISO 12 / ICSP-1 50 - GREY
    SPI SCK SCK 13 / ICSP-3 52 - GREEN
    */
    #include
    #include
    #include
    #include
    #include
    //MFRC522 PINs
    #define SS_PIN 53
    #define RST_PIN 8
    //Configuração de Rede
    byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    IPAddress serverIP(192, 168, 1, 2); // IP of the MySQL *server* here
    IPAddress ip(192, 168, 1, 111); // IP Arduino Device
    EthernetClient client;
    int porta = 80;
    //Instacia do MFRC522
    MFRC522 mfrc522(SS_PIN, RST_PIN);
    void setup() {
    Ethernet.begin(mac_addr, ip);
    Serial.begin(9600);
    //Start SPI
    SPI.begin();
    //Start MFRC522
    mfrc522.PCD_Init();
    //Pino LED Vermelho - ACESSO NEGADO
    pinMode(5, OUTPUT);
    //Pino LED Verde - ACESSO CONCEDIDO
    pinMode(6, OUTPUT);
    //Pin RELAY
    pinMode(7, OUTPUT);
    //Chamada da menssagem solicitando o cartão
    showMessage();
    }
    void loop() {
    reader();
    delay(100000);
    }
    Arquivo helper
    void showMessage() {
    Serial.print("Passe seu cartão sobre o leitor");
    Serial.println();
    }
    Arquivo - reader
    void reader() {
    if (! mfrc522.PICC_IsNewCardPresent()) {
    return;
    }
    if (! mfrc522.PICC_ReadCardSerial()) {
    return;
    }

    // Serial.print("UID da tag: ");
    String tagContent = "";
    char tagContentChar[64];

    for (byte i = 0; i < mfrc522.uid.size; i++) {
    tagContent.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    tagContent.concat(String(mfrc522.uid.uidByte[i], HEX));
    }
    tagContent.replace(" ", "");
    tagContent.toUpperCase();
    //Serial.print(tagContent);
    //Serial.println();

    tagContent.toCharArray(tagContentChar, 64);
    //
    // Serial.print(tagContentChar);
    // Serial.println();
    api(tagContent);
    }

    Arquivo api
    void api(String tagContent) {
    Serial.print("\n");
    Serial.print("Conectando...\n");
    if (client.connect(serverIP, porta)) {
    Serial.print("Conectado\n");
    StaticJsonDocument<200> doc;
    doc["tag"] = tagContent;
    serializeJson(doc, Serial);
    // Envia através de POST pelo caminho "POST /api/api.php/data HTTP/1.1"
    client.println("POST /api/api.php/data HTTP/1.1");
    // Envia os cabeçalhos HTTP
    client.println("Host: 192.168.1.2");
    client.println("Connection: close");
    client.print("Content-Length: ");
    client.println(measureJson(doc));
    client.println("Content-Type: application/json");
    client.println();
    serializeJson(doc, client);
    if (client.available()) {
    char c = client.read();
    Serial.print(c);
    }
    } else {
    Serial.print("Error, Data Base Not Connection!");
    }
    }
    Código da API que se encontra no servidor Web!
    ";
    echo "Pagina Recebe
    ";
    echo "============
    ";

    $json = file_get_contents('php://input');
    $resultado = json_decode($json, true);
    $encoda = json_encode($resultado);
    var_dump($resultado);
    echo "= = = = =
    ";
    echo $encoda;
    function valida_licenca($encoda){
    if($encoda == '{"tag":"8542B7C3"}'){
    return 'true';
    }else{
    return 'false';
    }
    }

    ResponderExcluir
  13. Fala Sergio
    Sou o Rafael quem trabalhou com vc na 7com
    Passa um contato

    ResponderExcluir
  14. It’s fully licensed and runs reliable buyer help through stay chat and e mail that you could contact any time you face a 파라오카지노 도메인 problem. Needless to say, Slots.LV is house to over 30 jackpot slots that pay out big prizes to lucky winners. Slots.lV accepts credit card payments if you ever determine to play for real cash as a substitute of free.

    ResponderExcluir