Катаемся на Xiaomi Vacuum Cleaner

Автор: admin от 3-01-2019, 20:45, посмотрело: 36

Вот и пришли новогодние праздники, а с ними и куча свободного времени, да еще и умный пылесос угодил ко мне в руки. Как только я увидел в приложении MiHome ручное управление, я сразу понял, что хочу сделать: будем управлять пылесосом с помощью геймпада Dualshock v4!

Смотрим, какие кнопки/стикеры за что отвечают




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 можно сделать просто print(axis) и проверить, что джойстик работает.

Далее нам нужно сделать так, чтобы робот ездил при нажатии на кнопки/стики, я выбрал левый стик по оси 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)




Запускаем скрипт, жмем Х на контроллере и робот должен ездить и поворачивать

На этом этапе у меня возникла проблема: почему-то если нажать левый стик вперед до конца и попытаться повернуть, он не будет поворачивать, придется сначала сбросить скорость, если попытаться уменьшить значения маппинга, например поставить -0.29, 0.29, он начнет ездить по кругу, пока не изменится положение левого стикера, я так и не разобрался, в чем тут проблема



Шаг 4, добавим музыки





Заходим по ssh на нашего робота и смотрим, какие скриптовые языки тут есть.

Питона не было, а устанавливать его я смысла не видел, зато нашел перл, для нашей небольшой задачки подойдет

Далее устанавливаем 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 7777n";

while(1)
{
    my $client_socket = $socketaccept();
    my $client_address = $client_socketpeerhost(); 
    my $client_port = $client_socketpeerport();
    print "connection from $client_address:$client_portn";
    my $data = "";
    $client_socketrecv($data, 256);
    print "received data: $datan";
    my @urls = split /;/, $data;
    system("killall play > /dev/null");
    $data = "ok";
    $client_socketsend($data);
    shutdown($client_socket, 1);
    if ( $urls[0] ne "") {
        system("play -q -v 0.4 " . $urls[0] . " &");
    }
}

$socketclose();




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 — аргумент функции



Результат





Источник: Хабр / Интересные публикации

Категория: Linux

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *