Wir fahren Xiaomi Staubsauger

So kamen die Neujahrsferien und mit ihnen viel Freizeit, und sogar ein intelligenter Staubsauger fiel mir in die Hände. Sobald ich die manuelle Steuerung in der MiHome-Anwendung sah, wurde mir sofort klar, was ich tun wollte: Wir werden den Staubsauger mit dem Dualshock v4-Gamepad steuern!

Schritt 1, Ziehen des Tokens, Blinken (optional)


Wir setzen die gepatchte MiHome-Anwendung ein, die uns das Token anzeigt, wählen dann die Root-Firmware aus, laden sie herunter, installieren python-miio (pip install python-miio) und versuchen, die Firmware mit mirobo --ip %ip% --token %token% update-firmware %filename% zu installieren mirobo --ip %ip% --token %token% update-firmware %filename% und zu diesem Zeitpunkt ist alles kaputt gegangen. Der Staubsauger weigerte sich verzweifelt, aktualisiert zu werden. Nach mehreren Stunden Googeln versuchte ich, die Debug-Ausgabe von mirobo zu sehen und siehe da! Aufgrund der Tatsache, dass auf meinem Laptop mehrere Adapter installiert sind, versuchte er, die Firmware im Netzwerk des VirtualBox Host-Only-Adapters zu verteilen. Als nächstes habe ich gerade den Dateiserver hochgefahren und diesen Befehl ausgeführt: 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"}' . Die Firmware ist in 10 Minuten irgendwo hochgekommen, der SSH-Zugriff hat funktioniert

Schritt 2, versuchen Sie den Roboter zu fahren


 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() 

Zu diesem Zeitpunkt sollte der Staubsauger sagen: Mit Fernbedienungen (oder ähnlichem, abhängig von der Firmware) zucken und anhalten

Schritt 3, Dualshock anschließen


Nach ein wenig Recherche wurde entschieden, Pygame zu verwenden
Wir schauen uns an, wofür Knöpfe / Aufkleber verantwortlich sind

 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) 

Im Moment können Sie in move_robot einfach drucken (Achse) und überprüfen, ob der Joystick funktioniert.
Als nächstes müssen wir den Roboter fahren lassen, wenn Sie die Knöpfe / Sticks drücken. Ich habe den linken Stick auf der Y-Achse (oben -1, unten 1) für die Geschwindigkeit und den rechten Stick auf der X-Achse für den Winkel gewählt. Es stellte sich so heraus

 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) 

Führen Sie das Skript aus, drücken Sie X auf der Steuerung und der Roboter muss fahren und sich drehen
Zu diesem Zeitpunkt hatte ich ein Problem: Wenn Sie aus irgendeinem Grund den linken Steuerknüppel bis zum Ende nach vorne drücken und versuchen, ihn zu drehen, dreht er sich nicht. Sie müssen zuerst langsamer werden. Wenn Sie versuchen, die Zuordnungswerte zu reduzieren, z. B. -0,29, 0,29, beginnt der Kreis Bis sich die Position des linken Aufklebers ändert, habe ich nie herausgefunden, wo das Problem liegt

Schritt 4, fügen Sie etwas Musik hinzu


Wir fahren mit ssh zu unserem Roboter und sehen, welche Skriptsprachen es gibt.

Es gab kein Python, aber ich sah keinen Sinn darin, es zu installieren, aber ich fand eine Perle, die für unsere kleine Aufgabe geeignet war.

Als nächstes installieren Sie Sox:

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

und schreibe einen kleinen Server auf die Perle:

 #!/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 

In unserer Konsole machen wir so etwas

 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() 

Und durch den Staubsauger sollte unsere test.mp3 abgespielt werden (dementsprechend müssen wir den Dateiserver auf unserem lokalen Computer anheben).

Unsere Funktion play_sound () macht fast dasselbe, nur sendall (url + ';') wird es sein, url ist das Funktionsargument.

Ergebnis


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


All Articles