Comunicação Arduino-Raspberry Pi usando i²C - Parte I
Comecei a me interessar por automação "pelas mãos" do Arduino. De fato, me re-interessei, porque apesar de estar afastado da área de automação e robótica já há anos, eu sempre tive curiosidade sobre a área, e trabalhando com TI nunca estive realmente longe.
Depois veio o Raspberry Pi, que com sua capacidade de memória e interfaces incomparavelmente maiores em relação à plaquinha italiana me permitiram fazer projetos de certa forma mais complexos, envolvendo processamento de imagem, interface gráfica etc.
Acontece que o Arduino bate sem dó no Pi em um aspecto: aplicações de tempo real. Por aplicações de tempo real entenda-se programas que tenham que dar respostas muito rápidas (estou falando de milionésimos de segundo). Nesse caso o Pi "faia", porque como ele tem um sistema operacional, ele tem que dividir a sua capacidade de processamento entre várias tarefas simultãneas, ou seja: ele cuida do vídeo um bocadim, aí atende ao mouse do usuário, em seguida dá atenção à parte de segurança, depois volta ao vídeo etc. Se ao mesmo tempo em que ele tem que desemprenhar essas tarefas ele tem que cuidar de alguma coisa que exija uma atençao a intervalos de tempo muito precisos, a coisa "mela".
Vou dar um exemplo prático: suponhamos que vc desenvolva um website e hospede-o no seu Raspberry. Isso é molezinha, o bicho roda até Apache, dentre outros webservers. Mas vamos supor que vc queira que o usuário comande um servo motor a partir dess seu site (vocês verão como isso é possível nos próximos posts, aguardem). Nesse caso... ferrou. Um servo comum funciona da seguinte forma: se vc enviar pulsos para ele cuja largura (tempo em que o sinal fica "alto", ou seja, em um vamor positivo maior que uns 3V) seja de 1 ms (milissegundo), o servo vai para a posição 0°. Se vc passa o sinal para 1,5ms de largura, o servo movimenta-se até a posição 90°, permanencendo lá enquanto o pulso seguir mais ou menos o mesmo padrão. Se vc passa a largura do pulso para 2ms, ele vai para 180°.
Ou seja, a variação máxima é da ordem de 1000 microssegundos. No Pi, ainda mais rodando como webserver, "no way".
Solução
E se ficássemos com os dois? Quer dizer, usássemos o Pi para hospedar o nosso site e, uma vez que tenha recebido comandos enviados pelo usuário através do site, ele entra em contato com o Arduino e diz a ele como posicionar o servo? Uma vez o servo em posição, basta ao Arduino informar que fez a tarefa e o Pi segue com a vida.
Bom, a ideia é boa, mas como fazer com que os dois "conversem"? Aí entra o protocolo I²C.
Em primeiro lugar "protocolo" é algo como um idioma, no sentido de uma "coisa" através da qual existe a comunicação, no caso a comunicação entre máquinas. Um desses protocolos é o I²C, que é largamente usado em automação, principalmente por ser muito simples e permitir a comunicação entre, em tese, milhares de equipamentos com apenas um par de fios, com uma velocidade mais que suficiente para a maioria dos nossos projetos de automação, mesmo os mais sofisticados. Mais sobre o assunto aqui.
Como implementar isso para a comunicação entre Arduino e RPi? Bom, vejamos com um exemplo prático. A ideia é enviar um número fornecido pelo usuário no Raspberry ao Arduino e o Arduino responder com esse número ao quadrado. Apesar da simplicidade nauseabunda, os conceitos estarão inteiramente explicados nessa aplicação, e outros exercícios virão em futuros posts.
Lado Arduino - Slave
Aqui a coisa é bem simples. Vc deve usar a biblioteca Wire, que já vem com o Arduino, e o "pograminha" fica assim:
O programa realmente é simples, o que talvez exista aí de diferentes são as callbacks.
Uma função callback é uma função definida para ser chamada por "alguém" que não seja a gente, ou seja, o programador. Perguntaria vc: "Como assim cê fala, tio???". Respondo eu: veja o exemplo acima. Nessa caso, as funções receiveData() e sendData() são chamadas não pelo nosso programa, mas pela biblioteca Wire respectivamente quando dados são enviados pelo master (app Raspberry) ou são solicitados por ele. Sacaste? Isso dá ao Arduino o papel um pouco politicamente incorreto de slave, ou seja, quem decide quando enviar os dados ou quando recevber alguma resposta é o master, no caso o RPi.
Lado RPi - Master
Preparar o Pi para seu papel é um pouquinho mais enrolado, mas um pouquinho só mesmo.
Primeiramente temos que tirar a comunicação I²C da "blacklist", que é uma lista de protocolos bloqueados no ambiente Linux. Para isso, altere o arquivo raspi-blacklist.conf:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
"Comente" a linha referente ao protocolo I²C no arquivo, colocando um # na primeira coluna. Isso irá "desativar a desativação" do protocolo, ou seja, torná-lo ativo. A linha deve ficar assim:
Em seguida, adicione a linha a seguir ao arquivo /etc/modules
Agora, é tempo de instalar as bibliotecas necessárias para o uso do I²C no RPi:
Habilitando o I²C, usuário pi:
Agora, reinicie o seu Raspberry:
Depois do reboot, se vc der o comando:
... deverá ver as portas abertas pelo I²C no Pi. Se a sua placa for a primeira revisão, vc verá algo como:
/dev/i2c-0
Outro teste poderá ser feito se vc rodar:
Nesse caso, a saída será algo como:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Se houvesse algum device I²C conectado, veríamos o endereço dele ocupado acima. Vamos ver isso daqui a pouco.
"And last but not least..." vamos instalar a lib do Python para uso do protocolo:
Depois das configurações e downloads, devemos rodar o programa Python que conversa com aquele do Arduino lá de cima. Eis o bicho:
Comparando os dois programas, vc pode ver que a variável address tem o mesmo valor no Arduino e no RPi, indicando que eles vão se comunicar usando esse endereço.
Em seguida o sistema fica num loop eterno (while True:), onde ele vai ler um valor fornecido pelo usuário para em seguida coletar e exibir o valor respondido pelo Arduino.
Conecatando eletricamente Arduino & Pi
Bom, essa... fica prá amanhã.
Abracadabraço,
Mauro
Depois veio o Raspberry Pi, que com sua capacidade de memória e interfaces incomparavelmente maiores em relação à plaquinha italiana me permitiram fazer projetos de certa forma mais complexos, envolvendo processamento de imagem, interface gráfica etc.
Acontece que o Arduino bate sem dó no Pi em um aspecto: aplicações de tempo real. Por aplicações de tempo real entenda-se programas que tenham que dar respostas muito rápidas (estou falando de milionésimos de segundo). Nesse caso o Pi "faia", porque como ele tem um sistema operacional, ele tem que dividir a sua capacidade de processamento entre várias tarefas simultãneas, ou seja: ele cuida do vídeo um bocadim, aí atende ao mouse do usuário, em seguida dá atenção à parte de segurança, depois volta ao vídeo etc. Se ao mesmo tempo em que ele tem que desemprenhar essas tarefas ele tem que cuidar de alguma coisa que exija uma atençao a intervalos de tempo muito precisos, a coisa "mela".
Vou dar um exemplo prático: suponhamos que vc desenvolva um website e hospede-o no seu Raspberry. Isso é molezinha, o bicho roda até Apache, dentre outros webservers. Mas vamos supor que vc queira que o usuário comande um servo motor a partir dess seu site (vocês verão como isso é possível nos próximos posts, aguardem). Nesse caso... ferrou. Um servo comum funciona da seguinte forma: se vc enviar pulsos para ele cuja largura (tempo em que o sinal fica "alto", ou seja, em um vamor positivo maior que uns 3V) seja de 1 ms (milissegundo), o servo vai para a posição 0°. Se vc passa o sinal para 1,5ms de largura, o servo movimenta-se até a posição 90°, permanencendo lá enquanto o pulso seguir mais ou menos o mesmo padrão. Se vc passa a largura do pulso para 2ms, ele vai para 180°.
Ou seja, a variação máxima é da ordem de 1000 microssegundos. No Pi, ainda mais rodando como webserver, "no way".
Solução
E se ficássemos com os dois? Quer dizer, usássemos o Pi para hospedar o nosso site e, uma vez que tenha recebido comandos enviados pelo usuário através do site, ele entra em contato com o Arduino e diz a ele como posicionar o servo? Uma vez o servo em posição, basta ao Arduino informar que fez a tarefa e o Pi segue com a vida.
Bom, a ideia é boa, mas como fazer com que os dois "conversem"? Aí entra o protocolo I²C.
Em primeiro lugar "protocolo" é algo como um idioma, no sentido de uma "coisa" através da qual existe a comunicação, no caso a comunicação entre máquinas. Um desses protocolos é o I²C, que é largamente usado em automação, principalmente por ser muito simples e permitir a comunicação entre, em tese, milhares de equipamentos com apenas um par de fios, com uma velocidade mais que suficiente para a maioria dos nossos projetos de automação, mesmo os mais sofisticados. Mais sobre o assunto aqui.
Como implementar isso para a comunicação entre Arduino e RPi? Bom, vejamos com um exemplo prático. A ideia é enviar um número fornecido pelo usuário no Raspberry ao Arduino e o Arduino responder com esse número ao quadrado. Apesar da simplicidade nauseabunda, os conceitos estarão inteiramente explicados nessa aplicação, e outros exercícios virão em futuros posts.
Lado Arduino - Slave
Aqui a coisa é bem simples. Vc deve usar a biblioteca Wire, que já vem com o Arduino, e o "pograminha" fica assim:
// Add I²C lib #include <Wire.h> #define SLAVE_ADDRESS 0x04 int number = 0; void setup() { // initialize i2c as slave Wire.begin(SLAVE_ADDRESS); // define callbacks for i2c communication Wire.onReceive(receiveData); Wire.onRequest(sendData); } void loop() { delay(100); } // callback for received data void receiveData(int byteCount){ while(Wire.available()) { number = Wire.read(); } } // callback for sending data void sendData(){ Wire.write(number*2); }
O programa realmente é simples, o que talvez exista aí de diferentes são as callbacks.
Uma função callback é uma função definida para ser chamada por "alguém" que não seja a gente, ou seja, o programador. Perguntaria vc: "Como assim cê fala, tio???". Respondo eu: veja o exemplo acima. Nessa caso, as funções receiveData() e sendData() são chamadas não pelo nosso programa, mas pela biblioteca Wire respectivamente quando dados são enviados pelo master (app Raspberry) ou são solicitados por ele. Sacaste? Isso dá ao Arduino o papel um pouco politicamente incorreto de slave, ou seja, quem decide quando enviar os dados ou quando recevber alguma resposta é o master, no caso o RPi.
Lado RPi - Master
Preparar o Pi para seu papel é um pouquinho mais enrolado, mas um pouquinho só mesmo.
Primeiramente temos que tirar a comunicação I²C da "blacklist", que é uma lista de protocolos bloqueados no ambiente Linux. Para isso, altere o arquivo raspi-blacklist.conf:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
"Comente" a linha referente ao protocolo I²C no arquivo, colocando um # na primeira coluna. Isso irá "desativar a desativação" do protocolo, ou seja, torná-lo ativo. A linha deve ficar assim:
#blacklist i2c-bcm2708
Em seguida, adicione a linha a seguir ao arquivo /etc/modules
i2c-dev
Agora, é tempo de instalar as bibliotecas necessárias para o uso do I²C no RPi:
$ sudo apt-get install i2c-tools
Habilitando o I²C, usuário pi:
$ sudo adduser pi i2c
Agora, reinicie o seu Raspberry:
$ sudo reboot
ll /dev/i2c*
... deverá ver as portas abertas pelo I²C no Pi. Se a sua placa for a primeira revisão, vc verá algo como:
/dev/i2c-0
Outro teste poderá ser feito se vc rodar:
$ i2cdetect -y 1
Nesse caso, a saída será algo como:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Se houvesse algum device I²C conectado, veríamos o endereço dele ocupado acima. Vamos ver isso daqui a pouco.
"And last but not least..." vamos instalar a lib do Python para uso do protocolo:
sudo apt-get install python-smbus
Depois das configurações e downloads, devemos rodar o programa Python que conversa com aquele do Arduino lá de cima. Eis o bicho:
import smbus import time # for RPI version 1, use "bus = smbus.SMBus(0)" bus = smbus.SMBus(0) # This is the address we setup in the Arduino Program address = 0x04 def writeNumber(value): bus.write_byte(address, value) # bus.write_byte_data(address, 0, value) return -1 def readNumber(): number = bus.read_byte(address) # number = bus.read_byte_data(address, 1) return number while True: var = input("Enter a number: ") if not var: continue writeNumber(var) print "I just sent to Arduino: ", var # sleep one second time.sleep(1) number = readNumber() print "Arduino sent to me back: ", number print
Comparando os dois programas, vc pode ver que a variável address tem o mesmo valor no Arduino e no RPi, indicando que eles vão se comunicar usando esse endereço.
Em seguida o sistema fica num loop eterno (while True:), onde ele vai ler um valor fornecido pelo usuário para em seguida coletar e exibir o valor respondido pelo Arduino.
Conecatando eletricamente Arduino & Pi
Bom, essa... fica prá amanhã.
Abracadabraço,
Mauro
Como posso Ligar a Rpi com um Mega R3?
ResponderExcluirNo Mega os pinos i2c são os pinos 20 e 21, que correspondem respectivamente aos pinos 4 e 5.
ExcluirUma vez conectado o software é o mesmo.
UresiOper_ni Jason Bader Crack
ResponderExcluirculilahed
gulcumclivso-2000 George Strickler Kaspersky AntiVirus
ResponderExcluirclick
Axure RP Pro 9.0.0.3727
LDPlayer 9.0.19
ulpleasransre