Montamos o aspirador Xiaomi

Então chegaram as férias de Ano Novo, e com elas muito tempo livre, e até um aspirador inteligente caiu em minhas mãos. Assim que vi o controle manual no aplicativo MiHome, percebi imediatamente o que queria fazer: controlaremos o aspirador usando o gamepad Dualshock v4!

Etapa 1, arrastando o token, piscando (opcional)


Colocamos o aplicativo MiHome corrigido, que nos mostrará o token e, em seguida, selecione o firmware raiz, faça o download, instale o python-miio (instale o python python-miio), tente instalar o firmware usando mirobo --ip %ip% --token %token% update-firmware %filename% e, neste ponto, tudo quebrou. O aspirador se recusou desesperadamente a ser atualizado, depois de várias horas pesquisando, tentei ver a saída de depuração do mirobo e eis que eis! Devido ao fato de eu ter vários adaptadores instalados no meu laptop, ele tentou distribuir o firmware na rede do adaptador VirtualBox Host-Only. Em seguida, acabei de criar o servidor de arquivos e mirobo --ip=%ip% --token=%token% raw-command miIO.ota '{"mode":"normal", "install":"1", "app_url":"http://%my_ip:port%/%filename%.pkg", "file_md5":"%md5%","proc":"dnld install"}' este comando: mirobo --ip=%ip% --token=%token% raw-command miIO.ota '{"mode":"normal", "install":"1", "app_url":"http://%my_ip:port%/%filename%.pkg", "file_md5":"%md5%","proc":"dnld install"}' . O firmware subiu em algum lugar em 10 minutos, o acesso ssh funcionou

Etapa 2, tente montar o robô


 import miio ip = '' token = '' bot = miio.vacuum.Vacuum(ip, token) bot.manual_start() bot.manual_control(0, 0.3, 2000) # move forward with max speed for 2 seconds bot.manual_control(90, 0, 1000) # rotate bot.manual_stop() 

Neste ponto, o aspirador de pó deve dizer: Usando controles remotos (ou algo semelhante, dependendo do firmware), torça e pare.

Etapa 3, conecte o Dualshock


Depois de um pouco de pesquisa, decidiu-se usar pygame
Examinamos quais botões / adesivos são responsáveis ​​por

 BUTTON_SQUARE = 0 BUTTON_X = 1 BUTTON_CIRCLE = 2 BUTTON_TRIANGLE = 3 def init_joystick(): pygame.init() pygame.joystick.init() controller = pygame.joystick.Joystick(0) controller.init() return controller def main(): controller = init_joystick() bot = miio.vacuum.Vacuum(ip, token) modes = ['manual', 'home', 'spot', 'cleaning', 'unk'] mode = 'unk' axis = [0.00 for _ in range(6)] flag = True button = [False for _ in range(14)] print('Press start to start!') while flag: for event in pygame.event.get(): if event.type == pygame.JOYAXISMOTION: axis[event.axis] = round(event.value,2) elif event.type == pygame.JOYBUTTONDOWN: button[event.button] = True # Touchpad to exit if event.button == 13: flag = False elif event.type == pygame.JOYBUTTONUP: if mode == 'unk': print('Ready to go! Press X to start manual mode') if event.button == BUTTON_X: mode = 'manual' bot.manual_start() elif mode == 'manual': if event.button == BUTTON_TRIANGLE: bot.manual_stop() mode = 'unk' elif event.button == BUTTON_X: play_sound('http://192.168.1.43:8080/dejavu.mp3') # see ya later elif event.button == BUTTON_CIRCLE: # stop sound play_sound(';') if mode == 'manual': try: move_robot(bot, button, axis) # see ya in the next step except: bot.manual_start() pass time.sleep(0.01) 

Por enquanto, no move_robot, você pode simplesmente imprimir (eixo) e verificar se o joystick está funcionando.
Em seguida, precisamos fazer o robô andar quando você pressiona os botões / palitos, escolhi o manípulo esquerdo no eixo Y (para cima -1, para baixo 1) para velocidade e o manípulo direito no eixo X para ângulo, ficou assim

 def translate(value, leftMin, leftMax, rightMin, rightMax): leftSpan = leftMax - leftMin rightSpan = rightMax - rightMin valueScaled = float(value - leftMin) / float(leftSpan) return rightMin + (valueScaled * rightSpan) def move_robot(bot, buttons, axis): rot = 0 val = 0 to_min, to_max = -0.3, 0.3 # Right stick X if axis[2] != 0: rot = -translate(axis[2], -1, 1, -90, 90) if abs(rot) < 8: rot = 0 # Left stick Y, -1 up, 1 down if axis[1] != 0: val = -translate(axis[1], -1, 1, to_min, to_max) if abs(val) < 0.07: val = 0 if rot or val: bot.manual_control(rot, val, 150) 

Execute o script, pressione X no controlador e o robô deve montar e girar
Nesse estágio, tive um problema: por algum motivo, se você pressionar o manípulo esquerdo para a frente até o fim e tentar girar, ele não girará, será necessário desacelerar primeiro, se tentar reduzir os valores do mapeamento, por exemplo, defina -0,29, 0,29, ele começará a circular , até que a posição do adesivo esquerdo mude, nunca descobri qual é o problema

Etapa 4, adicione um pouco de música


Vamos ao ssh até o robô e ver quais linguagens de script existem.

Não havia Python, mas não vi o objetivo de instalá-lo, mas encontrei uma pérola, adequada para nossa pequena tarefa.

Em seguida, instale o sox:

 sudo apt-get install sox, libsox-fmt-mp3 

e escreva um pequeno servidor na pérola:

 #!/usr/bin/perl use IO::Socket::INET; $| = 1; my $socket = new IO::Socket::INET ( LocalHost => '0.0.0.0', LocalPort => '7777', Proto => 'tcp', Listen => 2, Reuse => 1 ); die "cannot create socket $!\n" unless $socket; print "server waiting for client connection on port 7777\n"; while(1) { my $client_socket = $socket->accept(); my $client_address = $client_socket->peerhost(); my $client_port = $client_socket->peerport(); print "connection from $client_address:$client_port\n"; my $data = ""; $client_socket->recv($data, 256); print "received data: $data\n"; my @urls = split /;/, $data; system("killall play > /dev/null"); $data = "ok"; $client_socket->send($data); shutdown($client_socket, 1); if ( $urls[0] ne "") { system("play -q -v 0.4 " . $urls[0] . " &"); } } $socket->close(); 

 sudo perl sound_server.pl 

no nosso console, fazemos algo como

 import socket ip = '' s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 7777)) s.sendall(b'http://%local_ip%:%local_port%/test.mp3;') s.close() 

E através do aspirador, nosso test.mp3 deve ser reproduzido (portanto, precisamos aumentar o servidor de arquivos em nossa máquina local).

Nossa função play_sound () fará quase a mesma coisa, apenas sendall (url + ';') será, url é o argumento da função.

Resultado


Source: https://habr.com/ru/post/pt435064/


All Articles