O projeto é simples, utiliza um arduino UNO, um controle remoto que estava sobrando - da propria TV, uma panasonic, e um receptor de IR manjado ( TSOP4838 ). O arduino interpreta o sinal vindo do TSOP4838, comunica pelo USB com o computador, e um programa em python converte isso para comandos em Linux.
Receptor IR - Arduino
O hardware não tem nada demais, é o receptor de IR espetado no arduino. Coloquei tudo dentro de um copo do starbuck para não ficar dando curto com o resto dos equipamentos que estão no rack da tv.
O programa utilizado no Arduino é baseado num dos exemplos disponíves com a biblioteca IRremote. Foi adicionado código para lidar coma alimentação do sensor (pino 12 = GND e pino 13 = VCC), e tudo oque era descenessário foi retirado. No meu caso tive sorte do protocolo do controle remoto que eu tinha ser suportado pela biblioteca. No meu caso o protocolo utilizado é o PANASONIC.
#include <IRremote.h> int RECV_PIN = 11; int RECV_VCC_PIN = 13; int RECV_GND_PIN = 12; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { digitalWrite(RECV_GND_PIN, LOW); digitalWrite(RECV_VCC_PIN, HIGH); pinMode(RECV_GND_PIN, OUTPUT); pinMode(RECV_VCC_PIN, OUTPUT); Serial.begin(9600); irrecv.enableIRIn(); // Start the receiver } void loop() { if (irrecv.decode(&results)) { Serial.println(results.value, HEX); irrecv.resume(); // Receive the next value
}
Esse programa retorna um número hexadecimal para cada tecla do controle. Mapeando a função com cada código retornado é feito um mapa do controle remoto. Neste controle da Panasonic algumas teclas mandam o mesmo código 3 vezes, geralmente as teclas que vc não que que fique repetindo, como play/pause e outras. As demais teclas com volume ficam mandando o código periodicamente enquanto o botão é apertado.
O programa monitor a porta serial /dev/ttyACM0 na qual o arduino esta conectada. Sempre que recebe um comando serial ele dispara o correspondente no linux. A ferramente xdotool permite simular o mouse e teclado, e com isso é possivel enviar comandos como aumentar/baixa volume pelas teclas especiais de volume, play/pause etc. Também é possível utilizar diretamente outros comandos do linux, como por exemplo desligar a tela ou fazer shutdown da máquina.
No exemplo acima estão comandos diretos no linux, comandos que simulam teclado ( xdotool key ... ) e comandos que simulam mouse (xdotool mousemove_relative e click ) .
Na figura acima esta uma amostra do programa recebendo os códugos. O primeiro campo é o código recebido pela IR, depois o numero de repetições, uma descrição do código, e o comando executado no linux.
Para algumas teclas do controle é simulado o uso de teclas de multimedia (volume, play, stop por exemplo), barra de rolagem do mouse, ou é executado algum comando específico, como desligar o sistema.
Interpretador em python
Programa python para recepção dos dados. Utiliza biblioteca pySerial e a ferramenta xdotool. Utilizo o python3. O programa acabou ficando mais complicado que o previsto inicialmente porque o receptor pega um pouco de ruído e envia alguns códigos incorretos. O software também gera uma movimentação não linear para o ponteiro do mouse, ou seja, começa devagar e vai movendo cada vez mais rápido, isso torna o controle pelo controle remoto mais fluido. O código esta bastante comentado.# Recepção de control remoto
import time import serial import os VERSION = "0.1" SERIAL_PORT = "/dev/ttyACM0" BAUD_RATE = 9600 REPEATABLE = True NOT_REPEATABLE = False UNKNOW_COMMAND = '??' NO_COMMAND = '' NO_DESCRIPTION = '' NO_IR_CODE = -1 #Lista de relacao entre codigo IR e comando linux. Formato [Codigo IR, Comando Linux, Descricao, Pode Repetir?] command_list = [ ['E17AF807','amixer -q -D pulse sset Master toggle','mute',NOT_REPEATABLE], ['BE3BB37','xdotool key XF86AudioRaiseVolume','aumenta volume',REPEATABLE], ['D4D9F2A7','xdotool key XF86AudioLowerVolume','baixa volume',REPEATABLE], ['21035431','xdotool mousemove_relative -- %MOUSE_MOVE 0','seta para direita',REPEATABLE], ['983AB4C1','xdotool mousemove_relative -- -%MOUSE_MOVE 0','seta para esquerda',REPEATABLE], ['C20370A1','xdotool mousemove_relative -- 0 -%MOUSE_MOVE','seta para cima',REPEATABLE], ['81930A09','xdotool mousemove_relative -- 0 %MOUSE_MOVE','seta para baixo',REPEATABLE], ['BB0ED9E1','xdotool click 1; sleep 0.2','ok',NOT_REPEATABLE], ['AA7B2167','xdotool key XF86AudioPlay','play',NOT_REPEATABLE], ['2E8C2A89','xdotool key XF86AudioNext','fwd',NOT_REPEATABLE], ['1F6E01C9','xdotool key XF86AudioPrev','rew',NOT_REPEATABLE], ['1D15F4D7','xdotool key XF86AudioStop','stop',NOT_REPEATABLE], ['406A954D','systemctl poweroff -i','desliga',NOT_REPEATABLE], ['E17A24DB','xset dpms force off; sleep 1','apaga tv',NOT_REPEATABLE], ['E17A18E7','xdotool key C; sleep 1','apaga tv',NOT_REPEATABLE], ['E17A7887','xdotool getwindowfocus getwindowname;sleep 1','pega nome janela em foco',NOT_REPEATABLE], ['A26409C9','pkill --oldest chrome; google-chrome-stable deezer.com/br/ & sleep 1','Abre pagina deezer',NOT_REPEATABLE], ['240C9161','pkill --oldest chrome; google-chrome-stable www.netflix.com & sleep 1','Abre pagina netflix',NOT_REPEATABLE], ['68E839F1','pkill --oldest chrome; google-chrome-stable www.youtube.com & sleep 1','Abre pagina youtube',NOT_REPEATABLE], ['ABBE1086','xdotool key Escape','esc',NOT_REPEATABLE], ['68E69B7F','xdotool click 4','scrool up',REPEATABLE], ['223C02A7','xdotool click 5','scrool down',REPEATABLE] ] #Codigo q corresponde a tecla repetida do IR. Tecla ainda esta apertada button_down = 'FFFFFFFF' #inicializa para evitar possivel chamada dessa variavel sem inicilizacao linux_command = NO_COMMAND last_command = NO_COMMAND description = NO_DESCRIPTION allow_repeat = NOT_REPEATABLE repetition_count=0 last_ir_code = NO_IR_CODE ir_code = NO_IR_CODE #tempo max para interpretar que a tecla foi solta IR_TIMEOUT = 0.3 #sinaliza q tecla esta pressionada desde ultima vez pressed = False #Maximo deslocamento do mouse max_mouse = 35 # Hello message print("Controle Remoto Arduino/Linux TabaJairo para controle Panasonic") print("Versao: " + VERSION); # Tenta conectar a serial serial_connected = False print("Procurando porta serial...") while (not serial_connected): try: ser = serial.Serial(port=SERIAL_PORT,baudrate=BAUD_RATE, timeout=1) serial_connected = True print("yeah...achei") except: print("buuu...ainda não achei") time.sleep(1) #Loop infinito - ctrl+c para terminar while 1 : #Recebe ir code. Aguarda enquanto nao tem nada na serial last_ir_code = ir_code t = 0 while ser.inWaiting() == 0: time.sleep(0.1) t = t + 0.1 if t > IR_TIMEOUT: t=0 #limpa ultimo codigo pois estourou timeout last_ir_code = NO_IR_CODE out = ser.readline().rstrip() ir_code = out.decode('utf-8') #Procura comando na lista #Coloca NO_COMMAND em linux_command para indicar q nao foi encontrado linux_command = NO_COMMAND for command in command_list: if ir_code == command[0]: linux_command = command[1] description = command[2] allow_repeat = command[3] # Se teve timeout na recepcao do codigo IR entao o ultimo comando eh vazio if last_ir_code == NO_IR_CODE: last_command = NO_COMMAND pressed = False #Verifica se eh comando repetido (tecla pressionada) if (linux_command == last_command) and (last_ir_code != NO_IR_CODE): pressed = True # Aqui tem um truque para melhor responsividade: se o comando atual nao eh reconhecido e # nao teve timeout na recepcap de IR supoe que houve problema na recepcao do codigo: # o codigo eh diferente mas corresponde a ultima tecla pressionada if (linux_command == NO_COMMAND) and (last_ir_code != NO_IR_CODE) and (last_command != NO_COMMAND): pressed = True linux_command = last_command print("Codigo IR invalido! Provavelmente eh o ultimo comando, vamos repetir..."); # Incrementa contador de botao pressionado if pressed: repetition_count+=1 else: repetition_count=0 # Atualiza last command. A posicao da linha eh importante para o codigo funcionar last_command = linux_command #subsitui wildcard %MOUSE_MOVE do movimento do mouse para fazer aceleracao mouse_move = repetition_count*repetition_count+1; if mouse_move > max_mouse: mouse_move = max_mouse linux_command = linux_command.replace("%MOUSE_MOVE",str(mouse_move)) #executa comando se for conhecido. Verifica se ele pode ser repetido ou nao. # Nao queremos o play/pause repetindo, nem o mute por exemplo if linux_command != NO_COMMAND: if repetition_count == 0 or (repetition_count > 0 and allow_repeat): print(ir_code + ' ' + str(repetition_count) + ' --> ' + description + ' --> ' + linux_command); os.system(linux_command) else: print(ir_code + ' ' + str(repetition_count) + ' --> ' + description + ' --> nao pode repetir'); else: print(ir_code + ' ' + str(repetition_count) + ' --> buuu, nao conheco esse comando ');
O programa monitor a porta serial /dev/ttyACM0 na qual o arduino esta conectada. Sempre que recebe um comando serial ele dispara o correspondente no linux. A ferramente xdotool permite simular o mouse e teclado, e com isso é possivel enviar comandos como aumentar/baixa volume pelas teclas especiais de volume, play/pause etc. Também é possível utilizar diretamente outros comandos do linux, como por exemplo desligar a tela ou fazer shutdown da máquina.
No exemplo acima estão comandos diretos no linux, comandos que simulam teclado ( xdotool key ... ) e comandos que simulam mouse (xdotool mousemove_relative e click ) .
Na figura acima esta uma amostra do programa recebendo os códugos. O primeiro campo é o código recebido pela IR, depois o numero de repetições, uma descrição do código, e o comando executado no linux.
Para algumas teclas do controle é simulado o uso de teclas de multimedia (volume, play, stop por exemplo), barra de rolagem do mouse, ou é executado algum comando específico, como desligar o sistema.
Ajuste do navegador
Foi encontrado um problema inesperado durante esse projeto: os navegadores de internet de forma geral não aceitam as teclas de acesso rápido multimidia (play, pause, stop...). Para fazer isso funcionar é necessário instalar um plugin no navegador. Não tive sucesso ao utilizar isso no firefox - o plugin não funcionava. No chrome o plugin funcionou corretamente e agora consigo controlar sites de musica, youtube e netflix com o controle remoto.
Falta deixar claro que estamos simulando tecla de atalho multimidia, que é possivel encontra em alguns teclado reais. Existe o padrão XF86 que são as telcas multimidia. Existe diferentes funções que podem ser acessadas com essas teclas.
Recepção Arduino
A comunicação com o Arduino é feita pela USB. Se o sistema não estiver encontrado o arduino verifique o nome da porta que o arduino esta instalado e corrija no programa de recepção em python. Também verifique se o acesso a USB esta liberado. Falta de acesso é um problema comum com o Arduino, existe bastane informação sobre isso na internet.
Nenhum comentário:
Postar um comentário