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-скетча:
В комплект платформы из электрики, кроме четырёх двигателей с редукторами, идут тумблер и разъём внешнего питания. Разъём совместим с разъёмом питания Arduino Uno и очень пригодился потом при тестировании.
Вот моё первое фото тележки:
Здесь установлено пять батареек формата AA в держателе, идущем в комплекте. Как выяснилось позже, батареек для четырёх двигателей, двух сервоприводов и электроники мне стало не хватать. И тут открылась вся прелесть моей тележки. Я разжился 12-ти вольтовыми Ni-MH аккумуляторными сборками. Так вот оказалось, что вместо штатного держателя на 5 AA в тележку могут поместиться две аккумуляторные сборки по десять банок AA в каждой. Это 20 банок AA! Сборки я включил параллельно, получив 12 В и 2200 mAh. Правда, теперь пришлось тратиться на зарядное устройство для этого мини-монстра. И опять пригодился разъём внешнего питания. Его я теперь использую и для зарядки аккумулятора робота.
Дополнительный приятный бонус платформы – штатное место для крепления сервопривода.
Единственный недостаток тележки, с которым я столкнулся, это неплотная установка колёс на валы редукторов. При сборке крепление колёс казалось надёжным, но при первых же испытаниях робота на ковре колёса стали отваливаться. Конструкция колеса не предполагала его привинчивание – просто плотное прилегание, приклеивать колёса мне не хотелось, поэтому пришлось их высверливать и закреплять на валу редуктора обычными саморезами. Благо, отверстия в валах редукторов есть.
Проблемы с “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 (два из них должны быть с ШИМ). Даже готовая библиотека не нужна. Правда, на нём нет разъёмов для сервоприводов, но это уже мелочи.
Система команд простая: все команды пятисимвольные, причём первые два символа обозначают саму команду, а оставшиеся три символа – цифровые, определяют значение параметра. Например: LF190 – левый двигатель вперёд (left forward) со скоростью 190 (скорость задаётся от 000 до 255); HH045 – установить горизонтальный угол поворота головы (head horizontal) равным 45 градусам.
Поэтому, я пошёл по другому найденному мной, и уже изрядно протоптанному всеми пути: 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-кабелем от ПК. Эксперимент с дополнительным источником питания подтвердил мою теорию. Судя по всему, по питанию 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-роутер. Не знаю, ошибка ли это разработчиков или заложенная полезность, но мне нравится. Я могу отключить GSM, 3G, Bluetooth и при этом пользоваться WiFi. Я даже не стал делать Android-сервис, а обошёлся Android-приложением.
Посылку ИК-сигнала (выстрел) и обработку приёма ИК-сигнала (попадание) я выполняю, естественно, в Arduino-скетче. Для этого использую библиотеку IRremote.
Для сужения пучка ИК-излучения я поместил светодиод в металлическую трубку (я использовал часть секции сломанной телескопической антенны).
Следующий шаг - установка вертикального сервопривода и крепления для телефона. Как я уже писал, для крепления горизонтального привода на тележке уже есть штатное установочное место, а для вертикального я приобрёл специальный кронштейн.
Для установки моего телефона идеально подошёл держатель для 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 преобразователя выведен на разъёмы сервоприводов. Так получилось четыре «этажа» плат. Четвёртый этаж никак не хотел помещаться в тележку, пришлось ставить небольшие проставки, чтобы приподнять верхнюю панель платформы.
В принципе, с этим можно было уже и выходить. Но мне не давала покоя ещё одна вещь – управляемость роботом. Реализация вроде бы работоспособная, но что-то было не так. По традиции левый джойстик геймпэда управляет движением. Правый – обзором, т.е. вращением головы. Недочёты в управлении были и там и там.
Сначала для тех, кто не в курсе, пара слов о джойстиках. Джойстики геймпэда по крайней мере под 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’) новые координаты, растянутые для квадрата, но только для первой половины первого квадранта.
Ну вот, пожалуй, все. Подправив управляемость, поехал хвалиться в офис.
Сначала по стоимости деталей непосредственно робота:
Вот такая сумма. Цены Московские. Правда, детали можно заказывать и в китайских интернет-магазинах. Там цены отличаются поразительно: получается в два, а то и в три раза дешевле. Но приходится долго ждать. У меня было мало времени, хотя, надо признать, я бы и не вытерпел.
Теперь что я ещё купил или уже имел и без чего робот не поедет:
Пропущу абзац.
Да. Пока то, что у меня есть рано называть роботом. Я это понимаю. Но я думаю, что роботом оно будет. Следующая тема, которую мне интересно поднять, это передача видео и аудио потока от смартфона к ПК. Ну и обратно.
Что хотелось бы сделать дальше, это развивать автономность робота. Сейчас, когда готова мобильная платформа, на «плечах» робота довольно мощная «голова» с языком программирования высокого уровня, плюс можно найти уже готовые открытые алгоритмы распознавания звуков, образов, лиц, перспективы открываются головокружительные. Боюсь даже заглядывать так далеко. Если получится интересно, буду писать дальше.
Надеюсь, мой опыт, набитые мной шишки и подробная граблекарта кому-нибудь послужат.
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. Удачи!
Не думал, что так меня скрутит, но вот случился довольно острый приступ робототехники. Ну и как всякий уважающий себя пострадавший, я постараюсь заразить как можно больше людей.
Как развивалось помешательство, я решил описать в статье. Получилось длинно, но может кому-нибудь будет интересно. Думаю, статья ориентирована на тех, кто ещё не практиковался в робототехнике.
Вот что получилось в результате. Видео винтажное, снималось владельцем 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-скетча:
- Установление соединения с Android-приложением.
- Приём и исполнение команд, полученных от Android-приложения.
- Приём сигналов от сенсоров робота и передача этих сигналов в Android-приложение.
- Установление соединения с Arduino-скетчем.
- Установление соединения с .NET-приложением.
- Приём команд от .NET-приложения.
- Исполнение части принятых команд, не предназначенных для уровня Arduino. Например, проигрывание звуков, включение фары (вспышка фотокамеры), смена мордочек на дисплее смартфона и т.д.
- Передача команд в Arduino.
- Приём сигналов сенсоров от Arduino.
- Реагирование на сигналы сенсоров. Например, проигрывание звука при «попадании» выстрела из ИК-пушки в моего робота.
- Передача сигналов сенсоров в .NET-приложение.
- Установление соединения с Android-приложением.
- Обработка ввода (геймпэд XBOX 360).
- Формирование команд.
- Передача команд в Android-приложение.
- Приём сигналов сенсоров от Android-приложения.
- Отображение текущего состояния робота.
Мой план
Сроки я посчитал достаточно сжатыми или это я такой медленный, поэтому я составил себе следующий план:- Освоение контроллера Arduino.
- Сборка тележки, монтаж на ней электроники.
- Программирование Arduino, автономное выполнение команд.
- Управление тележкой через USB ПК.
- Подключение Arduino к Android-смартфону.
- Передача команд от ПК смартфону.
- Пушка и датчики попадания.
- Окончательная сборка.
- Причёсывание, документирование.
Освоение контроллера Arduino
Первый пункт плана мне был нужен для «разогрева». Надо было понять, что такое Arduino, установить среду разработки, освоиться с новым языком, написать пару тестовых скетчей. Для экспериментов я приобрёл уже готовый набор «Матрёшка X». Прошу не воспринимать ссылку как коммерческую рекламу, но Амперка оказался очень удобным ресурсом. Там много обучающей информации, видеоуроки, форум. Наигравшись со светодиодиками, пришла пора двинуться дальше.Сборка тележки, монтаж на ней электроники
Что я хотел от мобильной платформы робота: чтобы она была достаточно маленькой для удобного маневрирования в квартире, чтобы она была резвой и чтобы встреченные ей ковры, порожки и провода от удлинителей не были для неё непроходимым препятствием. Ну и ещё, естественно, должно быть достаточно места для электроники Arduino и смартфона. Подо всё это замечательно подошла вот такая четырёхколёсная платформа.В комплект платформы из электрики, кроме четырёх двигателей с редукторами, идут тумблер и разъём внешнего питания. Разъём совместим с разъёмом питания Arduino Uno и очень пригодился потом при тестировании.
Вот моё первое фото тележки:
Здесь установлено пять батареек формата AA в держателе, идущем в комплекте. Как выяснилось позже, батареек для четырёх двигателей, двух сервоприводов и электроники мне стало не хватать. И тут открылась вся прелесть моей тележки. Я разжился 12-ти вольтовыми Ni-MH аккумуляторными сборками. Так вот оказалось, что вместо штатного держателя на 5 AA в тележку могут поместиться две аккумуляторные сборки по десять банок AA в каждой. Это 20 банок AA! Сборки я включил параллельно, получив 12 В и 2200 mAh. Правда, теперь пришлось тратиться на зарядное устройство для этого мини-монстра. И опять пригодился разъём внешнего питания. Его я теперь использую и для зарядки аккумулятора робота.
Дополнительный приятный бонус платформы – штатное место для крепления сервопривода.
Единственный недостаток тележки, с которым я столкнулся, это неплотная установка колёс на валы редукторов. При сборке крепление колёс казалось надёжным, но при первых же испытаниях робота на ковре колёса стали отваливаться. Конструкция колеса не предполагала его привинчивание – просто плотное прилегание, приклеивать колёса мне не хотелось, поэтому пришлось их высверливать и закреплять на валу редуктора обычными саморезами. Благо, отверстия в валах редукторов есть.
Программирование 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. Удачи!
Дмитрий Дзаховв
Отличная статья! У меня появилось несколько вопросов:
ОтветитьУдалить1) Расскажите, как -5В преобразователя превратить в +10В.
2) Где достать такие чудесные акумуляторные сборки как у вас? Посмотрел довольно много магазинов тематики радиоуправляемых разных игрушек, но настолько удачных по толщине и мощности не нашел.
3) Как такие акумуляторные сборки заряжаются? Видел множество зарядников на тех же сайтах, но детально не разобрался.
Спасибо.
Дмитрий, по Вашим вопросам:
ОтветитьУдалить1) Тут всё просто: выход DC-DC преобразователя - три вывода. По его datasheet-у это -5В, Общий и +5В. Но никто не запрещает нам назвать общим -5В :) Тогда мы получим 3 вывода: Общий, +5В и +10В. Это просто вопрос терминологии.
2) Да, как мне достались эти сборки, это чудо. Просто коллега на работе пытался избавиться от хлама и спросил не надо ли кому. И тут появляюсь я... Найти у нас в магазинах это чудо я тоже не смог. Есть два варианта: самостоятельно собрать сборку из AA аккумуляторов (просто 10 последовательно соединённых банки) или попробуйте тут набрать Ni-Mh 12V. Будет много предложений и даже куда более мощных чем у меня.
3) Я покупал здесь. И это очень дорого! Причём, у этой модели зарядки нет даже своего источника питания - подключаю к блоку питания компьютера (12В). Прелесть его в мощности (хватает на две мои сборки, включённые параллельно) и универсальности (заряжает всё, даже автомобильный свинцовый). Друзья воодушевлённые моей находкой заказали похожий, но со своим блоком питания у китайцев. Мягко говоря, сильно дешевле, но ждать надо.
Здравствуйте. Прошу прошения за беспокойство, но мне по настоящему нужна помощь =(
ОтветитьУдалитьНа Амперке Вы абсолютно правильно сказали, что причина была в использовании новой версии IDE. Но проблема уже не в этом.
У меня стоит такая задача: передать данные с Андроида на Ардуино. На вскидку — ничего сложного вроде, но я уже вторую ночь не могу сдвинуться с места.
Пытался использовать разные примеры, вытягивал куски кода с Google ADK DemoKit и пытался Ваши исходники использовать.
Но до Ардуино ничего не доходит. Скорее всего причина в том что у меня практически нету опыта в использовании подобных технологий и в принципе понимания работы COM-портов. весь мой опыт как разработчика относиться исключительно к в веб программированию (php, javascript).
Вот то что я пытался:
1. Исходники для андроида. http://dl.dropbox.com/u/28146021/RollerTest.rar
2. Исходники для ардуино. http://dl.dropbox.com/u/28146021/roller.rar
Насколько я понял, не проходит условие
if (getLastNonConfigurationInstance() != null) {
mUsbAccessory = (UsbAccessory) getLastNonConfigurationInstance();
mOpenAccessory.open(mUsbAccessory);
onUsbAtached();
} else {
}
Но как исправить не пойму.
Если вам не сложно, можете, пожалуйста, прислать самый элементарный рабочий пример пересылки данных с Андроида (любую строку) на ардуино, где через Serial.println передавать полученую команду от Андроида. Мне главное переступить через этот шаг, а дальше алгоритм работы я сумею написать сам.
И еше, попутный вопрос:
Вы используете для отладки
Logger.d(...);
Как просмотреть все лог записи? То есть после того как андроид отключен от ардуино, нужно подключить его обратно к компьютеру и как-то через adb logcat просмотреть записи?
Заранее благодарен.
Попробуйте ещё взять библиотеки Arduino именно из моего проекта (http://code.google.com/p/robot-mitya/downloads/list).
ОтветитьУдалитьНу это пока так, попытка. Сегодня вечером, завтра я поковыряюсь подробнее в Вашем вопросе.
Только что заливал полностью ваш сорс для Андроида. И все равно ничего.
УдалитьКстати, только что залил Google DemoKit. По идеи он же должен передавать данные через usb на Arduino в любом случае,а там я уже просто их слушаю. Но все равно ничего не выводилось. Начинаю сколняться к тому, что скетч для Arduino написан не правильно.
ОтветитьУдалитьМожет быть ещё и аппаратная проблема, но давайте попробуем по порядку: сначала простой, работающий у меня код, потом ищем "пять отличий" у Вас. Если код идентичен, буден разбираться с железом.
Удалитьу меня Android version 2.3.5
УдалитьHTC wildfire S A510e
Arduino Uno + Usb Host Shiled (http://odduino.shopium.ua/products/adkusbhost/)
Ссылки на исходники я кидал в сообщении выше.
Уфф. Ну вопрос разрешился. Hlx опубликовал вопрос на Хабре. И вот ответ.
УдалитьЯ, в свою очередь, перевёл Митю на Arduino IDE 1.0 и всё работает. Доработанные библиотеки положил в downloads проекта. Скетч не менялся, разве что теперь сменил расширение файл (IDE 1.0 затребовала).
Hlx, спасибо!
Здравствуйте Дмитрий, после прочтения вашей публикации "Android +
ОтветитьУдалитьArduino + 4 колеса" на http://habrahabr.ru, я действительно
заразился тематикой связанной с робото-техникой. Статья меня очень
воодушевила, даже можно сказать зацепила. Я решил действовать по
вашему плану, сначала решили заказать Матрёшку или нечто подобное ей,
но оказалось это не так уж и легко, в наличии пока наборов нет, ну я
оставил заявочку осталось только ждать. Пока буду ждать появление и
доставку набора решил, более углубиться в интерфейсную часть
взаимодействия Android (Планшет acer) и Arduino. Хочу попробовать
(научиться) писать простенькие приложения для Android. После того как
у меня появится Arduino я первым делом буду пробовать по средствам
планшетника выполнять элементарные операции (включить-выключить
светодиод, научиться управлять сервоприводами и т.д.). Апогеем всего
задуманного хочу получить в итоге некое устройство (скорее всего
машинку) с камерой ( для просмотра картинки от первого лица на экране
планшета), управляемую при помощи планшетника (по средствам WiFi либо
Bluetooth). Вот такая вот у меня идея. Как думаете это вообще реально
?
И может Вы посоветуете с чего начать изучение написания приложений под
Android. И не могли бы поделиться материалами (примерами,
взаимодействия Arduina и Androida (Передача команд в Arduino. Приём
сигналов сенсоров от Arduino )).
Алексей, здравствуйте!
УдалитьПо переписке в почте, я знаю, что Вы Алексей ;)
Информации по сопряжению Android и Arduino, действительно, не так уж и много в сети. Вчера столкнулся с вопросом на эту же тему на форуме Амперки. Это Hlx (см. выше) - я тоже попросил его перебраться сюда, давайте учиться вместе.
По поводу Ваших вопросов, начну с конца. Я не встречал ни одного проекта, где передача видео осуществлялась бы по Bluetooth. Не хватает пропускной способности канала. Это накладывает ограничения на архитектуру. Как вариант, поместить устройство с Android-ом на машинку (как поступил я). Второй вариант, о котором я недавно прочитал, впихнуть роутер с Линуксом на машинку. По-моему, замечательная идея! Такое решение обойдётся дешевле Android-устройства, а само Android-устройство можно приберечь для пульта управления. Мой вариант хорош только наличием уже встроенных "возможностей" в гаджет (камеры, дисплей, звук, гироскоп и т.д.). Такое решение прощё программно развивать, а мне это ближе. Выбирать Вам, наверняка ещё вариант придумаете.
Что читал я: обошлось только книжкой "Hello, Android. Introducing Google's Mobile Development Platform" Ed Burnette (в электронке она вполне доступна). Очень понравился ресурс developer.android.com. В разделе Dev Guide подробно разобраны типовые задачки для начинающих. Потом, когда хочется большего, здесь информация как-то резко обрывается и начинается Google. Почитываю форум на GoogleGroups, но, ответов больше находил на Stack Overflow.
Начинал изучение Андройда (считаю, я и сейчас на этой стадии :) ) с сугубо функциональных (практических) задач: управления несколькими активити, диалог редактирования опций приложения, организация меню, вёрстка в layout, вывод сообщений (алертов). И обязательно поднял нефункциональные задачи: интеграция с SVN, тестирование (JUnit Test) и статический анализатор кода (ну или типа того - CheckStyle). Без этого я уже как-то не могу. Очень рекомендую, если Вы уже не пользуетесь.
Ну a по поводу взаимодействия Android-Arduino, завтра-послезавтра сооружу простой пример (на сколько смогу), работающий у меня. Посмотрим, что получится.
По Bluetooth... Посмотрел Википедию. Можно, оказывается, передавать видео. Есть даже профиль такой в стандарте - Video Distribution Profile (VDP). Но это, как я понял, экзотика.
УдалитьВот еще вопрос:
ОтветитьУдалитькак лучше всего от Android передать данные на Arduino так, что бы в одном пакете предать несколько значений? К примеру мне нужно передать угол ( 2 цифры ) и направление ( 1 или 0 ).
В голову лезет что то из серии:
sendCommand("12.1");
А на Arduino уже как нибудь разбить строку по точке и получить массив из двух значений: 12 и 1. Только я не знаю как на Arduino это сделать :)
Может есть лучше вариант?
Я работаю со строковыми командами. Посмотрите мой скетч. Команды такого вида: "LF123" (Left Forward Speed=123). Приходится парсить в скетче, но это очень удобно, т.к. в тестах я передаю команды или непосредственными значениями (строками), или через serial-порт (в этом случае для тестирования мне достаточно Serial Monitor-а).
УдалитьВопрос по поводу String to Int;
ОтветитьУдалитьКак перевести строку в число? вроде элементарно но не получается
Вот кусок скетча и что я вижу, когда слушаю ком порт
http://ybex.com/d/cpagnommte8w0y3tssecytn2tkouw6brbxuujgej.html
У меня в скетче примерно так:
Удалитьint angleValue = command[1] - '0'; // единицы (самый младдший разряд)
angleValue += 10 * (command[0] - '0'); // десятки
Например, такое выражение: '8' - '0' вернёт целое значение 8.
Это если Вы уверены, что разрядность всегда два знака. Если не уверены, то в цикле наращивать значение, начиная с последнего разряда и наращивая десятки умножением на 10 на каждой итерации.
А вообще надо посмотреть что есть в Си для преобразования. У меня просто были только положительные целые всегда трёхзначные числа.
Вопрос про скорость передачи данных:
ОтветитьУдалитьС какой скоростью Androdi передает данные на Arduino? и где это можно менять?
Наверняка зависит от шилда. Мой Usb Host Shield работает на хост-контроллере MAX3421E. Он поддерживает low-speed и fast-speed спецификации USB 2.0.
УдалитьLow-speed, 10—1500 Кбит/c (клавиатуры, мыши, джойстики)
Full-speed, 0,5—12 Мбит/с (аудио-, видеоустройства)
В USB 2.0 есть ещё Hi-speed (25—480 Мбит/с), но она не поддерживается. Думаю, и Ардуино не потянет. Памяти-то кот наплакал.
а как менять скорость? где нибудь есть документация по этому? или только исходники читать и разбираться?
УдалитьВот это не знаю. Думаю, шилд работает на максимальной скорости. А зачем её менять? Ну и пусть работает. :)
УдалитьВопрос про передачу данных:
ОтветитьУдалитьУ меня данные предаются при изменении ориентации телефона, что происходит довольно часто и весь GUI просто зависает. Как решить проблему?
Не совсем понял вопрос...
УдалитьИзменение ориентации вообще неудобный момент очень. При этом может даже уничтожаться активити и создаваться новая. Надо полностью восстанавливать GUI. Это неудобно, поэтому у себя в Android-приложении я возможность смены ориентации отключил программно.
А вообще обрабатывать данные старайтесь в другом потоке (thread, точнее), не в потоке GUI.
Так мне просто нужно передавать значение углов наклона. Вот как раз и передаю их при смене ориентации. А с Thread еше ни разу не работал (
УдалитьА... Я думал речь идёт об ориентации дисплея: портрет или пейзаж. А это углы гироскопа, видимо... Ну надо бы thread поднимать. Обработка данных в основном потоке это зло.
УдалитьИ еще вопрос про передачу данных:
ОтветитьУдалитьДопустим логика такая:
С Андроида шлются данные постоянно, а на Ардуино в зависимости от обработки полученных данных, выполняются функция delay(x), где x - рассчитанность время. Проблема в том, что с Андроида данные шлются постоянно, и после того как на Ардуино выполнилась задержка ( delay() ) опять считываются данные, которые были высланы ранее,а не те, которые высылаются сейчас. Вот я изобразил на картинке:
Тут смотреть
В скетче Вы работаете с потоком ввода и прыгать по нему не получится (насколько мне известно). Могу предложить только прочитать последовательно всё что накопилось после паузы, и выполнить только последнюю команду.
ОтветитьУдалитьпросто проблема в том что я не могу найти документацию по библиотеке хоть какую нибудь. А чтобы решить проблемы нужно после задержки очищать ком порт. А как это сделать я не знаю (
УдалитьА почему Вы не можете просто "вычитать" всё из буфера? Пока он не опустеет. Там так много набирается команд? И можно повторяющиеся команды не отправлять.
УдалитьИ ещё вопрос. А нельзя ли обойтись без задержек? Посмотрите в сторону прерываний, например. Я правда эту тему не поднимал в Ардуино. Но знаю что они есть. Просто задержка останавливает вообще всю жизнь в скетче. Если у Вас нет сенсоров, тогда ладно, а иначе обработка их значений тоже приостанавливается.
Ну в принципе мне любое работающее решение подойдет, просто я не знаю как сделать. В интернете ну вообще ничего не нашел. Читал исходники - тоже не особо понятно. Два места только заинтересовало там:
УдалитьРаз
Два
Так что если Вы знаете как эту проблему решить, я буду очень рад и признателен :)
"Раз" точно отпадает. Это освобождение ресурсов вообще. "Два" тоже по-моему не то. Я предлагаю Вам делать
Удалитьadk.RcvData(&bufferLength, buffer);
до тех пор, пока не получите пустой буфер. Затем просто выполните последнюю команду.
Кстати часто замечал, что используют proccessing. Там вместо loop() используют draw()
ОтветитьУдалитьЧто это такое и в чем разница?
proccessing это же вроде canvas/svg библиотека для JS))
С языком Processing я совсем не знаком. Единственное что знаю, что он ориентирован на графический интерфейс, поэтому закономерно, что есть функция, вызывающаяся для перерисовки интерфейса (draw). Она вызывается, наверняка, автоматически, поэтому на неё и навешивают какие-то операции. Не уверен насколько это правильно. Например, во фреймворке .NET XNA есть два таких метода: Draw и Update. Draw предназначен для перерисовки экрана, а Update для обработки ввода и расчётов.
УдалитьКупил вчера MotorShield от DFROBOT
ОтветитьУдалитьЧитал мануал и смотрел ваш пример, но мои моторы как то с непонятной скоростью крутятся)
значение скорости передаваемой от 0 до 255? 255 - Это максимальная?
как то медленно крутит..
http://robocraft.ru/shop/index.php?route=product/product&product_id=61
в спецификации написано 85 об / мин. А у меня где то 30
Всё верно, от 0 до 255, 255 - максимальная скорость. Судя по спецификации на микро мотор-редуктор, максимальную скорость он разовьёт при напряжении 9В. Проверьте без мотор шилда на батарейке крона.
УдалитьА по мотор шилду есть один нюанс, на всякий случай озвучу. На нём есть клемник для внешнего питания двигателей и джампер. Джампер определяет используется ли внешнее питание или питание Ардуино (Vcc). Так что для двигателей можно поставить ещё один источник на 9В. Хотя предложение ужасное, я понимаю.
А вообще очень уж больше передаточное число у редуктора. Может Вам больше подойдёт такой мотор-редуктор?
может и лучше, но мне уже деваться некуда(
Удалитьклейма стоит на питание моторов от Arduino.
у меня передаточной число 100:1 или 150:1 я не помню какой мне прислали, а на моторчике никакой маркировки нету(
крутит медленно =\
И от Кроны медленно? Просто чтобы исключить возможные проблемы с ПО и шилдом.
УдалитьИ вот ещё фантастическая идея :)
Если бы я был производителем нескольких микромотор-редукторов, отличающихся только передаточным числом в редукторе, я бы делал их унифицированными. Может можно перебрать редуктор и выкинуть какую-нибудь звёздочку? Судя по картинкам, может и получиться...