понедельник, 9 января 2012 г.

Рождение робота Мити

21-го декабря я подвёл черту своему двухмесячному роботостроительству и выложил статью в Хабрахабр. Здесь я её просто повторю.


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

Как развивалось помешательство, я решил описать в статье. Получилось длинно, но может кому-нибудь будет интересно. Думаю, статья ориентирована на тех, кто ещё не практиковался в робототехнике.

Вот что получилось в результате. Видео винтажное, снималось владельцем iPhone, а они ведь затейники, ну вы знаете.




Лирика

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

Началось всё с обеда в офисе. Нас было несколько человек, и одна сотрудница спросила, есть ли у кого-нибудь хобби. Мы подумали, подумали и вдруг поняли, что хобби-то ни у кого и нет. Есть, конечно, тяга к программированию, есть занятия спортом, семьи и друзья, но так чтобы домики из спичек клеить, кораблики вырезать или марки собирать – нет, такого не оказалось. Не знаю, от жадности или другого какого чувства, но мысль об отсутствии любимого дела застряла в моей голове. Подъём, дорога на работу, работа, дорога домой, максимум часик с семьёй (у всех же дела!), сон... Ночью, видимо, происходит какой-то сброс, и наутро начинается новая итерация. Та сотрудница как будто воткнула проводок с обратной связью мне в голову. И не только мне. Пострадавших за тем обедом, как вскоре выяснилось, стало двое. Темой, интересующей нас обоих, оказалась робототехника. В детстве я был радиолюбителем, институт закончил по специальности "роботы, робототехнические системы и комплексы", сейчас я разработчик ПО. Такое хобби просто создано для меня. Где я был раньше?

В офисе мы выступили с призывом сделать роботов и провести РобоБитву, но больше желающих не нашлось. Были сочувствующие, но участников так и осталось двое. Мы решили, что каждый сделает своего робота и в назначенную дату (срок получился, примерно, два месяца), мы схлестнёмся в сражении. Чувство прекрасного и неприятие насилия заставили нас отказаться от кувалд, болгарок и прочих орудий дикарей в пользу ИК-пушки и ИК-приёмника. Хоть со временем идея РобоБитвы и перестала меня трогать, потому что теперь у меня был робот (моя прелесть, естественно) и масса планов по его развитию, надо признать, факт проведения РобоБитвы, очень подстегнул меня по срокам. Это был прекрасный мотиватор, он заставлял выискивать время и спешить.

Архитектура

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

Первоначально я предполагал, что для системы управления (в будущем мозга) робота я буду использовать платформу Arduino. Мой «противник» двигался по этому же пути. Тема была новая для нас, поэтому порывшись в интернете, мы обнаружили, что в мире Arduino есть всё: Ethernet Shield, Bluetooth Shield, Motor Shield, гироскопы, акселерометры и целая куча других сенсоров и плат сопряжения, которые могут пригодиться гикам вроде нас. Но чем больше я выискивал полезных узлов для своего робота, тем больше я убеждался в том, что это у меня уже есть. В смартфоне. У меня HTC Sensation с ОС Android 2.3.4 на борту. И там уже есть: Bluetooth, WiFi (даже WiFi роутер), камера, фонарь, огромный дисплей, звук, микрофон, microUSB, память, гироскоп, компас. И вот тут я решил, что мозг моего робота переедет в смартфон. А Arduino будет выполнять функции спинного мозга. Пусть принимает команды, исполняет их и собирает данные с сенсоров, чтобы потом передать их в мозг.

У такого архитектурного решения есть большой минус – кажется, в конце статьи мне придётся включить стоимость моего смартфона в стоимость робота, но смартфон у меня уже был, а пройти мимо плюсов, которые он мне подарил, я не смог. К тому же по работе мне была интересна тема программирования под ОС Android, и такое решение пришлось как нельзя кстати. К автономным действиям мой робот ещё не готов, это тема дальнейшего развития проекта, поэтому родился ещё один слой в управлении роботом – простая клиентская программа, которая формирует команды управления и передаёт их через TCP-сокет в Android-приложение. Такая программа может быть написана под любую платформу, лишь бы можно было установить соединение через TCP-сокет. Сейчас я написал простенькое .NET-приложение с использованием XNA. Для управления роботом я использую геймпэд от XBOX 360.

Функции

Приблизительно набросаю кто чем занят.

Функции Arduino-скетча:
  1. Установление соединения с Android-приложением.
  2. Приём и исполнение команд, полученных от Android-приложения.
  3. Приём сигналов от сенсоров робота и передача этих сигналов в Android-приложение.
Функции Android-приложения:
  1. Установление соединения с Arduino-скетчем.
  2. Установление соединения с .NET-приложением.
  3. Приём команд от .NET-приложения.
  4. Исполнение части принятых команд, не предназначенных для уровня Arduino. Например, проигрывание звуков, включение фары (вспышка фотокамеры), смена мордочек на дисплее смартфона и т.д.
  5. Передача команд в Arduino.
  6. Приём сигналов сенсоров от Arduino.
  7. Реагирование на сигналы сенсоров. Например, проигрывание звука при «попадании» выстрела из ИК-пушки в моего робота.
  8. Передача сигналов сенсоров в .NET-приложение.
Функции .NET-приложения:
  1. Установление соединения с Android-приложением.
  2. Обработка ввода (геймпэд XBOX 360).
  3. Формирование команд.
  4. Передача команд в Android-приложение.
  5. Приём сигналов сенсоров от Android-приложения.
  6. Отображение текущего состояния робота.
С программной реализацией функций больших проблем у меня не возникло, разве что для меня было новым программирование на Java (уровень Android-приложения), но это мои личные трудности. Скетчи на Arduino никаких трудностей не вызвали – очень простой язык (Wiring), вполне сносная среда разработки. С чем пришлось повозиться, так это с управлением роботом. Приложение я писал на C#, и оно пока без затей и очень простое, но алгоритмы управления роботом пришлось дорабатывать дважды – я не сразу смог добиться хорошей управляемости роботом. Но это я забегаю вперёд, напишу об этом ниже.

Мой план

Сроки я посчитал достаточно сжатыми или это я такой медленный, поэтому я составил себе следующий план:
  1. Освоение контроллера Arduino.
  2. Сборка тележки, монтаж на ней электроники.
  3. Программирование Arduino, автономное выполнение команд.
  4. Управление тележкой через USB ПК.
  5. Подключение Arduino к Android-смартфону.
  6. Передача команд от ПК смартфону.
  7. Пушка и датчики попадания.
  8. Окончательная сборка.
  9. Причёсывание, документирование.

Освоение контроллера Arduino

Первый пункт плана мне был нужен для «разогрева». Надо было понять, что такое Arduino, установить среду разработки, освоиться с новым языком, написать пару тестовых скетчей. Для экспериментов я приобрёл уже готовый набор «Матрёшка X». Прошу не воспринимать ссылку как коммерческую рекламу, но Амперка оказался очень удобным ресурсом. Там много обучающей информации, видеоуроки, форум. Наигравшись со светодиодиками, пришла пора двинуться дальше.

Сборка тележки, монтаж на ней электроники

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

В комплект платформы из электрики, кроме четырёх двигателей с редукторами, идут тумблер и разъём внешнего питания. Разъём совместим с разъёмом питания Arduino Uno и очень пригодился потом при тестировании.

Вот моё первое фото тележки:

Фото тележки

Здесь установлено пять батареек формата AA в держателе, идущем в комплекте. Как выяснилось позже, батареек для четырёх двигателей, двух сервоприводов и электроники мне стало не хватать. И тут открылась вся прелесть моей тележки. Я разжился 12-ти вольтовыми Ni-MH аккумуляторными сборками. Так вот оказалось, что вместо штатного держателя на 5 AA в тележку могут поместиться две аккумуляторные сборки по десять банок AA в каждой. Это 20 банок AA! Сборки я включил параллельно, получив 12 В и 2200 mAh. Правда, теперь пришлось тратиться на зарядное устройство для этого мини-монстра. И опять пригодился разъём внешнего питания. Его я теперь использую и для зарядки аккумулятора робота.

Фото тележки c двумя аккумуляторными сборками

Дополнительный приятный бонус платформы – штатное место для крепления сервопривода.

Единственный недостаток тележки, с которым я столкнулся, это неплотная установка колёс на валы редукторов. При сборке крепление колёс казалось надёжным, но при первых же испытаниях робота на ковре колёса стали отваливаться. Конструкция колеса не предполагала его привинчивание – просто плотное прилегание, приклеивать колёса мне не хотелось, поэтому пришлось их высверливать и закреплять на валу редуктора обычными саморезами. Благо, отверстия в валах редукторов есть.

Доработка колёс

Программирование Arduino, автономное выполнение команд

Итак, на следующем шаге я хотел добиться от платформы движения. Для этого приобрёл “Motor Shield v3” от “Freeduino.ru”. Он позволяет управлять четырьмя двигателями постоянного тока или двумя шаговыми двигателями, а также на нём установлены разъёмы для двух сервоприводов. Кроме того, motor shield поддерживает SPI. Как мне тогда показалось замечательный вариант, даже избыточный – мне было нужно управление двумя сервоприводами и только двумя двигателями постоянного тока (для левой и правой стороны передние и задние двигатели соединены параллельно). Более того, у меня получилось управление двигателями и сервоприводами, и я даже закрыл этот пункт своего плана.



Проблемы с “Motor Shield v3” начались позже. Когда я для сопряжения со смартфоном приобрёл USB Host Shield от DFRobot, у меня начались конфликты по используемым цифровым выходам Arduno. Я пробовал и обычный режим управления этим motor shield, и SPI – лучшее чего я добился, это управление двигателями и сервоприводами, но больше свободных выходов у меня не оставалось. А ведь ещё надо было управлять ИК-пушкой. Насколько я понял, проблема была чисто программная. Библиотеки, которые я использовал, взяты там же, на freeduino.ru. Датированы они декабрём 2009 года. На сайте указано, что модификация библиотеки для работы с SPI не протестирована на шаговых двигателях, но в ближайшее время, они обещают это сделать. И Бог бы с ними, с этими шаговыми двигателями, только дата библиотеки 2009 год. Похоже, проект заброшен. Я честно посмотрел исходники, вздохнул, и понял, что вникать в это мне совсем не хочется. Как-нибудь в другой раз. Я, конечно, мог обойтись только одним сервоприводом, но очень уж не хотелось себя ограничивать.

По идее, для управления двумя двигателями мне нужно четыре ноги контроллера, ещё две мне нужны для сервоприводов, одна для стрельбы из ИК-пушки и четыре для управления USB Host Shield. Итого одиннадцать ног. Нулевую и первую ноги я использовать не стал – это TX и RX последовательного порта Arduino Uno. Вообще говоря, их можно использовать, но это предприятие рискованное, насколько я понял – надо быть готовым к перепрограммированию контроллера. Поэтому я оставил эти ноги в покое. Получается, я перебрал все тринадцать ног Arduino Uno. Вот только заставить “Motor Shield v3” использовать по две ноги на двигатель или четыре ноги SPI-шины мне не удалось.

Пришлось приобрести ещё один motor shield. Производитель DFRobot. Название не особенно оригинальное: “2A Motor Shield For Arduino”. Зато он прост и для управления ему нужны только четыре цифровых выхода Arduino (два из них должны быть с ШИМ). Даже готовая библиотека не нужна. Правда, на нём нет разъёмов для сервоприводов, но это уже мелочи.

Управление тележкой через USB ПК

На этом шаге я сформулировал систему команд робота и, можно сказать, получил почти финальную версию Arduino-скетча. При соединении через USB-порт Arduino подключается как обычный serial-порт. Команды в него можно передавать любым терминальным клиентом. Поначалу я использовал Serial Monitor, входящий в IDE Arduino. Вколачивать команды быстро надоело, и для тестов я написал WinForm-приложение с тремя ползунками (для управления двигателями и горизонтальным сервоприводом), которые позволили мне проверить свои скетчи и провести первые эксперименты с управляемостью роботом.



Система команд простая: все команды пятисимвольные, причём первые два символа обозначают саму команду, а оставшиеся три символа – цифровые, определяют значение параметра. Например: LF190 – левый двигатель вперёд (left forward) со скоростью 190 (скорость задаётся от 000 до 255); HH045 – установить горизонтальный угол поворота головы (head horizontal) равным 45 градусам.

Подключение Arduino к Android-смартфону

Тут пришлось поучиться и помучиться. Сначала я думал, что подключение Arduino к Android пройдёт так же просто, как подключение к Windows. В Android-приложении получу serial-порт и буду писать в него команды для Arduino. Так запросто это сделать не получилось. Оказывается, COM-порт в Android-устройстве спрятан где-то далеко. Допускаю, что я что-то не понял – у меня не было времени на изыскания. Изучая вопрос, я нашёл проект “android-serialport-api”. Там даже есть раздел, посвящённый активации последовательного порта в телефонах HTC. И рассматриваются три модели: Dream, Magic и Hero. Моего тут нет. Что ещё меня остановило, так это то, что для активации первое, что надо сделать, это “Root your phone”. Я не рутовал свой телефон, и пока не очень-то собираюсь.

Поэтому, я пошёл по другому найденному мной, и уже изрядно протоптанному всеми пути: Android Open Accessory Development Kit. В DevGuide всё достаточно подробно описано, единственное, что мне не понравилось, так это какой-то безумный пример DemoKit, приведённый там. Пример включает в себя всё что только можно и сразу: и соединение, и определение подключения, и передачу данных, и приём, и управление несколькими светодиодами, и двигателями, и работу с джойстиком, и довольно навороченные (по крайней мере, для меня) activity в Android-приложении. Не осилив с первого захода исходный код примера, я нашёл его упрощённый вариант и всё сразу встало на свои места.

Купив и установив USB Host Shield от DFRobot, мне удалось передавать команды от моего Android-приложения в Arduino-скетч, но тут меня накрыло сразу двумя проблемами. Одна описана выше – это какой-то конфликт с моим первым motor shield (уверен, проблема в библиотеке управления motor shield от freeduino.ru). А вот вторую я так и не смог пока решить. Будет здорово, если кто-нибудь подскажет что делать. USB Host Shield является хостом в USB-соединении (извините за это умозаключение). Это значит, что питание поступает от USB Host Shield к смартфону. И мой смартфон-переросток начинает объедать и так часто страдающую недоеданием от батарейки типа Крона или пяти AA батареек тележку. Так родилась идея поставить аккумуляторы. 12 В и 2200 мАч это большое подспорье в деле питания двигателей, сервоприводов и смартфона, но мне очень хочется исключить смартфон из этой пищевой цепочки. В опциях телефона ничего найти не удалось. Похоже, программного решения без опять рутирования телефона не будет. Тогда мне оставалось только аппаратное решение проблемы. USB-кабель содержит четыре линии: питание, земля, линия передачи и линия приёма. Первая идея – перерезать питание – провалилась. После этого смартфон перестаёт определять соединения с USB хостом. Опять копаясь в интернете, я нашёл человека, решившего эту проблему. Simon Monk добился отключения зарядки своего Nexus One при подключении к USB Host Shield в аналогичной связке с Arduino. Для этого он в разрез линии питания USB-кабеля установил резистор на 1 кОм. Это сопротивление он получил эмпирически, когда определение подключения (accessory detection) уже срабатывало, а заряд телефона ещё не начинался.

Я поставил в разрез линии килоомный резистор и попробовал подключить смартфон. Подключение обнаружилось, и сразу началась зарядка аккумулятора смартфона. Тогда я поставил переменный резистор на 10 кОм. Эффект тот же. Теперь добавил последовательно ещё 10 кОм – accessory detection не произошло. И зарядка не началась. Был миг триумфа, я начал медленно понижать сопротивление переменным резистором, и на 16-ти килоомах смартфон обнаружил Arduino. Одновременно началась зарядка смартфона. Крах. Я ещё поколдовал немного, отписался Саймону в комментарии к его посту, так там последний комментарий и висит от Дмитрия и пока сдался. В конце концов, с 2200 мАч как-нибудь перезимуем.

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

Внеплановый сюрприз – помехи по питанию Arduino

Итак, я получил следующую конфигурацию: смартфон с моим тестовым приложением подключен к трём этажам плат – USB Host Shield, Motor Shield и Arduino Uno. Моё тестовое приложение на смартфоне отправляет команды тележке для вращения двигателей в разных режимах (смена скорости, направления) и поворота сервопривода на разные углы. И тут вдруг опять крах. Иногда команды выполняются, а иногда тележка ведёт себя как сумасшедшая – то крутит колёсами в разные стороны, то мотает сервоприводом, причём ничего общего с переданными командами эти припадки не имеют.

Странно было то, что раньше я с этой проблемой не сталкивался. Изучая её, я понял: в новой конфигурации питание производится от одного источника – и питание двигателей, и питание электроники. А ранее я всегда запитывал Arduino отдельным источником: или батарейкой Крона, или USB-кабелем от ПК. Эксперимент с дополнительным источником питания подтвердил мою теорию. Судя по всему, по питанию Arduino идут наводки от работающих двигателей. Я посмотрел, что об этом пишут. Люди с такой проблемой встречаются, как я понял, в мире квадрокоптероводов она есть, это мир мощных электродвигателей, и, возможно, меня затянуло в него из-за включения моих двигателей двумя параллельными парами. Ток удвоился, помехи усилились, и мою тележку потянуло к квадрокоптерам.

Я открыл тему на форуме в Амперке, но люди с подобными проблемами там не сталкивались. Мне ужасно не хотелось использовать два источника питания – это как-то странно. Я понимал, что мне достаточно поставить фильтр на вход по питанию Arduino, но моих технических способностей на это уже не хватало, да и время на дальнейший поиск уже давно закончилось. Единственное, что мне удалось найти из решений подобных проблем, здесь. Я решил рискнуть и купил DC-DC преобразователь TEN 8-1221. Входные 12В преобразователь превращает в +5В и -5В с общим контактом по 0,8А каждый. Я сделал общим -5В и получил +5В и +10В. 10В пошли на питание Arduino и через его стабилизатор на USB Host и микросхемы Motor Shield-а. А 5В я использовал для питания сервоприводов, чтобы немного разгрузить стабилизатор Arduino. Также как и раньше, всё те же 12В я подал на клеммы motor shield для внешней запитки двигателей. Но теперь я надеялся на фильтр, встроенный в DC-DC преобразователь. Мне повезло, и мои надежды оправдались. Теперь тележка прилежно исполняла все команды тестового Android-приложения.

Передача команд от ПК смартфону

Здесь, на моё счастье, всё прошло гладко. Идея была такая: для взаимодействия ПК и смартфона нужен либо внешний WiFi-роутер, либо сам HTC Sensation может выступать в роли роутера. Это удобно, тогда управлять роботом можно хоть в лесу. Я намеренно выбрал WiFi, а не Bluetooth или, например, XBee из-за своих далеко идущих планов. Для связи Android-приложение открывает серверный сокет, далее .NET приложение устанавливает соединение и передаёт команды роботу. Всё было просто.

Полезной опцией моего телефона оказалось то, что его можно перевести в режим «самолёта», при этом будут отключены все средства связи, а затем включить WiFi-роутер. Не знаю, ошибка ли это разработчиков или заложенная полезность, но мне нравится. Я могу отключить GSM, 3G, Bluetooth и при этом пользоваться WiFi. Я даже не стал делать Android-сервис, а обошёлся Android-приложением.

Пушка и датчики попадания

Тут тоже всё получилось без затей. Роль пушки выполняет ИК-светодиод TSAL4400, а для фиксации попадания я использовал фотоприёмник TSOP31236. ИК-светодиод работает на 100мА, и пиковых 200мА. Максимальный допустимый ток на цифровом выходе Arduino - 40 мА. Поэтому, рекомендую поставить транзистор, для управления ИК-светодиодом. Обвязка фотоприёмника указана в его datasheet.

Посылку ИК-сигнала (выстрел) и обработку приёма ИК-сигнала (попадание) я выполняю, естественно, в Arduino-скетче. Для этого использую библиотеку IRremote.

Для сужения пучка ИК-излучения я поместил светодиод в металлическую трубку (я использовал часть секции сломанной телескопической антенны).

Фото пушки

Окончательная сборка

К этому моменту все основные и аппаратные и программные проблемы были решены, но я умудрился найти себе ещё одни грабли. Так получилось, что до этого у меня был только один сервопривод (DF05BB с углом поворота 180 градусов). Голова моего робота должна поворачиваться в горизонтальной и вертикальной плоскости, поэтому я озаботился покупкой второго сервопривода. Точно такого же я не нашёл, но нашёл более мощный с углом поворота 360 градусов. Я подумал, прекрасный вариант для горизонтальной плоскости. Когда купил, оказалось, что я не обратил внимание на два слова в описании: "continius rotaiting". Это значит, что сервы крутятся не на 360 градусов, а просто крутятся. Можно управлять скоростью и направлением их вращения, но углом поворота управлять нельзя. Раньше я не знал о существовании таких сервоприводов. Пришлось искать другой, благо в Амперке появился к тому времени мой первый сервопривод.

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

Крепление сервоприводов

Крепление сервоприводов

Для установки моего телефона идеально подошёл держатель для HTC Sensation: HTC Z710e (Z710ECAR01). Его я покупал специально для робота. Шляпки винтов для крепления к кронштейну вертикального сервопривода получились утопленными и ничем не вредят задней стенке корпуса телефона.

Крепление держателя телефона

Свободного места под держателем телефона оказалось немного, и не всякий microUSB разъём там умещался. Поместился разъём фирменного USB-кабеля от HTC, к тому же сам кабель довольно мягкий. Пришлось его укоротить. На другой конец я поставил разъём USB-A (male) для подключения к USB Host Shield.

Теперь об ИК-пушке и ИК-приёмнике. Крепление для ствола пушки сделано из подручных средств: для этой роли прекрасно подошла деталь от полуигрушечной струбцины. Я закрепил её слева на держателе телефона, чтобы пушка не мешала наклонам головы робота и использованию "аппаратных" кнопок смартфона, если они вдруг понадобятся (кнопки находятся справа). Как я уже писал, ствол сделан из телескопической антенки, а её секции зафиксированы термоусадочной трубкой. С ИК-приёмником особо мудрствовать не стал - в таком виде он нужен мне только для проведения РобоБитвы, а затем его можно снять (вообще-то и пушку тоже). Поэтому приёмник я просто прилепил двусторонним скотчем на спине робота.

Ну и пара слов об электронике. Для монтажа DC-DC преобразователя я купил плату для прототипирования Proto Shield, заодно на ней распаял обвязку ИК-приёмника для отсекания ложных срабатываний. На неё же установил разъёмы для сервоприводов и разъём питания всей моей электроники. 10-ти вольтовый выход DC-DC преобразователя выведен непосредственно на контакты Vcc и Gnd. Т.е. разъёмом питания Arduino Uno я не пользуюсь. 5-ти вольтовый выход DC-DC преобразователя выведен на разъёмы сервоприводов. Так получилось четыре «этажа» плат. Четвёртый этаж никак не хотел помещаться в тележку, пришлось ставить небольшие проставки, чтобы приподнять верхнюю панель платформы.

Причёсывание

Для выхода в свет роботёнку требовалось лицо и, конечно, хвост. Я тот ещё компьютерный художник, поэтому под рукой у меня только Paint. Кое-как нарисовал четыре рожицы: довольную, недовольную, злую и насмерть убитую. Затем подправил программу управления для смены настроений. Кстати, попробовав и то и другое, могу с уверенностью сказать, что программировать намного проще. Хвост закрутил из медной проволоки, запихнул в термоусадочную трубку и зажал между спиной и разъёмом USB. Добавил звуки выстрела и попадания. Надо бы ещё звуки под каждое настроение.

Хвост с всё такое

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

Сначала для тех, кто не в курсе, пара слов о джойстиках. Джойстики геймпэда по крайней мере под XNA дают координаты x и y в диапазоне от -1 до +1. Точка (0, 0) соответствует центральному положению джойстика. Причём, крайние положения джойстика соответствуют окружности с радиусом равным 1.

Теперь об управлении движением. Рулевых колёс у тележки нет, поэтому поворот происходит как у гусеничной техники. Идею лучше всего объяснить на примере. Предположим, мы хотим сделать во время движения вперёд плавный поворот направо. Тогда левые колёса должны продолжать вращаться, не меняя скорости, а правые должны замедлиться. Джойстик будет в положении вперёд и вправо и вернёт координаты x и y в интервале от 0 до +1. Рассмотрим состояние джойстика как вектор с началом в точке (0, 0) и концом в (x, y). Идея заключается в том, чтобы представить модуль вектора как скорость левых двигателей, а произведение модуля на синус угла, который он образует с осью x, как скорость правых двигателей тележки. Ось x перпендикулярна направлению движения. Получается, что при углах, близких к 0 градусов (джойстик в правом положении), скорость правых двигателей будет нулевой, а если угол 90 градусов, скорость правых двигателей будет равна скорости левых.

К моменту «причёсывания» эта идея уже была воплощена. Более того, дополнительно уже был добавлен режим разворота, когда при зажиме левого триггера геймпэда и малых углах вектора с осью X работал другой алгоритм – двигатели на разных сторонах тележки вращались в разные стороны с одинаковыми скоростями, равными модулю вектора.

Но одной вещи не хватало для удобства управления. Значения скоростей по всей вышеописанной тригонометрии менялись от 0 до 1. Эти значения я пропорционально переводил в величины от 0 до 255 для задания ШИМ на двигателях. При малых значениях двигатели только гудели с разной тональностью, а затем довольно резко набирали скорость до максимума. И интуитивно это воспринималось как дискомфорт при управлении тележкой. Выход был в добавлении нелинейной зависимости. При малых значениях координаты, например x, f(x) должна быстро расти. По мере приближения x к 1 рост f(x) должен замедляться. То же самое для координаты y. Мне вполне подошла функция окружности с центром в точке (1, 0) и радиусом 1: f(x) = sqrt(2x - x^2). После добавления этого преобразования по обеим координатам управление стало менее резким и более предсказуемым.

А теперь о правом джойстике и вращении головой. Мой недочёт заключался в том, что координаты джойстика я преобразовывал в углы поворота головы пропорционально. Т.е. центральное положение джойстика соответствовало 90 градусам по горизонтали и 90 градусам по вертикали. Это направление взгляда вперёд. С вертикалью я вру, потому что я вводил программное ограничение по углу поворота по вертикали, и это было не 90 градусов, а середина от амплитуды вертикального отклонения. Но сейчас это не важно, будем считать 90 градусов, потому что мои сервоприводы поворачиваются от 0 до 180 градусов. И что получилось: при координате джойстика (1, 0) голова повёрнута вправо (0 градусов). При координате (0, 1) голова повёрнута вверх (0 градусов). Но если джойстик отклоняется не по горизонтали или вертикали, а по диагонали, голова уже не сможет добраться до нуля градусов ни по одному, ни по другому сервоприводу. Область джойстика окружность, поэтому, например, координата (1, 1) не будет доступна. Отсюда вывод: круговую область джойстика с центром в начале координат и диаметром равным 2 надо «растянуть» на квадратную область с тем же центром и стороной равной 2. Эту задачку я решил для первой половины первого квадранта (от 0 до 45 градусов), остальные решения получались отражениями. Короче говоря, получилось следующее:

x’ = sqrt(x^2 + y^2) y’ = y * x’ / x где (x’, y’) новые координаты, растянутые для квадрата, но только для первой половины первого квадранта.

Ну вот, пожалуй, все. Подправив управляемость, поехал хвалиться в офис.

Цена

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

Сначала по стоимости деталей непосредственно робота:

Дата покупки Цена, руб. Наименование
21.10.2011 2 590 Четырёхколёсная платформа
21.10.2011 590 Сервопривод
21.10.2011 1 990 Матрёшка Х (Arduino Uno + детали для прототипирования)
26.10.2011 1 200 Сервопривод и кронштейн для него
01.11.2011 0 Аккумуляторные сборки 12В, 1100мАч 2 штуки (подарили)
01.11.2011 850 Держатель автомобильный для HTC Sensation
07.11.2011 1 690 USB Host Shield
21.11.2011 690 2A Motor Shield
21.11.2011 290 Proto Shield
01.12.2011 93 ИК-приёмник TSOP3123
01.12.2011 13 ИК-светодиод TSAL4400
01.12.2011 690 Сервопривод
05.12.2011 886 DC-DC преобразователь TEN 8-1221 TRACO
весь период 1 000 Мелочёвка (флюс, провода, термоусадочные трубки, батарейки и прочее)
Итого 12 572


Вот такая сумма. Цены Московские. Правда, детали можно заказывать и в китайских интернет-магазинах. Там цены отличаются поразительно: получается в два, а то и в три раза дешевле. Но приходится долго ждать. У меня было мало времени, хотя, надо признать, я бы и не вытерпел.

Теперь что я ещё купил или уже имел и без чего робот не поедет:

Дата покупки Цена, руб. Наименование
29.10.2011 1 290 Геймпэд XBOX 360
25.11.2011 3 850 Универсально зарядное устройство IMAX B5
давно 18 900 HTC Sensation (средняя цена по Москве на 19.12.2011 по Яндекс маркету)


Планы и заключение

После двух месяцев полуночной работы, когда я прошёл всё, что описано выше, жена спросила меня: «Нет, я всё понимаю, но что ты просто машинку радиоуправляемую не купишь?».

Пропущу абзац.

Да. Пока то, что у меня есть рано называть роботом. Я это понимаю. Но я думаю, что роботом оно будет. Следующая тема, которую мне интересно поднять, это передача видео и аудио потока от смартфона к ПК. Ну и обратно.

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

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

UPD: Проект перенесён на сервис code.google.com. В семье и среди моих знакомых уже закрепилось имя робота Митя, поэтому проект так и назван: robot-mitya. Я открыл для просмотра весь исходный код. Здесь все три уровня программирования робота: скетч для Arduino, Android-приложение и Windows-приложение. В качестве системы управления версиями используется Subversion. В папке tag содержится полностью рабочий релиз версии 1.0.0. Его работоспособность я проверял "с нуля" загружая с сервера исходные коды проектов, компилируя их и выполняя на роботе. В папке Trunk, как всегда, текущая ветка проекта. Arduino-скетч написан на версии IDE arduino-0022. Версию IDE с используемыми мной библиотеками выложил в раздел downloads. При написании Android-приложения использовалась среда разработки Eclipse IDE for Java Developers версии Indigo Service Release 1 с установленным плагином анализа кода Checkstyle. Единственная поблажка, которую я себе позволил в настройках Checkstyle, это увеличение максимальной длины строки с 80 до 160 символов. Остальные настройки оставил без изменений. Для разработки Windows-приложения применялась Microsoft Visual C# 2010 Express. Для анализа качества кода использовался StyleCop. Express версия студии не поддерживает встраивания расширений, но использование StyleCop возможно, благодаря возможности его интеграции с MSBuild. Тема замечательно описана в статье StyleCop & C# Express. Удачи!