Ride on Xiaomi Vacuum Cleaner
- Tutorial
So the New Year holidays came, and with them a lot of free time, and even a smart vacuum cleaner got into my hands. As soon as I saw manual control in the MiHome application, I immediately understood what I wanted to do: we will control the vacuum cleaner using the Dualshock v4 gamepad!
We install the patched MiHome application, which will show us the token, then choose the custom firmware, download, install python-miio (pip install python-miio), try to install the firmware with the help
At this point, the vacuum cleaner should say Using remote controls (or something like that depending on the firmware), twitch and stop
After a little research, it was decided to use pygame
We look at which buttons / stickers are responsible for
While in move_robot, you can simply print (axis) and check that the joystick is working.
Next, we need to make the robot go by pressing the buttons / stick, I chose the left stick on the Y axis (up -1, down 1) for speed and the right stick on the X axis for the angle, it turned out about the function
Run the script, press X on the controller and the robot has to drive and turn.
At this stage I had a problem: for some reason, if you press the left stick forward to the end and try to turn, it will not turn, you will have to slow down first if you try to decrease the mapping values , for example, put -0.29, 0.29, he will start to go in a circle until the position of the left sticker changes, I have not figured out what the problem is
We go on ssh on our robot and see what scripting languages are there.
There was no python, but I didn’t see the point of installing it, but I found a pearl, it will work for our small task.
Next, install sox:
and write a small server on a pearl:
do something like in my console
And through the vacuum cleaner, our test.mp3 should play (accordingly, we need to raise the file server on our local machine).
Our play_sound () function will do almost the same thing, only there will be sendall (url + ';'), url - function argument.
Step 1, dragging a token, flashing (optional)
We install the patched MiHome application, which will show us the token, then choose the custom firmware, download, install python-miio (pip install python-miio), try to install the firmware with the help
mirobo --ip %ip% --token %token% update-firmware %filename%
and at this moment everything broke. The vacuum cleaner desperately refused to be updated, after several hours of googling, I tried to look at the mirobo debugging output and about a miracle! Due to the fact that I have several adapters installed on my laptop, he tried to distribute the firmware on the VirtualBox Host-Only adapter network. Next, I just picked up a file server and execute the command 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"}'
. The firmware got up in about 10 minutes, access via ssh workedStep 2, trying to ride a robot
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()
At this point, the vacuum cleaner should say Using remote controls (or something like that depending on the firmware), twitch and stop
Step 3, connect the dualshock
After a little research, it was decided to use pygame
We look at which buttons / stickers are responsible for
BUTTON_SQUARE = 0
BUTTON_X = 1
BUTTON_CIRCLE = 2
BUTTON_TRIANGLE = 3definit_joystick():
pygame.init()
pygame.joystick.init()
controller = pygame.joystick.Joystick(0)
controller.init()
return controller
defmain():
controller = init_joystick()
bot = miio.vacuum.Vacuum(ip, token)
modes = ['manual', 'home', 'spot', 'cleaning', 'unk']
mode = 'unk'
axis = [0.00for _ in range(6)]
flag = True
button = [Falsefor _ 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 exitif event.button == 13:
flag = Falseelif 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 laterelif event.button == BUTTON_CIRCLE:
# stop sound
play_sound(';')
if mode == 'manual':
try:
move_robot(bot, button, axis) # see ya in the next stepexcept:
bot.manual_start()
pass
time.sleep(0.01)
While in move_robot, you can simply print (axis) and check that the joystick is working.
Next, we need to make the robot go by pressing the buttons / stick, I chose the left stick on the Y axis (up -1, down 1) for speed and the right stick on the X axis for the angle, it turned out about the function
deftranslate(value, leftMin, leftMax, rightMin, rightMax):
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
valueScaled = float(value - leftMin) / float(leftSpan)
return rightMin + (valueScaled * rightSpan)
defmove_robot(bot, buttons, axis):
rot = 0
val = 0
to_min, to_max = -0.3, 0.3# Right stick Xif axis[2] != 0:
rot = -translate(axis[2], -1, 1, -90, 90)
if abs(rot) < 8:
rot = 0# Left stick Y, -1 up, 1 downif axis[1] != 0:
val = -translate(axis[1], -1, 1, to_min, to_max)
if abs(val) < 0.07:
val = 0if rot or val:
bot.manual_control(rot, val, 150)
Run the script, press X on the controller and the robot has to drive and turn.
At this stage I had a problem: for some reason, if you press the left stick forward to the end and try to turn, it will not turn, you will have to slow down first if you try to decrease the mapping values , for example, put -0.29, 0.29, he will start to go in a circle until the position of the left sticker changes, I have not figured out what the problem is
Step 4, add music
We go on ssh on our robot and see what scripting languages are there.
There was no python, but I didn’t see the point of installing it, but I found a pearl, it will work for our small task.
Next, install sox:
sudo apt-get install sox, libsox-fmt-mp3
and write a small server on a pearl:
#!/usr/bin/perluse 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
do something like in my console
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()
And through the vacuum cleaner, our test.mp3 should play (accordingly, we need to raise the file server on our local machine).
Our play_sound () function will do almost the same thing, only there will be sendall (url + ';'), url - function argument.