[Практика 7] Веб-интерфейс для управления роботом
Фев 21, 2020 в 12:49  •  17 мин  •  читали 863 раза

Всем доброго времени суток.


Если Вы читали статью о цели практики, то знаете, что должно получиться в итоге. Спойлер: мы хотим собрать робота-исследователя, который будет снимать то, что происходит перед ним и управляться удаленно. Программная часть данного проекта уже почти готова, а значит настало время показать интерфейс управления роботом и рассказать как он будет работать.



Начнем!


В сердце веб приложения находится js фреймворк Vue. Для передачи данных между роботом и браузером оператора будет использоваться socket.io.



Контейнер app содержит 2 компонента:


<video-stream /> отвечает за, собственно, стрим видео с робота

<control-keyboard /> отвечает за панель управления роботом.


Эти компоненты располагаются друг за другом в одну колонку.


%lang(css)%
.app {
  position: fixed;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}


Тут описаны css стили для класса .app, который и является родителем для вышеописанных компонентов.


Теперь по порядку о компонентах:


<video-stream />



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

Если нам удалось подключиться, показывается видеопоток:

Это все, что делает этот компонент.


<control-keyboard />



Этот компонент рендерит нам клавиатурку (компонент <keys-figure />), на которой находятся 4 кнопки. Также он привязывает слушатели для событий нажатия/отжатия клавиш клавиатуры.


%lang(js)%
{
  registerListeners() {
    document.addEventListener('keydown', this.keyDownHandler);
    document.addEventListener('keyup', this.keyUpHandler);
  },
  unRegisterListeners() {
    document.removeEventListener('keydown', this.keyDownHandler);
    document.addEventListener('keyup', this.keyUpHandler);
  },
  keyUpHandler({ key }) {
    if (this.nowKey) {
      let found = keyCalls.find(x => x.key === key);
      found.onPull && found.onPull(this.socket);
      this.nowKey = null;
    }      
  },
  keyDownHandler({ key }) {
    let found = keyCalls.find(x => x.key === key);
    if (!found || this.nowKey === found.id) return;
    found.onPush && found.onPush(this.socket);
    this.nowKey = found.id;
  }
}


Еще этот компонент инициирует открытие сокет-соединения с роботом:

%lang(js)%
{
  mounted() {
    this.registerListeners();
    this.socket = socketConnect();
  },
  destroyed() {
    this.unRegisterListeners();
    this.socket.close();
  }
}

Если соединение не будет установлено, мы увидим ошибку:


Метод socketConnect содержит всего одну строку:

%lang(js)%
import io from 'socket.io-client';

function socketConnect() {
  return io('http://192.168.0.108:8765');
}

export { socketConnect };


Вам наверное интересно что за keyCalls я использовал. Это просто массив вот таких объектов:

%lang(js)%
{
  key: 'ArrowUp',
  onPush: (socket) => {
    go(socket, 'forward');
  },
  onPull: (socket) => {
    stop(socket);
  },
  id: 'up'
}


key - это название клавиши, на которую нажали или которую отпустили. Два метода говорят нам что делать в соответствующем случае и поле id для того, чтобы можно было гарантировать уникальность объекта (на самом деле еще для кое чего).


Мы хотим, чтобы при нажатии кнопки и удержании onPush сработал только один раз, также мы хотим знать на какую кнопку мы сейчас нажали. Для этого существует переменная nowKey, куда и записывается id объекта. Потом мы передает проп color-key в компонент <keys-figure />, чтобы подсветить нажатую клавишу.



Примерно так это работает:

При нажатии и отпускании кнопок, вызываются методы onPush, onPull, которые в свою очередь вызывают один из этих методов:

%lang(js)%
function go(socket, direction) {
  socket.emit('go', direction);
}

function stop(socket) {
  socket.emit('stop', '');
}

function turn(socket, direction) {
  socket.emit('turn', direction);
}

export { go, stop, turn };

Данные отправляются роботу и он начинает или останавливает свое движение.


Работает как нажатие клавиш на клавиатуре, так и нажатие на нарисованные кнопки мышкой.


Это все, что я хотел рассказать про веб-приложение для управления нашим роботом.


Спасибо за внимание.


ps. Приложение пока в разработке и, скорее всего, будет обрастать новыми фичами, из-за чего могут быть несоответствия между написанным здесь и кодом на гитхабе. Хотя, надеюсь, логика в целом не изменится.



Копирование материалов допускается только с разрешения автора (vladivanov.dev@gmail.com) в письменной форме.
(Copying of materials is allowed only with the written permission of the author)
Похожие статьи