Manual
do
Maker
.
com
Controle remoto por infravermelho com Arduino; claro, para nós nerds declarados, nada mais é que um meio de comunicação sem fio evoluído do código morse, mas para o usuário é como se para aumentar o som da TV o controle enviasse um sinal "aumente o volume" ao aparelho. Então, se você não pretende acompanhar toda a viagem até chegar no sumo desse post, você pode pular diretamente para a parte de código e procurar a prova de conceito mais ao final do video. Mas recomendo o video, além de que sua opinião a respeito é muito importante.
Para você, usuário comum de controle remoto, não se assuste com nenhum termo inicial. Aliás, ignore se não entender, porque o vídeo tem o propósito de subtrair de sua mente toda e qualquer dúvida relacionada ao dispositivo em questão (quer será o controle remoto de meu blue-ray player para efeito de testes, mas poderia ser um ar condicionado, uma TV, etc).
Para iniciar essa deliciosa aventura ao mundo dos bits (porque essa será uma comunicação de bits), precisaremos dividir o trabalho em duas partes.
Mapear o controle remoto para poder usar infravermelho com Arduino deve ser a primeira etapa porque você não sabe realmente o que sua TV (ou rádio, ar condicionado, ou seja lá qual for o equipamento) recebe no primir de uma tecla. Então nesse primeiro momento o projeto focará em receber comandos do controle que você já tem. Poderiamos chamar esse código de "projeto Kakashi", mas não são todos que gostam de Naruto, então vamos pular a parte do nome nerd.
Após ter feito a aquisição dos comandos, será necessário desenvolver a segunda parte do código, que terá a função de enviar comandos selecionados pelo usuário. Nessa etapa será utilizada apenas a comunicação via monitor serial.
Dito isso, agora podemos entender (ou refletir, para os que já sabem) sobre como funciona um controle remoto de TV, ou mais precisamente, como é feita uma comunicação por infrared, ou em português, "infra-vermelho", explicado em detalhes no bloco a seguir.
A comunicação IR, infrared ou infra-vermelho tem esse nome porque é uma comunicação por sinal de luz um pouco abaixo do espectro visível, após o vermelho; isto é, ondas de comprimento de 1 milímetro até 700 nanômetros.
Quando falamos de comunicação por infrared podemos relacioná-la diretamente ao sinal de fumaça nos primórdios da humanidade, à luz de lampiões utilizados na guerra que levou à independência das Treze Colônias, proclamada em 4 de Julho de 1776, ou a meios mais modernos de comunicação binária como o telégrafo em 1830, através de código morse. Aliás, como era compreendido o sinal enviado pelo telegrafo? - A resposta é simples, e a mesma utilizada nos atuais controles-remoto das modernas TVs, seja tubo, plasma, LCD, LED, OLED ou outra:
Um protocolo é um conjunto de regras convencionadas entre as partes envolvidas, ou seja, é como falar um idioma; falamos português portanto, é necessário que você compreenda suficientemente bem as regras gramaticais, signos e todos os demais adereços que compõe nossa linguagem. E assim o é para todo o meio de comunicação digital; cada tecnologia se comunica por meio de seus protocolos.
Quando você aperta a tecla "4" do controle remoto, a regra relacionada a esse botão executa uma sequência de pulsos elétricos que são recebidos pela TV através do sinal luminoso do LED infra-vermelho. Não significa que ao apertar a tecla "4" você está enviando 4 pulsos luminosos, mas uma sequência binária de tamanho variável, dentro de um intervalo de tempo X. Se o comando não tiver o comprimento certo, se não for executando dentro do tempo limite ou se a sequência binária não estiver contida no protocolo, então a TV ignora o comando enviado pelo controle.
Claro que quando se está programando, o nível de complexidade se reduz um bocado, já que o mais baixo nível da comunicação é a interpretação do comando, que será recebido e tratado pela micro-controladora da TV (ou até mesmo o micro-processador, se esse for um replacement para a tradicional interpretadora). Ainda está um bocado abstrato, mas não se preocupe que pouco a pouco as coisas se tornarão mais claras até chegarmos ao perfeito entendimento.
Então, para copiarmos os comandos do controle remoto de nossa TV, a primeira fase será a leitura de alguns comandos do respectivo controle, utilizando um receptor infra-vermelho de 38KHz (que significa uma amostragem possível de 38000 0's ou 1's), que pode ser adquirido através de nossos parceiros (que você vê no início de página de cada artigo) por alguns reais com um controle remoto próprio. Tendo-o em mãos, sigamos.
Outra coisa de suma importância é o comprimento de onda do LED IR. É fundamental ler o datasheet do seu receptor IR para saber o LED IR ideal. Se optar por comprar um desses que já vem com o controle, então você não tem nada a se preocupar.
Ótima frase de um kibador, e em partes funciona bem. Para fazermos a captura dos sinais, utilizaremos a biblioteca prontinha desenvolvida para usar infravermelho com Arduino, que você encontra bem aqui. Dito isso, faço do autor todos os créditos, porque de outro modo seria necessário fazer uma leitura muito delicada para medir o comprimento e pulsos de cada comando - e garanto, não é trivial.
Então, seguindo o esquema desenhado com a utilização do software Fritzing, poderemos utilizar o código a seguir (ok, o sensor não é o do desenho, mas não achei o correto).
/*
* IRremote: IRrecvDump - dump details of IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
#include <IRremote.h>
int RECV_PIN = 6;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
// Dumps out the decode_results structure.
// Call this after IRrecv::decode()
// void * to work around compiler issue
//void dump(void *v) {
// decode_results *results = (decode_results *)v
void dump(decode_results *results) {
int count = results->rawlen;
if (results->decode_type == UNKNOWN) {
Serial.print("Unknown encoding: ");
}
else if (results->decode_type == NEC) {
Serial.print("Decoded NEC: ");
}
else if (results->decode_type == SONY) {
Serial.print("Decoded SONY: ");
}
else if (results->decode_type == RC5) {
Serial.print("Decoded RC5: ");
}
else if (results->decode_type == RC6) {
Serial.print("Decoded RC6: ");
}
else if (results->decode_type == PANASONIC) {
Serial.print("Decoded PANASONIC: ");
}
else if (results->decode_type == JVC) {
Serial.print("Decoded JVC: ");
}
else if (results->decode_type == SAMSUNG) {
Serial.print("Decoded SAMSUNG: ");
}
int val1 = results->value;
Serial.print(val1, HEX);
Serial.print(" (");
int valbits = results->bits;
Serial.print(valbits, DEC);
Serial.println(" bits)");
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");
for (int i = 0; i < count; i++) {
if ((i % 2) == 1) {
int valen = results->rawbuf[i]*USECPERTICK;
Serial.print(valen, DEC);
}
else {
int negvalen =-(int)results->rawbuf[i]*USECPERTICK;
Serial.print(negvalen, DEC);
}
Serial.print(", ");
}
Serial.println("");
}
void loop() {
if (irrecv.decode(&results)) {
int hexen = results.value;
Serial.println(hexen, HEX);
dump(&results);
irrecv.resume(); // Receive the next value
}
}
Não é necessário que você domine todos os fundamentos envolvidos nessa pequena porção prévia de código, mas há algo que deve ser percebido; a controladora se tornou um dispositivo dedicado, já que não pode dividir tempo de processamento com nenhuma outra tarefa; pelo lado positivo, lembre-se que a única razão dessa configuração é mapear o controle remoto, posteriormente reutilizando a controladora para enviar os comandos mapeados.
Mais uma vez, você pode baixar a biblioteca nesse link. Ela é repleta de exemplos, o site também se repete ao mostrar como utilizá-la, portanto, não há meios para que você diga que não conseguiu fazer!
Ao abrir o terminal serial, você verá algumas mensagens passando periodicamente, mas atente-se apenas na mensagem de quando você pressionar algum botão do controle. Deve retornar algo como:
Decoded SAMSUNG: FFFF807F (32 bits)
Raw (68): 6306, 4500, -4500, 600, -1600, 600, -1650, 600, -500, 650, -500, 550, -550, 600, -500, 600, -1650, 600, -500, 600, -1650, 600, -1650, 600, -500, 600, -500, 600, -1650, 600, -500, 600, -1650, 600, -500, 600, -1650, 600, -500, 600, -550, 550, -550, 600, -500, 600, -550, 600, -500, 600, -500, 600, -550, 600, -1600, 600, -1650, 550, -1650, 600, -1650, 600, -1650, 550, -1650, 650, -1600, 600,
Mas dependendo da TV, da marca ou do dispositivo, pode aparecer "unknown device", que é o caso do meu blue-ray. Mas não se preocupe, para fazer o envio do comando a regra é muito simples (faremos juntos no código final):
1 - Remova o primeiro campo numérico e certifique-se de que os campos restantes somam o total Raw mostrado entre parênteses. No caso do blue-ray, você poderá ver no video que o tamanho da mensagem também é diferente; 78 valores estão dispostos na mensagem.
2 - Passe todos os valores negativos para positivo. Se você for tão preguiçoso quanto eu, pode utilizar o próprio C++ para converter os valores para você. Já mostro mais alí.
3 - Monte um array com esses valores.
4 - Envie o comando.
Claro que você verá no video os códigos, captura do valor e a execução. Agora vejamos o código para a execução de um comando:
#include <IRremote.h> // use the library
IRsend irsend;
// Power ON / OFF
unsigned int powerOn[68] = {4500, 4500, 600, 1600, 600, 1650, 600, 500, 650, 500, 550, 550, 600, 500, 600, 1650, 600, 500, 600, 1650, 600, 1650, 600, 500, 600, 500, 600, 1650, 600, 500, 600, 1650, 600, 500, 600, 1650, 600, 500, 600, 550, 550, 550, 600, 500, 600, 550, 600, 500, 600, 500, 600, 550, 600, 1600, 600, 1650, 550, 1650, 600, 1650, 600, 1650, 550, 1650, 650, 1600, 600};
void setup()
{
Serial.begin(9600);
}
void loop() {
// @param1 Raw data
// @param2 length
// @param3 frequency, (most devices use 38khz)
irsend.sendRaw(powerOn,68,38);
delay(100);
}
Esse é o código de exemplo do desenvolvedor. Vamos a alguns pontos importantes; você não vê nele o pino utilizado para enviar o sinal ao LED IR. O desenvolvedor fala "Pino3", mas a lib 1.0 está configurada para utilizar o pino 13.
Instancia-se um objeto irsend e, devido ao dispositivo não ter sido reconhecido automaticamente (porque não há código específico para interpretar comandos do blue-ray na biblioteca), então deve-se enviar o comando em modo raw.
O protocolo da Sony convenciona que os comandos devem ser enviados 3 vezes, ou seja, cada ínfimo detalhe deve ser considerado, portanto, nao ache que o código não funciona! Na parte física, apenas tente certificar-se de que a frequência do seu receptor é igual à frequência de transmissão, senão não funcionará.
O código de exemplo está enviando o comando a cada 100ms.
o método sendRaw recebe o array de valores do comando, o tamanho do buffer e a frequência de envio, que deve ser a mesma do receptor.
Mudaremos o código de exemplo para um funcionamento mais adequado a um exemplo de dois comandos e utilizaremos uma pitada de código C++ para converter os valores negativos para positivos, poupando-nos o trabalho de remover manualmente. Pode parecer pouco a princípio, mas se você mapear por exemplo 40 teclas, vezes uma média de 20 valores negativos, já seriam 800 valores para percorrer removendo sinais de menos. Um método ajudará a resolver o problema e tornará o código mais divertido!
Criei duas funções na classe main de um projeto C++ criado no Code::Blocks. Você pode fazer algo semelhante na própria interface do Arduino, mas o Code::Blocks é gratuito e poderá lhe servir também como um ambiente de testes e treino em C/C++ antes de subir algum código para a micro-controladora.
Programar é uma arte, exatamente como pintar um quadro; vai da inspiração até que o programador desenvolva seu próprio estilo e por fim mostre-se um criativo nos meios adotados para cumprir uma determinada tarefa. Pensando nisso, fiz as duas funções justamente para reduzir o número de críticos e haters; uma trabalha sobre o valor inteiro, a outra trabalha sobre uma string dos valores (mas sim, eu sei - as possibilidades são amplas):
Se você utilizar essa função no Code::Blocks, não esqueça de fazer include da cmath na primeira linha do arquivo cpp, seja o main ou alguma classe criada por você:
#include <cmath>
Depois sim, crie seu método ou função tal qual segue.
void removeNegativeSignal(long int *commandArray, int lenght, string varName)
{
unsigned int arrayValues[lenght];
for (int i=0;i<lenght;i++){
arrayValues[i] = abs(commandArray[i]);
}
cout << "unsigned int " << varName << "= {";
for (int i=0;i<lenght;i++){
cout << arrayValues[i];
if (i<lenght-1){
cout << ",";
}
}
cout << "};" << endl;
}
Ao executá-lo, a conversão é exibida no terminal, bastando copiá-lo e colá-lo na IDE do Arduino.
Essa função recebe como parâmetros a string contendo os valores e um nome para a variável resultante.
void simplifiedNegativeRemover(string values, string name)
{
while(values.find('-') != string::npos){
values.replace(values.find("-"),1," ");
}
cout << endl << "unsigned int " << name << "=" << values << ";" << endl;
}
As variáveis para as respectivas funções você adapta conforme a escolha:
long int onOff[4] = {234,-545,-222,111};
string valores = "{234, -545, -222, 111}";
No video você verá a montagem na protoboard tal qual o desenho acima. No video inicialmente falei "pino 13", mas foi um equivoco. O pino 13 está sendo utilizado pelo sender, o receptor usa o pino definido na variável RECV_PIN, que está definida logo após o include da biblioteca IRremote.
Vale também citar que o desenvolvedor da biblioteca diz que na atual versão, o sender está utilizando o pino 3 da controladora, mas de fato está utilizando o pino 13.
Agora chegamos finalmente à parte que nos interessa, que é enviar comandos pelo Arduino. O código supracitado refere-se ao modo de fazê-lo conforme o exemplo do desenvolvedor e vou usar algo muito parecido, mas com o comando selecionado via monitor serial. Eu gostaria de mapear o controle remoto da TV, mas já há algum tempo que meu controle quebrou e acabei fazendo um em Qt para Android. Acabou que o relaxo não me permitiu adquirir outro controle até então. Por fim, eu sentei e escrevi esse código em menos de 10 minutos, sem nenhum planejamento. Por favor, não o odeiem, é apenas um exemplo para prova de conceito. Dito isso, vamos ao código:
#include <IRremote.h>
//infravermelho com Arduino
IRsend sender;
int go =0;
char nByte[10];
int byteCounter = 0;
String comm;
unsigned int onOff[78] = {4650, 4400, 600, 400, 600, 450, 550, 450, 550, 450, 550, 450, 550, 1450, 600, 400, 600, 400, 600, 450, 550, 450, 550, 450, 550, 450, 600, 400, 600, 400, 600, 400, 600, 450, 550, 4450, 550, 1450, 600, 1400, 600, 1450, 550, 450, 550, 450, 600, 400, 600, 400, 600, 400, 600, 450, 550, 450, 550, 450, 550, 450, 550, 1450, 600, 1400, 600, 1450, 550, 1450, 600, 1400, 600, 1450, 550, 1450, 550, 1450, 600, 1208};
void clearVar(){
for (int a=0;a<10;a++){
nByte[a] = 0;
}
}
void setup(){
Serial.begin(9600);
clearVar();
}
void loop(){
if (Serial.available() > 0){
nByte[byteCounter] = Serial.read();
go = 1;
byteCounter++;
}
else if (go == 1){
comm = nByte;
if (comm.equals("power")){
Serial.println("mandou power");
sender.sendRaw(onOff,78,38);//buffer,lenght,KHz
}
else if (comm.equals("nada")){
Serial.println("Nada, apenas para testar");
}
else{
Serial.println(nByte);
}
go = 0;
byteCounter = 0;
clearVar();
}
}
Se você não assistiu o video, assista agora, está consideravelmente bom. Pra finalizar, não deixe de dar um like lá no youtube, que é a recompensa pelo trabalho de vários dias compondo video, áudio, textos e arte, para tentar entregar a você uma experiência cada vez mais agradável. E se te apraz, assine o canal, isso não lhe gerará infortúnios com spam nem excesso de posts, considerando o tempo que levo para produzi-los atualmente, que é de vários e vários dias.
Se desejar, aproveite para ver a configuração de um infravermelho no Raspberry.
Inscreva-se no nosso canal "Manual do Maker Brasil" no YouTube para participar de um sorteio de alguns componentes para diversão com Arduino que será sorteado com data anunciada no próximo post:
Manual do Maker Brasil
Produção
Efeitos Sonoros:
Free SFX
Edição de video e chroma key:
KDEnLive (link)
Edição e gravação de áudio:
Audacity (link)
Sony Audio Recorder
Animações:
Blender (link)
Criação musical:
Music Maker Jam (1)
Portal de pesquisa:
Google
Programação:
Code::Blocks (1)
Arduino IDE (2)
Material de produção do projeto
Material ambiente parar fazer o controle infravermelho com Arduino
Se gostou desse artigo de como utilizar infravermelho com Arduino, não deixe de compartilhar; dê seu like no vídeo e inscreva-se no nosso canal Manual do Maker Brasil no YouTube.
Prefere seguir-nos pelo facebook? Basta curtir aqui.
Prefere twitter? @DobitAoByte.
Próximo post a caminho!
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.