Introdução
Identificação por radiofrequência, como podemos chamar o RFID, não é uma tecnologia recente e há especulações que já era utilizada na segunda guerra mundial. É a comunicação por sinal de rádio onde um dos dispositivos é energizado e fica ativo, e o outro lado, a TAG (chaveiro ou cartão RFID), não necessariamente é energizado. Quando aproximados, realizasse a captura da informação do TAG, tecnologia essa que deu o passo inicial para NFC (Near Field Communication).
Utilizando o computador de bolso mais popular, o Raspberry Pi, a linguagem de programação Python, que é o canivete suíço para prototipar ideias, e um módulo RFID comercial vamos ver como é simples, direto e didático fazer a comunicação via SPI com essa turma.
Não conhece muito bem o Raspberry Pi? Veja o artigo Raspberry Pi do Thiago Lima. E como vamos usar o Raspberry Pi B com Linux, para conhecer melhor essa dupla veja o artigo A Raspberry Pi e o Linux de Vinicius Maciel. Se isso não te assusta, continue lendo o artigo.
Módulo RFID
O Mifare MFRC522 (NXP RC522), ou comercialmente RFID-RC522, é um dos mais populares leitores RFID do mercado, no modo comprar, ligar e usar, uma excelente forma para prototipar.
O RFID-RC522 já vem pronto para ser utilizado, fazendo uso da comunicação SPI. Essa comunicação é nova pra você? Então recomendo o artigo Comunicação SPI do Francesco Sacco. Além disso o CI RC522 possui os recursos I2C e UART para comunicação e realiza comunicação RFID a 13.56 MHz.
Na figura 1 temos uma imagem do nosso módulo leitor RFID (RFID-RC522) e junto o que o acompanha na compra, um chaveiro e um cartão.
Figura 1 – Módulo RFID com cartão e chaveiro
Segue a relação dos pinos disponíveis para alimentação e comunicação na figura 2.
Figura 2 – Relação de pinos de alimentação e comunicação do módulo RFID
Esquema de ligação
Na sequência, na figura 3, o esquema de ligação do módulo RFC522 com o Raspberry Pi.
Figura 3 – Esquema de ligação do módulo RFID com o GPIO do Raspberry Pi B
Apenas alguns detalhes no esquema de ligação é a alimentação 3,3V utilizando o pino 1 do barra de pinos de GPIO, e a comunicação SPI, sendo o SDA no módulo RFID o sinal CS (Chip Select) ou SS (Slave Select), que depende da adoção do fabricante, sendo o correto uso do nome SDA para comunicação I2C.
Configuração do ambiente host
- Board: Raspberry Pi B;
- Distribuição: Raspbian – Debian Wheezy (2014-01-07);
- Kernel 3.12.22;
- Python 2.7.
Preparando o ambiente
Agora a parte legal, vamos preparar o Raspbian para liberar o uso device SPI no Linux, resolver as dependências de software e testar com uma aplicação padrão de teste. Para isso, o primeiro passo é verificar se o dispositivo SPI está liberado, ou melhor, se o módulo do kernel subiu para fornecer o acesso.
pi@raspberrypi ~ $ ls /dev/spi* ls: cannot access /dev/spi*: No such file or directory pi@raspberrypi ~ $ lsmod | grep spi_bcm* pi@raspberrypi ~ $ dmesg | grep spi pi@raspberrypi ~ $
Se na sua Raspberry Pi obteve as mesmas saídas acima, o módulo SPI está desabilitado. Caso contrário, pule a próxima etapa. No Raspbian isso quer dizer que ele está no black list do modprobe, e para habilitar o módulo SPI siga o passo a passo abaixo e reinicie a Raspberry Pi.
pi@raspberrypi ~ $ sudo vim /etc/modprobe.d/raspi-blacklist.conf # blacklist spi and i2c by default (manu users don't need them) #blacklist spi-bcm2708 blacklist i2c-bcm2708 :wq pi@raspberrypi ~ $ sudo reboot
Verificando novamente:
pi@raspberrypi ~ $ ls /dev/spi* /dev/spidev0.0 /dev/spidev0.1 pi@raspberrypi ~ $ lsmod | grep spi_bcm spi_bcm2708 4808 0 pi@raspberrypi ~ $ dmesg | grep spi [ 5.078766] bcm2708_spi bcm2708_spi.0: master in unqueued, this is deprecated [ 5.230200] bcm2708_spi bcm2708_spi.0: SPI Controller at 0x2020400 (irq 80) pi@raspberrypi ~ $
Para ler/escrever no barramento SPI precisamos de um módulo no Python. Um que possui rotinas e funções bem escritas é o SPI-Py do Louis Thiery. Vamos clonar o repositório do GitHub, compilar e instalar. Mas antes, é necessário confirmar se possui o python-dev. Você pode verificar com o comando abaixo:
pi@raspberrypi ~ $ dpkg –list | grep -E 'ii.*python.*dev' ii python-dbus-dev 1.1.1-1 all main loop integration development files ii python2.7-dev 2.7.3-6+deb7u2 armhf Headers files and static library for Python (v2.7)
No caso acima temos instalado. Caso não aparecesse python2.7-dev ou python-dev, poderia executar a sua instalação com o comando abaixo:
pi@raspberrypi ~ $ sudo apt-get update && sudo apt-get install python-dev -f
Agora vamos clonar o repositório do SPI-Py, acessar o diretório e instalar.
pi@raspberrypi ~ $ git clone https://github.com/lthiery/SPI-Py spi-py Cloning into 'spi-py'... remote: Counting objects: 64, done. remote: Total 64 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (64/64), done. pi@raspberrypi ~ $ pi@raspberrypi ~ $ cd spi-spy pi@raspberrypi ~/spi-py $ sudo python setup.py install running install running build running build_ext building 'spi' extension … running install_lib copying build/lib.linux-arm6l-2.7/spi.so → /usr/local/lib/python2.7/dist-packages running install egg_info Writing /usr/local/lib/python2.7/dist-packages/SPI_Py-1.0.egg-info pi@raspberrypi ~/spi-py $
O módulo para comunicação via SPI está pronto. Agora vamos baixar de outro repositório um código exemplo pronto para comunicar com RC522, que depende do módulo SPI-Py para funcionar, no caso é o MFRC522-python que, além do SPI-Py, utiliza também o RPi.GPIO.
pi@raspberrypi ~/spi-py $cd ~ pi@raspberrypi ~ $ mkdir -p python_rfid pi@raspberrypi ~ $ cd python_rfid pi@raspberrypi ~/python_rfid $ git clone https://github.com/mxgxw/MFRC522-python Cloning into 'MFRC522-python'... remote: Counting objects: 60, done. remote: Total 60 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (60/60), done. pi@raspberrypi ~/python_rfid $ cd MFRC522-python pi@raspberrypi ~/python_rfid/MFRC522-python $
Testando a aplicação RFID
Dos arquivos clonados do repositório e que estão no diretório MFRC522-python, o importante neste momento é saber que toda programação e tratamento do SPI com o RF522 está no arquivo MFRC522.py, e que no arquivo Read.py há um exemplo pronto para testar a comunicação e o Write.py é outro exemplo para gravação no RC522.
pi@raspberrypi ~/python_rfid/MFRC522-python $ sudo python Read.py Welcome to the MFRC522 data read example Press Ctrl+C to stop.
No momento que aproximo o cartão:
pi@raspberrypi ~/python_rfid/MFRC522-python $ sudo python Read.py Welcome to the MFRC522 data read example Press Ctrl+C to stop. Card detected Card read UID: 227, 41, 93, 116 Size: 8 Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ^Cctrl+C captured, ending read.
Agora, vamos utilizar o módulo MFRC522.py e criar uma aplicação nossa baseada no Read.py. Primeiro vou abrir o código do Read.py e comentá-lo, logo em seguida irei escrever nossa aplicação (veja os comentários para mais detalhes).
#!/usr/bin/env python
# -*- coding: utf8 -*-
import RPi.GPIO as GPIO
import MFRC522
import signal
continue_reading = True
"""
Função que é chamada assim que Ctrl+C é pressionado
"""
# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
global continue_reading
print "Ctrl+C captured, ending read."
continue_reading = False
GPIO.cleanup()
"""
Responsável por capturar o SIGINT gerado (Ctrl+C) e chamar a função end_read
"""
# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)
"""
Criando um objecto da class MFRC522
"""
# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()
# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."
"""
Entra em um loop infinito baseado na variavel global 🙁 continue_reading, que ira mudar o seu valor assim que
a aplicação for interrompida e a função end_read() irá setar como False
"""
# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
"""
Maioria das chamadas abaixo falam por si só, irei comentar as que achar interessante
"""
# Scan for cards
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# If a card is found
if status == MIFAREReader.MI_OK:
print "Card detected"
"""
Agora iremos receber o ID RFID e o status, e o nome Anticoll é baseado no proprio protocolo
no Registrador ErrorReg bit3 verifica se houve colisão dos dados
"""
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
"""
Uma camada de segurança a mais, onde além de verificar o ID que recebemos podemos enviar a key dos chaveiros e tags
e aguardar a autenticação
Veja no datasheet MF1S70yyX.pdf Pagina: 11 - 8.6.3 Sector trailer
E as rotinas para esta checagem segue abaixo.
Usando a key abaixo é a chave de 6 bytes utilizada para
autenticar a comunicação maneira esta usando o MFAuthent
endereço 0x60 a 0x61
OBS: Não irei utilizar isso em nossa aplicação!
"""
# This is the default key for authentication
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
# Select the scanned tag
MIFAREReader.MFRC522_SelectTag(uid)
"""
Aqui é enviado a key do "fabricante", modo de autenticação 0x60 ou 0x61, Block Address e nosso uid
"""
# Authenticate
status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
# Check if authenticated
if status == MIFAREReader.MI_OK:
MIFAREReader.MFRC522_Read(8)
MIFAREReader.MFRC522_StopCrypto1()
else:
print "Authentication error"
O código foi exposto e adicionei alguns comentários para facilitar. As informações detalhadas sobre o protocolo e o modo de autenticação pode ser abstraído no datasheet do cartão RFID. No meu caso o cartão é um MIFARE Classic 4k e do código do MFRC522.py.
Agora vamos à nossa aplicação rfid_embarcados.py, onde utilizaremos a estrutura pronta do Read.py, removendo a parte de autenticação.
#!/usr/bin/env python
# -*- coding: utf8 -*-
import os
import sys
import signal
"""
Lista com relação dos IDs autorizados
"""
acessos_autorizados = [[227,41,93,116,227], [201,39,92,115,201], [225,95,12,103,225]]
"""
Vou tentar importar os modulos abaixo, caso algum problema ocorra,
sera lançada a exceção na sequencia
"""
try:
import MFRC522
import RPi.GPIO as GPIO
except ImportError as ie:
print("Problema ao importar modulo {0}").format(ie)
sys.exit()
"""
Funcao que irá garantir que o root ou usuario com permissão de
super-usuario irá executar a aplicação
"""
def check_user():
if os.geteuid() != 0:
print("Você deve executar o programa como super-usuario!")
#print "Exemplo:\nsudo python {0}".format(os.path.realpath(__file__))
print("Exemplo:\nsudo python {0}").format(__file__)
sys.exit()
"""
Captura o sinal gerado, no caso o que nos interessa é o sinal
SIGINT(Interrupção do Terminal ou processo) e irá encerrar a aplicação
"""
def finalizar_app(signal,frame):
global continue_reading
print("\nCtrl+C pressionado, encerrando aplicação...")
continue_reading = False
GPIO.cleanup()
continue_reading = True
def main():
check_user()
# Handler do sinal SIGINT
signal.signal(signal.SIGINT, finalizar_app)
# Cria o objeto da class MFRC522
MIFAREReader = MFRC522.MFRC522()
print("Portal Embarcados - Python é sucesso!")
print("Pressione Ctrl-C para encerrar a aplicação.")
while continue_reading:
# Scan for cards
#(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
if uid in acessos_autorizados:
print("Acesso liberado!")
else:
print("Sem acesso!")
if __name__ == "__main__":
main()
No caso, para um controle simples, criei uma lista chamada acessos_autorizados=[] que contem listas de ID’s RFID. Na linha 73 verifico se o uid recebido está contido ou não da minha lista. Em caso positivo, irá imprimir “Acesso Liberado!”, caso contrário, “Sem Acesso!”. Agora vamos ver nossa aplicação em funcionamento.
pi@raspberrypi ~/rfid-python $ sudo python rfid_embarcados.py Portal Embarcados - Python é sucesso! Pressione Ctrl-C para encerrar a aplicação. Acesso liberado! Acesso liberado! Acesso liberado! Sem acesso! Acesso liberado! ^C Ctrl+C pressionado, encerrando aplicação...
A aplicação funcionou como previsto, porém, algumas implementações novas surgiram na aplicação como a função check_user() e um except ImportError. Nesses casos, estou garantindo que a aplicação só deve continuar se estiver sendo executada com permissão de super-usuário e é obrigatório ter MFRC522 e RPi.GPIO para prosseguir. Agora vamos ver o que ocorre se executar a aplicação como usuário comum e logo em seguida, executar se não tivermos o MFRC522.py.
pi@raspberrypi ~/rfid-python $ python rfid_embarcados.py Você deve executar o programa como super-usuario! Exemplo: sudo python rfid_embarcados.py pi@raspberrypi ~/rfid-python $ pi@raspberrypi ~/rfid-python $ sudo python rfid_embarcados.py Problema ao importar modulo No module named MFRC522 pi@raspberrypi ~/rfid-python $
Para melhorar essa aplicação, poderia utilizar um banco de dados que contém os IDs com alguns nomes e informações, realizar consultas e, em caso de sucesso, poderia acionar algum GPIO e abrir uma porta ou liberar algo.
Implemente, invente e faça seus testes e qualquer dúvida envie pelos comentários.
Conclusão
Vimos como é fácil realizar a configuração do módulo ao Raspberry Pi B, como é prático preparar o Linux com Python e realizar os testes, e como é simples utilizar o módulo que baixamos para criar uma aplicação própria para ler os dados RFID. E utilizando um arquivo exemplo mais os recursos do python conseguimos criar uma aplicação simples e com recursos interessantes, como por exemplo verificar se é o root que está executando e se o módulo existe.
Referências
https://www.nxp.com/documents/data_sheet/MFRC522.pdf
https://github.com/lthiery/SPI-Py
https://github.com/mxgxw/MFRC522-python
https://pypi.python.org/pypi/RPi.GPIO
https://www.nxp.com/documents/data_sheet/MF1S70YYX.pdf






