Pull to refresh

Управление компьютером без рук (гироскоп мне в темя!)

Reading time 8 min
Views 33K


В предыдущей статье я рассказал, как можно управлять компьютером при помощи глаз. Несмотря на то, что в ряде случаев отслеживание положения зрачков (eye gaze tracking) — единственный способ предоставить больному человеку возможность общаться с окружающим миром, описанная ранее система не лишена недостатков. Прежде всего, это необходимость использовать компоненты, которые трудно приобрести в России. Кроме того, человеку в очках приходится сильно ограничивать положение головы, чтобы свести к минимуму паразитные блики на поверхности очков и достичь стабильной работы системы.
А можно ли использовать что-нибудь попроще и понадёжнее, если человек способен двигать головой, но испытывает трудности при работе руками?

-= Обновление января 2019 года =-
Описываемый в статье пульт Upvel UM-510KB уже невозможно купить, но вместо него для отслеживания поворота головы можно использовать вот такую схему, собраную из Arduino Leonardo и модуля GY-521 с гироскопом/акелерометром MPU-6050.



Arduino Leonardo и GY-521 соединяются четырьмя проводами. По возможности припаяйте их.
У меня получился вот такой прототип. Естественно, по-хорошему нужно всё это облагородить/поместить в корпус.





Программа (скетч), которую нужно загрузить в Arduino, выглядит вот так:

#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
#include <Mouse.h>


MPU6050 mpu;


uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorFloat gravity;    // [x, y, z]            gravity vector
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

// для мыши
float old_mx=-200;
float old_my=-200;
float dx,dy,mx,my;


// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup()
{
  Wire.begin();
  Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties

  mpu.initialize();

  mpu.dmpInitialize();
  mpu.setDMPEnabled(true);

  packetSize = mpu.dmpGetFIFOPacketSize();
}



// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop() {

    // wait for MPU interrupt or extra packet(s) available
    while (fifoCount < packetSize)
    {
      fifoCount = mpu.getFIFOCount();
    }  

    // check for overflow (this should never happen unless our code is too inefficient)
    if ( fifoCount >= 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        fifoCount = mpu.getFIFOCount();

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else  {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

            // двигать мышь
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            
            // ypr[0] - ось X, ypr[1] - ось Y, Y - инвертировать
            mx=ypr[0] * 180/M_PI;
            my=ypr[1] * 180/M_PI;
            
            if(old_mx>-200) // это не первый запуск
            {
              if((old_mx<-100)&&(mx>100))
              {
                dx=(-180-old_mx)+(mx-180);
              }
              else if((old_mx>100)&&(mx<-100))
              {
                dx=(180-old_mx)+(180+mx);
              }
              else
              {
                dx=mx-old_mx;
              }

              dy=my-old_my;
              
              Mouse.move(2000/60*dx, -1000/30*dy);
            }
            
            old_mx=mx;
            old_my=my;
    }
}



Для компиляции скетча также необходимо скачать библиотеки I2Cdev и MPU6050. Взять их можно вот отсюда: github.com/jrowberg/i2cdevlib/tree/master/Arduino
После загрузки скетча собранное устройство действует так же, как и пульт из статьи. То есть вы меняете ориентацию устройства в пространстве, а курсор мыши на экране двигается.

-= далее — оригинал статьи=-
А можно ли использовать что-нибудь попроще и понадёжнее, если человек способен двигать головой, но испытывает трудности при работе руками?

Конечно, такие средства существуют. Прежде всего, это программы, которые используют обычную веб-камеру для контроля за поворотом головы и некоторыми другими действиями, такими как моргания глаз и движения губ (читайте про них ниже, в разделе "А стоит ли овчинка выделки?").


Кроме того, выпускаются и специализированные устройства, которые также представляют из себя камеры, следящие за маркерами, ярко светящимися в инфракрасном диапазоне. Маркеры крепят куда-нибудь в район головы, например, на оправу очков, кепку, гарнитуру. Иногда даже рекомендуют приклеить маркер на лоб.

Различные фирмы, которые ранее производили устройства такого типа, постепенно собрались под крылом компании NaturalPoint. И теперь у них на сайте можно найти устройства, которые раньше конкурировали, а теперь просто делят разные сегменты рынка. Так, например, вариант попроще (TrackIR) они предлагают для геймеров, а подороже (SmartNav) — для работы за компьютером.

И без того недешёвый SmartNav ($500) становится просто золотым, когда пытаешься приобрести его в России. Поэтому возникла идея сотворить нечто, что могло бы не хуже позиционировать курсор на экране компьютера, но при этом было бы доступнее.


Поначалу хотелось использовать тот же принцип работы: маркеры, подсветка, обработка изображения. Но приходили мысли и о прямых измерениях. Вплоть до того, чтобы приделать к голове электронный штангенциркуль (почти шутка).

Как впоследствии оказалось, такие приборы действительно существуют!

Посмотрите-ка вот на это чудо инженерной мысли — рычаг, который нужно держать ртом, и управлять им движениями головы!

Неожиданно появилась идея использовать [электронный] гироскоп. Они в последнее время стали доступны и весьма точны. Готовые устройства типа «аэромышь», правда, не получили большого распространения. Например, мышь Logitech MX Air уже снята с производства, видимо, из-за отсутствия спроса.

Существуют программы для смартфонов (как iPhone, так и Android), которые позволяют использовать их в качестве аэромыши, задействуя встроенные в них гироскопы. Но глубоко этот вопрос я не исследовал, так как интересовало, прежде всего, дешёвое решение.

Наконец в поле зрения попали пульты для мультимедия-приставок к телевизорам, также использующие встроенный гироскоп. Некоторые из них работают и с обычным компьютером, достаточно лишь вставить адаптер в USB-гнездо. Передача данных происходит по радиоканалу, то есть не требуется прямой видимости пульта, как в случае с инфракрасными приёмопередатчиками.

Пульт закрепляется на голове, и при её повороте курсор мыши на экране движется (как у Чебурашки в заголовке статьи). Остаётся только разобраться с нажатиями на кнопки мыши и виртуальной клавиатурой. Для этих целей я написал свою программу.

Сложность представляет следующий момент: пульты «засыпают» после некоторого периода бездействия, и пробуждать их нужно нажатием на кнопку, что может быть сложно для использующего их человека.



Пришлось поставить ряд экспериментов — зажимать одну из кнопок на клавиатуре и оставлять пульт в бездействии, надеясь, что нажатая кнопка не даст пульту заснуть. Причём зажимать кнопку приходилось прищепкой, а не рукой, так как рука могла передавать пульту небольшие движения. Кнопки же можно было нажимать только те, которые не используются в Windows.
Некоторые пульты победить не удалось, но в конце концов был найден пульт Upvel UM-510KB, который гарантированно не засыпает при удержании пары кнопок.



Если вскрыть этот пульт, то внутри можно найти микроконтроллер STM8L-151 от STMicroelectronics (1), трёхосевой гироскоп Invensense MPU-3050c (2) и ещё какой-то безымянный чип (3) для общения с USB- адаптером на 2.4 ГГц. Также виден инфракрасный светодиод. Он нужен, если вы хотите использовать пульт для переключения программ и регулировки громкости на телевизоре. При общении с компьютером светодиод не используется, поэтому его можно смело загораживать.

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

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

Переделка шаг за шагом


Прежде всего отмечу, что то, что у меня всё заработало, не значит, что оно заработает у вас. Если производитель, например, поменяет прошивку, то замыкание двух кнопок может оказаться бесполезным. Однако, надеюсь, что прошивку менять никто не будет за ненадобностью.

Итак, вскрываем пульт. Ковыряем отверткой, пока он не откроется, немного повредив корпус. Затем, вынимаем плату и замыкаем ему две кнопки (см. фото). Можно паяльником, зачистив плату, но я просто приклеил армированным скотчем кусочки фольги от конфет.

Подпаиваем питание от трёхвольтового стабилизированного источника питания.

По вкусу заливаем клеем, чтобы провод держался в корпусе прочно.




Замкнуть ДВЕ (!) кнопки в указанных местах. Внимание! Изначально фотография содержала ошибочно помеченные кнопки! Нужно замыкать кнопку «Set» и кнопку с четырьмя квадратиками, расположенную слева от «ОК» Укрепить провод В сборе



Как удерживать пульт на голове? Можно просто положить пульт на голову и сверху надеть шерстяную шапочку. Так я поначалу и делал. Но для долговременного использования можно пришить кармашек к какому-нибудь головному убору.


Точного положения пульта относительно головы не требуется. Если курсор мыши находится не там, где вы бы хотели, просто поворачивайте голову так, чтобы курсор начал упираться в край экрана. Это сдвинет курсор в сторону, противоположную вращению головы. Короче говоря, попробуйте, и всё станет понятно без объяснений.

А стоит ли овчинка выделки?



Уже после того, как всё было сделано, я решил для сравнения попробовать программы, которые используют обычную веб-камеру для управления мышью без рук. Каково же было моё удивление, когда все они отлично заработали! Если ничего другого под рукой нет, рекомендую ими воспользоваться.

Попробовал же я такие программы (все бесплатные):

Лично мне больше всего понравилась программа eViaCam, но это — чисто субъективное, поверхностное мнение, основанное на недолгом использовании с настройками по умолчанию, и с той веб-камерой, которая есть у меня. Вам, возможно, понравится совсем другая программа.


Чтобы оценить преимущества использования гироскопа над чисто программными решениями, я написал программу, в которой нужно перемещать курсор вслед за появляющимися на экране квадратиками. При этом курсор мыши должен остановиться (зафиксироваться) над квадратиком хотя бы на 0.2 секунды.

Показывается два квадратика: красный — куда нужно вести мышь, и зелёный — то место, куда переместится красный на следующем шаге.
Программа и её исходный код доступны на https://github.com/MastaLomaster/CStest

В результате были получены следующие времена перемещения курсора по 25 квадратикам 40x40 пикселов (косвенно более высокая скорость свидетельствует также о большей точности позиционирования):

обычная мышь в руке 28.3 секунды
пульт с гироскопом на голове 36.7 секунды
eViaCam 58,3 секунд
Head Mouse 66,3 секунды
Camera Mouse 48,4 секунды


Скорость набора текста на виртуальной клавиатуре менее показательна. Дело в том, что клавиатура требует, чтобы курсор мыши «зависал» над клавишей в течение продолжительного времени (около секунды). Иначе возможны ложные нажатия. Тем не менее, привожу данные и по набору текста. Я набирал текст «Управление компьютером без помощи рук» и это заняло у меня:

обычная мышь в руке 1 минута 15 секунд
пульт с гироскопом на голове 1 минута 23 секунды
eViaCam 1 минута 31 секунда
Head Mouse 1 минута 44 секунды
Camera Mouse 1 минута 28 секунд

Camera Mouse — мне понравилась меньше всего, из-за того, что курсор у неё не стоит на месте, а дёргается. Но скорость набора текста в ней получилась неплохая.

Использовалась программа, которую я написал для работы с устройством слежения за глазами Tobii REX, а впоследствии модифицировал для поддержки любого устройства, перемещающего курсор по экрану, в том числе аэромыши.
Сама программа и её исходный код доступны здесь: https://github.com/MastaLomaster/bkb

Иллюстрация работы программы с устройством слежения за глазами — здесь: http://www.youtube.com/watch?v=O68C4d2SNC8

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

Стоит ли всё-таки выбрасывать около тысячи рублей за пульт, блок питания, провода, да ещё время терять, если есть бесплатные программы, с которыми тоже можно работать, да ещё к голове ничего цеплять не нужно?

На мой взгляд, использование пульта даёт следующие преимущества:
  • Быстрая реакция курсора. вплоть до того, что можно играть в динамичные игры
  • Предсказуемость. То есть повернув голову на привычный угол, вы увидите, что курсор переместился на привычное место
  • Независимость от условий освещения и вообще от того, что в кадре появились новые лица/предметы.


Ну а решать, конечно, вам.

Tags:
Hubs:
+13
Comments 9
Comments Comments 9

Articles