Xiaomi掃除機に乗る

だから、新年の休暇が来て、彼らと一緒に多くの自由時間があり、スマートな掃除機でさえ私の手に落ちました。 MiHomeアプリケーションで手動制御を見るとすぐに、私がしたいことにすぐに気付きました。Dualshockv4ゲームパッドを使用して掃除機を制御します!



ステップ1、トークンのドラッグ、点滅(オプション)



トークンを表示するパッチを適用したMiHomeアプリケーションを配置し、ルートファームウェアを選択し、python-miioをダウンロードしてインストールし(pip install python-miio)、 mirobo --ip %ip% --token %token% update-firmware %filename%



を使用してファームウェアのインストールを試みますmirobo --ip %ip% --token %token% update-firmware %filename%



そしてこの時点ですべてが壊れました。 掃除機は必死に更新を拒否し、数時間のグーグル検索の後、miroboとloのデバッグ出力を見てみました! 私はラップトップにいくつかのアダプターがインストールされているという事実のために、彼はVirtualBox Host-Onlyアダプターのネットワークでファームウェアを配布しようとしました。 次に、ファイルサーバーを上げてこのコマンドを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"}'



ファームウェアは10分以内に起動し、sshアクセスが機能しました



ステップ2、ロボットに乗ろうとする



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





この時点で、掃除機はリモートコントロールの使用(またはファームウェアに応じて類似したもの)を言って、痙攣して停止するはずです。



ステップ3、Dualshockを接続する



少し調査した結果、pygameを使用することになりました

どのボタン/ステッカーが責任を負っているのかを調べます



 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)
      
      





これまでのmove_robotでは、印刷(軸)して、ジョイスティックが機能していることを確認できます。

次に、ボタン/スティックを押すとロボットに乗る必要があります。速度のためにY軸の左スティック(上-1、下1)を選択し、角度のためにX軸の右スティックを選択しました、それはこのようになりました



 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)
      
      





スクリプトを実行し、コントローラーでXを押すと、ロボットは乗車して旋回する必要があります

この段階で問題が発生しました:何らかの理由で、左スティックを最後まで押して回そうとすると、回らなくなり、まず減速する必要があります、マッピング値を小さくしようとすると、たとえば、-0.29、0.29を設定すると、丸くなり始めます、左のステッカーの位置が変わるまで、私は問題が何であるか理解できませんでした



ステップ4、音楽を追加する



ロボットにsshでアクセスし、スクリプト言語が何であるかを確認します。



Pythonはありませんでしたが、インストールする意味がわかりませんでしたが、小さな作業に適した真珠を見つけました。



次に、soxをインストールします。



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





真珠の上に小さなサーバーを書く:



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





コンソールでは次のようなことをしています



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





そして、掃除機を通してtest.mp3が再生されるはずです(したがって、ローカルマシンでファイルサーバーを上げる必要があります)。



play_sound()関数はほぼ同じことを行い、sendall(url + ';')のみが実行されます。urlは関数の引数です。



結果






All Articles