Controle remoto infravermelho no Arduino: decodifique o botão e use o código
Como ler o código de cada botão com o receptor de 38 kHz e a IRremote, ignorar repetição e ruído, e transformar o número em comando confiável.
Você aponta o controle da TV para o robô, filma o LED com a câmera do celular, vê a luz roxa piscando e o robô continua parado. A luz existe, mas o Arduino não sabe o que fazer com ela. A resposta curta: o receptor infravermelho entrega um código por botão, e o seu programa precisa conhecer esse código antes de agir. Primeiro você decodifica e anota o número de cada tecla; só depois escreve o if que move o motor.
Ao longo deste guia, o exemplo é um carrinho com quatro comandos (frente, ré, esquerda, direita) e um botão de parar, usando aquele controle pequeno de 21 teclas que vem em kits de Arduino e um receptor de três pinos do tipo VS1838B ou TSOP38238.
Por que filmar o LED não prova nada
O controle não "acende" de forma contínua. Ele liga e desliga o LED infravermelho numa frequência portadora, quase sempre perto de 38 kHz, e agrupa esses pulsos em rajadas longas e curtas. A sequência de rajadas forma um quadro digital com o endereço do aparelho e o número do comando. Cada fabricante usa um protocolo: NEC, Sony, RC5, Samsung e vários outros.
O receptor de três pinos faz a parte difícil. Ele filtra a luz que não está na portadora, demodula o sinal e entrega no pino de saída um nível lógico que acompanha as rajadas. A câmera do celular só mostra que há luz infravermelha; ela não diz se a portadora bate com o receptor, se o protocolo é conhecido ou se o quadro chegou inteiro.
Por isso o passo zero é sempre o mesmo: ler o que chega no pino, deixar uma biblioteca identificar o protocolo e imprimir o comando na Serial.
Como ligar o receptor
O receptor tem três pinos: saída de sinal, GND e alimentação. A ordem muda entre modelos e entre módulos montados em plaquinha, então confira a folha de dados ou a serigrafia antes de ligar. Inverter alimentação e GND costuma esquentar o componente em segundos.
- Ligue a alimentação em 5 V (ou 3,3 V, se a placa for de 3,3 V e o receptor aceitar essa tensão).
- Ligue o GND no GND do Arduino.
- Ligue a saída num pino digital. Aqui, o pino 2.
- Se o fio for longo ou a fonte ruidosa, coloque um capacitor de desacoplamento perto do receptor, como recomendam as folhas de dados desses componentes.
Como descobrir o código de cada botão
A biblioteca mais usada é a IRremote, instalável pelo gerenciador de bibliotecas da IDE. Nas versões recentes, a interface mudou: o objeto global IrReceiver substituiu o antigo IRrecv, e o cabeçalho recomendado é IRremote.hpp. Tutoriais antigos com irrecv.enableIRIn() e results.value não compilam do mesmo jeito; use os exemplos que vêm com a versão instalada.
Este sketch só lê e imprime:
#include <IRremote.hpp>
const uint8_t PINO_IR = 2;
void setup() {
Serial.begin(115200);
IrReceiver.begin(PINO_IR, ENABLE_LED_FEEDBACK);
Serial.println("Aponte o controle e aperte um botao por vez");
}
void loop() {
if (IrReceiver.decode()) {
IrReceiver.printIRResultShort(&Serial);
IrReceiver.resume();
}
}
Abra o Monitor Serial em 115200 e aperte cada botão uma vez, devagar. Você verá linhas com o protocolo, o endereço e o comando, algo como Protocol=NEC Address=0x0 Command=0x18. Os seus números serão outros; o que importa é anotar os pares em uma tabela no próprio código.
Se aparecer UNKNOWN, o protocolo não foi reconhecido ou o quadro chegou corrompido. Aproxime o controle, afaste o receptor da janela e tente de novo. Se continuar desconhecido em todas as tentativas, o controle provavelmente usa um protocolo que a biblioteca não decodifica, e é mais simples trocar de controle do que lutar com o sinal cru.
Como transformar o código em comando sem disparar duas vezes
Segurar um botão não repete o quadro inteiro em todos os protocolos. No NEC, por exemplo, o controle manda o quadro completo uma vez e depois quadros curtos de repetição enquanto o dedo estiver apertado. A IRremote marca essas repetições com uma flag. Para o carrinho, você quer duas coisas: andar enquanto o botão está apertado e parar quando as repetições cessam.
#include <IRremote.hpp>
const uint8_t PINO_IR = 2;
// Valores anotados com o sketch de leitura. Troque pelos seus.
const uint16_t ENDERECO_CONTROLE = 0x00;
const uint8_t CMD_FRENTE = 0x18;
const uint8_t CMD_RE = 0x52;
const uint8_t CMD_ESQUERDA = 0x08;
const uint8_t CMD_DIREITA = 0x5A;
const uint8_t CMD_PARAR = 0x1C;
const unsigned long TEMPO_SEM_SINAL_MS = 200;
uint8_t ultimoComando = CMD_PARAR;
unsigned long ultimoSinal = 0;
void executar(uint8_t cmd) {
switch (cmd) {
case CMD_FRENTE: Serial.println("frente"); break;
case CMD_RE: Serial.println("re"); break;
case CMD_ESQUERDA: Serial.println("esquerda"); break;
case CMD_DIREITA: Serial.println("direita"); break;
default: Serial.println("parar"); break;
}
}
void setup() {
Serial.begin(115200);
IrReceiver.begin(PINO_IR, DISABLE_LED_FEEDBACK);
}
void loop() {
if (IrReceiver.decode()) {
IRData &d = IrReceiver.decodedIRData;
bool repeticao = d.flags & IRDATA_FLAGS_IS_REPEAT;
if (d.protocol == NEC && d.address == ENDERECO_CONTROLE) {
if (!repeticao) {
ultimoComando = d.command;
executar(ultimoComando);
}
ultimoSinal = millis();
}
IrReceiver.resume();
}
if (ultimoComando != CMD_PARAR && millis() - ultimoSinal > TEMPO_SEM_SINAL_MS) {
ultimoComando = CMD_PARAR;
executar(CMD_PARAR);
}
}
Três detalhes fazem esse código ser confiável. O filtro de protocolo e endereço descarta o controle do ar-condicionado que alguém aperta na mesma sala. A repetição só renova o tempo, não executa a ação de novo. E o tempo limite sem sinal para o carrinho se o controle sair do alcance, em vez de deixá-lo andando até bater. Em qualquer coisa que se mova, a falta de sinal precisa significar parar. O mesmo raciocínio de "um evento, uma ação" aparece no guia sobre botão no Arduino sem repetir.
O valor de 200 ms é um ponto de partida. Se o carrinho engasgar enquanto você segura o botão, meça o intervalo entre repetições do seu controle imprimindo millis() e ajuste com folga.
Sol, lâmpada e alcance
A luz do sol tem muito infravermelho, e algumas lâmpadas fluorescentes e de LED com driver barato emitem ruído que o receptor tenta interpretar. O sintoma é decodificação intermitente ou códigos desconhecidos aparecendo sem ninguém apertar nada. Teste primeiro à sombra, depois no lugar de uso. Um tubinho opaco em volta do receptor, deixando só a frente aberta, já reduz bastante a luz lateral.
Lembre também que infravermelho precisa de linha de visada ou de reflexo em parede clara. Atrás de acrílico escuro, o alcance cai; atrás de metal, some.
Erros comuns
- Copiar códigos de outro tutorial: controles parecidos podem mandar endereços e comandos diferentes, e o programa nunca reconhece o botão.
- Executar a ação a cada quadro de repetição: um toque de meio segundo vira cinco comandos, e o servo ou o motor dá trancos.
- Esquecer o
resume(): o receptor para de aceitar novos quadros depois do primeiro, e parece que o controle "funcionou uma vez só". - Usar outra biblioteca que disputa o mesmo timer:
tone(), PWM em certos pinos ou uma segunda biblioteca de infravermelho deixam de funcionar. O assunto está detalhado em duas bibliotecas de infravermelho brigando pelo timer. - Não tratar ausência de sinal: o robô continua executando o último comando quando o controle sai do alcance.
- Bloquear o loop com
delay()longo: enquanto o programa dorme, quadros chegam e se perdem, e a resposta fica lenta.
Checklist
- A pinagem do receptor foi conferida na folha de dados ou na plaquinha antes de ligar.
- O sketch de leitura imprime protocolo, endereço e comando para cada botão usado.
- Os códigos estão em constantes com nome, não espalhados como números soltos.
- O programa filtra protocolo e endereço do seu controle.
- Repetições não disparam a ação de novo.
- Sem sinal por um tempo definido, o sistema volta ao estado seguro.
- O teste foi repetido no local real, com a iluminação real.
Abra o seu sketch agora: se você apertar um botão que não está na sua tabela, ou se o controle sair da sala no meio de um comando, o que o seu projeto faz?
Referência: http://www.criandorobocomarduino.com/2013/12/como-fazer-um-controle-remoto-de-tv-com.html