Четвероногий робот на базе Arduino. Обзор готовых каркасов для создания роботов на Arduino

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

Давай с чего-нибудь начнем? Главный вопрос - выбор контроллера. Существует множество ревизий Arduino, а также сторонних клонов, построенных на основе этих версий. Вот, пожалуй, два самых интересных для нас класса:

  • Arduino Uno - лучший выбор новичка, самая простая, бюджетная и распространенная плата. В основе - чип ATmega328 с тактовой частотой в 16 МГц, 32 Кб флеш-памяти, 2 Кб ОЗУ и 1 Кб EEPROM. В Uno 14 цифровых входов/выходов, которые могут использоваться для управления сенсорами и сервоприводами и другими устройствами;
  • Arduino Mega / Mega 2560 - плата, которая подойдет в случае, когда ты заранее знаешь, что проект будет сложным. Главное отличие - большее количество входов/выходов (48 в Mega, 54 в Mega 2560). Также тут намного больше памяти: 8 Кб ОЗУ, 4 Кб EEPROM, а флеш-памяти 128 и 256 Кб (в Mega и Mega 2560 соответственно). Между собой платы также отличаются чипом, скоростью USB и некоторыми другими характеристиками.

Разумеется, еще есть Arduino Pro, Arduino LilyPad и многие другие. Но сейчас давай остановимся на первых двух моделях. В нашем случае все довольно просто: Mega нужна для робота с большим количеством ног.

Первый код

Для начала установим Arduino IDE (arduino.cc) - это кросс-платформенная бесплатная среда разработки. Теперь, если мы подключим наш Arduino, мы сможем попробовать написать первый код на самом простом примере: программе мигания светодиодом. На большинстве Arduino-контроллеров он есть и подключен к пину 13. Кстати, в мире Arduino программы принято называть скетчами. Вот текст скетча с комментариями:

// Дадим этому пину имя LED: const int LED = 13; void setup() { // Инициализация цифрового пина // для вывода: pinMode(LED, OUTPUT); } void loop() { // Подать уровень логической единицы // на пин 13 (зажечь светодиод): digitalWrite(LED, HIGH); // Приостановить выполнение скетча // на секунду: delay(1000); // Подать уровень логического нуля // на пин 13 (потушить светодиод): digitalWrite(LED, LOW); // Снова приостановить выполнение // скетча на секунду: delay(1000); }

Обрати внимание на функции setup и loop. Они должны присутствовать в любом Arduino-скетче. Setup вызывается единожды при включении или после перезапуска контроллера. Если хочешь, чтобы код выполнялся только один раз, его следует размещать именно здесь. Чаще всего это всевозможные процедуры инициализации чего-либо. Наш скетч не исключение: цифровые пины Arduino могут работать и как входы, и как выходы. В функции setup мы говорим, что пин 13 будет работать как цифровой выход контроллера.

После того как функция setup завершит свою работу, автоматически запускается замкнутый цикл, внутри которого будет вызываться функция loop. От нас требуется написать, что мы хотим там выполнять. А мы хотим подать на пин 13 уровень логической единицы (5 В), то есть зажечь светодиод, затем подождать одну секунду (1000 в миллисекундах), потом подать уровень логического нуля (0 В) и опять подождать одну секунду. Следующий вызов loop все повторит.

Теперь «заливаем» наш скетч в контроллер. Нет, нам не понадобится программатор. Контроллеры Arduino, кроме наших скетчей, содержат специальную программу - bootloader, которая, в частности, управляет загрузкой кода из компьютера. Так что для заливки скетча нам понадобится только USB-кабель и пункт меню File → Upload (Ctrl + U) в Arduino IDE.

Ключевой вопрос

А сколько, собственно, нам нужно ног? Определимся во множестве конфигураций шагающих роботов. По количеству ног:

  • biped - двуногий (прототип - человек);
  • quadruped - четвероногий (прототип - большинство млекопитающих животных);
  • hexapod - шестиногий (прототип - большинство насекомых);
  • octopod - восьминогий (прототип - пауки, скорпионы, крабы и другие членистоногие).

Кроме количества ног, важна и конфигурация каждой. Главной характеристикой ноги является количество степеней свободы, или dimensions of freedom (DOF). Степень свободы - это способность поворачиваться или изгибаться вокруг одной оси (реже - поступательно двигаться вдоль нее). Очевидно, что если степень свободы одна, то на такой ноге далеко не уйдешь. Ноги с двумя степенями свободы (2DOF) уже позволяют двигаться многоногим роботам, хотя 2DOF дает возможность свободно перемещать кончик ноги только в одной плоскости. А 3DOF-нога перемещает «стопу» в 3D-пространстве (если, конечно, не все три оси параллельны). Есть и 4DOF-ноги, которые просто увеличивают гибкость и диапазон перемещения ноги. У насекомых чаще всего 4DOF-лапы.

Что это значит для нас? В дешевых любительских роботах каждую степень свободы реализует один двигатель, точнее, сервопривод, или серв. Конфигурация ног однозначно определяет, сколько таких сервов нужно. Так, 3DOF-гексапод потребует 18 сервов, а 4DOF-паук - уже 32. Не пугайся количества, маленькие сервоприводы, используемые в любительских радиоуправляемых моделях, очень дешевы. В интернет-магазинах их можно найти по запросу micro servo.

Чтобы программировать сервоприводы, достаточно знать, что в них уже есть контроллер, который делает основную работу. И все, что нужно, - подавать питание и цифровой сигнал, сообщающий контроллеру, в какую позицию мы хотим повернуть вал привода. Об их конструкции легко найти информацию. Протокол у них самый простой из всех цифровых протоколов связи: широтно-импульсная модуляция - ШИМ (PWM на английском). У всех простых сервов есть разъем с тремя контактами: земля, +5 В (вольтаж может отличаться в зависимости от размера и мощности) и сигнальный вход. Arduino-контроллеры могут двумя различными способами генерировать такой сигнал. Первый - аппаратный PWM, который сам чип умеет выдавать на нескольких из своих цифровых I/O-пинов. Второй - программный. Программный позволяет получить одновременно больше различных PWM-сигналов, чем аппаратный. Для него под Arduino предоставляется удобная обертка - библиотека Servo. Она позволяет использовать одновременно 12 сервоприводов на большинстве малогабаритных контроллеров (Uno, Due, Nano) и 48 сервоприводов на Arduino Mega и ему подобных. Сигнальный контакт серва подключается к цифровому выводу Arduino. Земля и питание - очевидно, к земле и питанию, они могут быть общими для всех сервов. В трехпроводных шлейфах сервов черный или коричневый - это земля, посередине обычно красный +5 В и, наконец, белый или желтый - сигнальный. С программной точки зрения управление предельно простое:

Servo myservo; // Сервопривод на 9-м пине Arduino myservo.attach(9); // Повернуть в положение на 90º myservo.write(90);

Большинство сервов умеют вращать вал на 180°, и для них 90° - среднее положение. Для упрощения подключения сервов к плате Arduino существует ряд решений. Самое каноничное - это Sensors Shield. Установив его на Uno и подав на клеммы питание для сервов, можно их разъемы подключать прямо в него.

Батарея

Еще один важный вопрос - питание. Если у тебя продвинутая плата, которая позволяет снабжать всю систему по одной линии питания (и двигатели сервов не дадут помех в работу контроллера), то можно обойтись одним источником. Выбор огромен, лучше всего, конечно, Li-Ion/Li-Po брикеты для радиомоделек. Но им нужны и соответствующие зарядные устройства. Если у тебя контроллер попроще (Uno/Due/Nano), то можно питать его отдельно, например 9-вольтовой «Кроной», а сервоприводы подключить к основной мощной батарее. Так сервоприводам точно хватит питания. В случае литиевых аккумуляторов нужно еще тщательней, чем обычно, следить за напряжением, чтобы не было переразряда (допустимые напряжения стоит уточнить для конкретного типа батареи). Для этого на робота-Слейпнира, о котором дальше пойдет речь, также прикручен маленький цифровой вольтметр.

Робожук своими руками

Набор

  • Контроллер Arduino Uno: 1150 р.
  • Три серводвигателя. Я использовал HXT500, 200 р. за штуку
  • Батарейный отсек для «Кроны» с выключателем: 50 р.
  • Батарейка «Крона»: 145 р.
  • ИК-приемник: 90 р.
  • Стальная проволока диаметром примерно 1,5 мм. Я, к примеру, использовал сломанный венчик для взбивания яиц

Итого: 2035 р.

DmitryDzz: Я хочу предложить тебе сделать небольшого дистанционно управляемого шестиногого робожука на базе контроллера Arduino Uno. Лапки будут иметь одну степень свободы, управление будет происходить с помощью обычного ТВ-пульта.

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

Более простой способ - взять набор-конструктор, потому что на первых шагах одного контроллера будет мало. Сейчас много магазинов предлагают такие наборы. Например, есть замечательный интернет-магазин «Амперка» . Здесь тебе предложат несколько подобных конструкторов, отличающихся наполненностью и, конечно, ценой. Мне вполне хватило самого простого - «Матрешка X». В него входит контроллер Arduino Uno, USB-кабель для подключения к компьютеру, доска для прототипирования (незаменимая вещь!), набор перемычек, светодиоды, резисторы и прочая мелочь.

В этом же магазине есть раздел «Вики», где ты найдешь даже замечательные короткие видео­уроки, переведенные на русский язык. Обязательно посмотри их. И конечно, есть форум, где тебе наверняка постараются помочь.

Что понадобится из инструментов:

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

Если все собрали, приступим!

Управление

Перейдем к первому шагу: нам надо научиться взаимодействовать с пультом ДУ и выведать коды нажатий на некоторые его кнопки. Эти коды потом пригодятся для скетча управления роботом.

На этом этапе понадобится еще ИК-приемник и хорошо бы иметь доску для прототипирования. Подавляющее большинство ИК-пультов работают на несущих частотах 36 кГц, 38 кГц или 40 кГц (Panasonic, Sony). Исключение составляют пульты Sharp (56 кГц), Bang & Olufsen (455 кГц) и, может, кто-то еще более экзотический. Поэтому нам вполне подойдет любой ИК-приемник на 36, 38 или 40 кГц. Частота может точно не совпадать с несущей частотой сигнала. В таком случае чувствительность приемника будет снижаться, но на практике я не заметил дискомфорта, используя ИК-приемник TSOP2136 (36 кГц - последние две цифры - частота) и пульт ДУ Sony (40 кГц).

Итак, для большинства пультов подойдут ИК-приемники TSOP21xx, TSOP22xx, TSOP312xx. Две последние цифры могут быть 36, 37, 38 или 40. Перед включением ИК-приемника уточни разводку его контактов - их всего три: +5V (питание), GND (земля), Vs (выход). Соберем схему, как на иллюстрации (разводка для TSOP2136).


Как видишь, к аналоговому входу контроллера A0 мы подключили выход ИК-приемника.

Вот как выглядит код скетча:

#include "IRremote.h" // Аналоговый вход контроллера, // к которому подключен ИК-приемник: const int IR_PIN = A0; // Создаем объект ИК-приемник: IRrecv irrecv(IR_PIN); void setup() { Serial.begin(9600); Serial.println("ready"); // Начинаем прослушивание ИК- // сигналов: irrecv.enableIRIn(); } void loop() { // Описываем структуру results, // в которую будут помещаться // принятые и декодированные // ИК-команды: decode_results results; // Если ИК-команда принята и успешно // декодирована, то выводим // полученный код в последовательный // порт контроллера: if (irrecv.decode(&results)) { Serial.println(results.value); irrecv.resume(); } }

В скетче используется специальная библиотека IRremote.h, декодирующая сигналы самых разных ИК-пультов. Эта библиотека - открытый проект, скачать ее ты можешь со страницыhttps://github.com/shirriff/Arduino-IRremote. А чтобы ее подключить к нашему проекту, надо выполнить три действия:

  • каталог библиотеки скопировать в каталог libraries, который, в свою очередь, находится в инсталляционном каталоге Arduino IDE;
  • перезапустить IDE;
  • добавить в начало нашего скетча строку #include «IRremote.h».

Теперь в скетче будут доступны функции декодирования ИК-сигналов. Но, чтобы увидеть полученные коды, мы еще будем использовать объект Serial. С его помощью по последовательному порту (все тот же USB-кабель) мы будем передавать коды на компьютер. В функции setup мы выполняем инициализацию объекта Serial. «9600» - это 9600 бод - скорость, которая будет использоваться для передачи данных. После инициализации мы можем производить запись в последовательный порт с помощью функции println. Для просмотра результата этого вывода на компьютере в Arduino IDE выбери пункт меню Tools → Serial Monitor (Ctrl + Shift + M). Только убедись, что в нем установлена скорость 9600 бод.

Итак, питание контроллер получает по USB-кабелю, данные передает по нему же. Загружаем скетч, запускаем Serial Monitor и начинаем жать кнопки пульта ДУ. В окне Serial Monitor должны появляться коды. Протоколы пультов отличаются, иногда это может быть один код, иногда несколько. В любом случае ты всегда можешь выделить коды, уникальные для каждой кнопки пульта.

Нам потребуется 13 кнопок пульта. Я использовал следующие:

  • 1 - плавный поворот налево;
  • 2 - движение вперед;
  • 3 - плавный поворот направо;
  • 4 - поворот налево на месте;
  • 5 - стоп;
  • 6 - поворот направо на месте;
  • 7 - движение назад с поворотом направо;
  • 8 - движение назад;
  • 9 - движение назад с поворотом налево;
  • синяя кнопка - очень медленно;
  • желтая - медленно;
  • зеленая - быстро;
  • красная - очень быстро.

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

Алгоритм движения

Скетч управления роботом доступен на странице нашего проекта (bit.ly/1dEwNDC). Не забудь изменить значения констант кодов нажатых кнопок пульта на коды своего пульта (константы IR_COMMAND_XXX_CODES в файле ir_command_codes.h).

Скетч подробно мы разбирать не будем, думаю, достаточно комментариев в коде, но один вопрос все же стоит рассмотреть.

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

У нашего робожука три серводвигателя, расположенные в ряд перпендикулярно движению. У левого и правого серводвигателей ось вала направлена вверх, а у центрального - вперед. Задача, например, левой сервомашинки - качать сразу две ноги: левую переднюю и левую заднюю. Они, кстати, жестко соединены между собой и приклеены к качалке этой сервомашинки. Задача центральной сервы - приподнимать то левый бок жука, то правый. Поэтому к качалке этого двигателя крепятся центральные левая и правая ноги, представляющие собой единую П-образную деталь.

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

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

Итак, как это реализовано? Мы помним, что контроллер постоянно вызывает функцию loop. Значит, в эту функцию мы должны поместить код, который определяет текущее положение серводвигателей и устанавливает их в это положение. Каждый серводвигатель должен совершать колебательные движения. Рассчитать положение серводвигателя в момент времени t мы сможем по следующей формуле:

X = A sin(2πt/T),

где X - искомое положение серводвигателя, A - амплитуда колебаний, T - период колебаний.

Так, в зависимости от момента времени t мы получим изменение величины X в интервале от –A до +A. Серводвигатели могут принимать положение в диапазоне от 0 до 180°. Поэтому колебания нам лучше производить вокруг «нулевого» положения в 90°. И если мы хотим обеспечить колебания с периодом 1 с вокруг положения 90° с амплитудой 30°, то формула преобразуется в следующий вид:

X = 90 + 30 sin(2πt/1000),

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

А теперь еще раз вернемся к нашей схеме, потому что формула, написанная выше, еще не завершена. Как обеспечить то синхронное, то встречное движение левого и правого серводвигателя? Как менять фазу центрального серводвигателя? Мы должны добавить в нашу формулу фазу колебаний. Сдвиг аргумента синуса на величину π для, например, правого двигателя заставит его работать в противофазу левому, то есть так, как нам надо для поворота на месте. Вот как теперь будет выглядеть наша формула:

X = 90 + 30 sin(2πt/1000 + Φ),

где Φ - фаза колебаний, значение от 0 до 2π.

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

Сборка

Теперь давай соберем робота на доске для прототипирования и зальем скетч управления.

Это очень важный этап перед сборкой. Попробуй отключить USB-кабель и запитай макет от батарейки «Крона». Проверь все фазы движения и убедись, что все работает. После сборки робота что-либо менять (например, заменить неработающий серводвигатель) будет уже сложнее.

Теперь перейдем к самой сборке. Основной несущий элемент - это батарейный отсек. Я советую использовать отсек закрытого типа и обязательно с выключателем.

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

Контроллер проще всего приклеить к отсеку, но мне этот вариант не очень нравится, так как придется навсегда отдать Arduino Uno жуку. Поэтому можно усложнить себе жизнь и использовать разъемы Arduino для крепления батарейного отсека. На нижней части отсека приклей штырьковый разъем с шагом между штырьками 2,54 мм. Он должен располагаться так, чтобы входить в гнездо контроллера в районе цифровых выводов 8–11. Они пока все равно нам не понадобятся. Если разъема под рукой не оказалось, подойдет П-образно изогнутая канцелярская скрепка.

Провода, идущие от батарейного отсека, надо соединить с выводами Vin и соседним с ним GND. Не перепутай полярность! Плюс «Кроны» на Vin, минус на GND. Чтобы обеспечить надежный контакт проводов с Arduino-разъемами, можно просто облудить кончик провода потолще, я же как штекер использовал короткий отрезок скрепки. А место пайки закрыл термоусадочной трубкой.

Разъемы со шлейфов сервоприводов следует срезать, провода питания (+5 В - обычно красный и GND - черный или коричневый) надо объединить и вывести к гнездам 5V и соседнему с ним GND на контроллере. Подключать будем чуть позже. Провода управляющего сигнала (обычно желтый) выводим на цифровые выводы контроллера: левый серводвигатель на пин 2, центральный на пин 4, правый на пин 7.

«+» и «–» ИК-приемника можно просто вставить в разъем Arduino (5V и соседний GND). Правда, согнув пополам, удвоив их толщину. К этим же ножкам питания ИК-приемника припаиваем ранее подведенные провода питания серводвигателей. Выход сигнала ИК-приемника до аналогового входа контроллера А0 уже вряд ли дотянется, и тебе придется наращивать его проводом.

Несколько советов по изготовлению ног. Сначала подготовь левую и правую «передне-задние» ноги. Убедись в их симметричности (обрати внимание и на длины, и на углы изгибов). Начинай клеить ноги, только убедившись, что серводвигатели установлены в «нулевое» положение (90°).

Среднюю пару ног лучше устанавливай в последнюю очередь. Советую сначала сделать средние ноги длиннее, а затем после установки подрезать их до нужной длины. В «нулевом» положении все шесть ног должны стоять на поверхности. Качение средних ног с амплитудой 15° не должно мешать поворотам «передне-задних».

Что дальше?

Робожук - это готовая мобильная платформа на базе одного из самых популярных и доступных контроллеров. Проект открытый: https://github.com/beetle-ringo/arduino . Делай в GitHub форк (ответвление) и добавляй свою функциональность. Дай волю фантазии - добавь ИК-светодиод, и робот готов для робобитвы. Подключи дальномеры, тактильные сенсоры, гироскоп… Научи робота обходить препятствия или ходить по линии, попробуй установить на него веб-камеру. Идей может быть миллион, и ты всегда можешь выбирать самую интересную.

Робот-Слейпнир

Набор

  • Контроллер Arduino Uno Dagu Spider Robot: 2530 р.
  • Сервоприводы SG90 9g (16 штук) 1150 р.
  • Аккумулятор LiPo battery pack, 7,4 В, 1800 мА ч 490 р.
  • Радиомодуль 4 Pin Bluetooth RF Transceiver 270 р.
  • Индикатор напряжения (опционален) DC 3,3–30 В Red LED Panel Meter 100 р.
  • Уголок алюминиевый. В ближайшем строймаркете 135 р.
  • Болтики и гайки. На ближайшей барахолке 35 р.

Итого: 4710 р.

*Компоненты покупались в разное время, и многие позиции можно оптимизировать

poconoco: Попробуем собрать нестандартную конфигурацию - восьминогого 2DOF-робота. 2DOF-ноги намного проще программировать, к тому же у меня есть в запасе куча неиспользованных сервоприводов. А главное, можно будет назвать его в честь восьминогого коня бога Одина Слейпниром (всегда мечтал!).

У нашего Слейпнира с каждой стороны будет по четыре ноги с двумя шарнирами. Каждый шарнир - сервопривод, значит, восемь сервоприводов на сторону. Для простоты все восемь шарниров одной стороны коня будут вращаться в одной плоскости. Хотя это вовсе не обязательно. Более того, если ноги с одной стороны пустить немного «шахматкой», чтобы две соседние ноги не могли задеть друг друга, это будет даже лучше, позволит делать шире шаг и скакать галопом.

Аккуратное и функциональное, но далеко не самое дешевое решение - использовать нестандартную плату контроллера, оптимизированную для подключения сервоприводов в большом количестве. Мне подвернулась Dagu Spider Robot Controller - это тот же самый Arduino Mega, но на плате с заранее распаянными 3-пиновыми штырьковыми разъемами, куда сразу, без всяких шилдов, можно подключить те самые 48 сервоприводов. Идеальна для многоногих роботов на Arduino.

Управление

Управление у нас будет происходить по Bluetooth. Для этого есть различные аппаратные решения. Это и шилды, и отдельные платки с UART последовательным интерфейсом (как обычный ком-порт, только с уровнями сигналов 5 В). Мне самой практичной показалась именно маленькая платка с UART-интерфейсом. Подключается к соответствующим контактам UART/Serial порта Arduino. Отметим два нюанса: на Uno/Due/Nano и подобных всего один такой порт, и он же используется для прошивки через USB. Поэтому, возможно, потребуется отключать Bluetooth-модуль на время прошивки. А второй нюанс - не забывай, что RX-контакт модуля подключается к TX-контакту Arduino, а TX - к RX. Такие дела в UART.

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

Char cmd; Serial.begin(9600); if (Serial.available()) cmd = Serial.read();

Если используется Arduino Mega и Bluetooth подключен ко второму порту, то вместо Serial пишется Serial1. Примечательно, что можно и не использовать Bluetooth, а управлять роботом прямо по USB. И в коде выше не изменится ничего! Это просто работа с последовательным портом, а висит ли там BT-передатчик или преобразователь USB Serial - нам неважно.

Другая сторона Bluetooth

Самый удобный способ подключения - это стандартные утилиты Linux. Для работы нам понадобятся утилиты sdptool, rfcomm (входят в состав пакета bluez в репозиториях Ubuntu), а также minicom (пакет так и называется). Инструкции по работе с этими утилитами можно найти в Сети.

Алгоритм движения

Для гексапода самой простой походкой будет такая: ноги делятся на две группы по три ноги, и одна из групп полностью на земле, другая - в воздухе, переставляется вперед. Это далеко не единственная возможная походка. Можно в воздухе держать только две лапы или даже одну, а остальные четыре или пять - на земле. Для октапода походок тоже множество. Мы возьмем самую простую, также с двумя группами по четыре ноги.

Итак, что нам нужно делать для работы с 16 сервоприводами и выбранной походкой? Правильный ответ - читать про инверсную кинематику (ИК). Объем статьи не позволяет развернуть тему широко, но материалов в интернете предостаточно. Вкратце, ИК решает задачу нахождения необходимых управляющих сигналов для того, чтобы система в пространстве заняла нужное положение. Для ноги это значит, что по координатам точки, куда должна попасть стопа, следует определить углы сервоприводов, которые для этого нужно выставить. А управляя координатами стоп, можно управлять положением тела. У нас 2DOF-ноги, оси параллельны, поэтому стопа перемещается всегда в одной плоскости. Задача ИК в данном случае сводится к 2D-пространству, что сильно ее упрощает.

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

Float A = -2 * x; float B = -2 * y; float C = sqr(x) + sqr(y) + sqr(hipLength) - sqr(shinLength); float X0 = -A * C / (sqr(A) + sqr(B)); float Y0 = -B * C / (sqr(A) + sqr(B)); float D = sqrt(sqr(hipLength) - (sqr(C) / (sqr(A) + sqr(B)))); float mult = sqrt(sqr(D) / (sqr(A) + sqr(B))); float ax, ay, bx, by; ax = X0 + B * mult; bx = X0 - B * mult; ay = Y0 - A * mult; by = Y0 + A * mult; // или bx для другой точки пересечения float jointLocalX = ax; // или by для другой точки пересечения float jointLocalY = ay; float hipPrimaryAngle = polarAngle(jointLocalX, jointLocalY); float hipAngle = hipPrimaryAngle - hipStartAngle; float shinPrimaryAngle = polarAngle (x - jointLocalX, y - jointLocalY); float shinAngle = (shinPrimaryAngle - hipAngle) - shinStartAngle;

где x и y - координаты точки, куда нужно дотянуться стопой; hipStartAngle - угол, на который повернуто «бедро» изначально (при среднем положении серва), аналогично - shinStartAngle. Кстати, в этих расчетах углы, очевидно, в радианах, а в объекты Servo их передавать нужно уже в градусах. Полный работоспособный код прошивки, включающий этот кусочек, выложен на GitHub, см. ссылку в конце статьи. Это кусок ИК, но кроме него нужно еще немного довольно простого кода, чтобы использовать эту ИК на всех ногах (см. функции legsReachTo(), legWrite()). Также необходим будет код, который собственно реализует походку - движение одной группы ног «назад» (чтобы робот двигался вперед), в то время как другая группа ног приподнимается и переставляется вперед для следующего шага, см. функцию stepForward(). Она делает один шаг с заданными параметрами. Этими параметрами, кстати, можно сделать и шаг назад, несмотря на название функции. Если эту функцию вызывать в цикле, то робот будет шагать вперед.

Теперь получение команд и их интерпретация. Добавим в программу состояние:

Enum State { STOP, FORWARD, BACKWARD, FORWARD_RIGHT, FORWARD_LEFT };

И в главном цикле исполнения loop() будем смотреть на текущее состояние (переменная state) и дергать stepForward(), если движемся вперед (с поворотом или без), и опять же stepForward(), но с отрицательным аргументом xamp, если надо двигаться назад. Повороты при этом будут обрабатываться в legWrite(), и для поворота направо ноги с правой стороны будут стоять на месте (пока левые гребут). Вот такой вот конь-танк. Брутально, зато очень просто и работает. Плавный поворот можно сделать только с 3DOF-ногами, пример этого можно увидеть в репозитории buggybug.

Switch (state) { case FORWARD: case FORWARD_RIGHT: case FORWARD_LEFT: stepForward(h, dh, xamp, xshift); break; case BACKWARD: stepForward(h, dh, - xamp, xshift); break; }

Char command; while (Serial1.available()) command = Serial1.read(); switch (command) { case "w": state = FORWARD; break; case "s": state = BACKWARD; break; case "d": state = FORWARD_RIGHT; break; case "a": state = FORWARD_LEFT; break; default: state = STOP; }

На этом основные моменты прошивки закончились, остальное - всякая мелочевка. Хотя есть еще один, пожалуй, важный момент - возможность точной подстройки сервов. Даже при самой аккуратной сборке, если всем сервам подать команду повернуться на 90°, все равно некоторые из них получатся чуть со сбитым углом. Потому нужна возможность его подстраивать. Как у меня это сделано, можно посмотреть в методах hipsWrite() и shinsWrite() и собственно в массивах тонких настроек hipsTune и shinsTune.

Сборка

Для подобных конструкций не нужно ничего особенного: подойдет листок оргстекла подходящей толщины (с ближайшей хозяйственной барахолки) и лобзик либо ножовка, чтобы выпиливать детальки. И конечно, дрель, чтобы сверлить отверстия. Вместо оргстекла можно использовать фанеру (тогда на финальной конструкции можно еще сделать памятную надпись выжигателем). Можно использовать и листы или уголки алюминия. Со Слейпниром я пошел как раз по пути использования алюминиевого уголка с ребрами в 1 см (купил где-то в строительном супермаркете).

Основой будет прямоугольная рама. Конечности - 4-сантиметровые полосочки. Стоит также запастись множеством маленьких болтиков, гаечек. Режем уголок на нужные кусочки, вырезаем пазы для сервов, сверлим дырочки для крепежных болтов и шурупов. Конструкцию лучше раз показать, чем описывать. Размеры могут быть любые, роботы должны быть разнообразны. Но помни: чем длиннее ноги, тем больший рычаг придется толкать сервоприводу и тем больше будет на него нагрузка. Вплоть до невозможности провернуться и даже поломки. Но 4–5 см - без проблем.

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

В комплекте с каждым сервом, как правило, поставляется пара-тройка шурупов и набор насадок, которые можно закрепить шурупом на валу для различных применений. Нам больше всего подойдет одиночный «рог» (или horn), который позволяет прикрепить к серву планку. Так, к одной планке крепятся оси двух сервов, и планка становится «бедром». При этом один серв крепится на теле, а другой становится частью голени. К нему стоит прикрутить еще планку, просто чтобы удлинить или сделать конечность поинтересней. Немного кропотливой работы - и платформа готова (удобные наборы отверток, ключей, пинцеты, кусачки и прочее сильно ускоряют дело).


Что дальше?

Весь проект доступен на странице https://github.com/poconoco/sleipnir . Я описал одну из самых непрактичных конфигураций - много 2DOF-ног, высокий, узкий, легко валится на бок. Попробуй сделать лучше, робота с 3DOF-ногами. С 4DOF-ногами. С клешнями или челюстями. В качестве примера 3DOF инверсной кинематики можешь обращаться к репозиторию buggybug - там прошивка гексапода. Также можно делать не управляемых, а интеллектуальных роботов, ставя вместо Bluetooth датчики расстояния, научить робота обходить стены и препятствия. Если такой сенсор поставить на сервопривод и вращать им, то можно сканировать местность, практически сонаром.

Много чего предстоит сделать, прежде чем мы дойдем до вот этой картинки:

Опуская росказни о том, как именно я пришел к мысли построить гексапода (это были тонны видео на ютубе), перейду сразу к процессу выбора деталек. Это был январь 2012-го. Я сразу знал, чего я хочу от своего робота, а чего - нет. Я хотел:

Каждая нога должна иметь 3 степени свободы - 3dof (3 dimensions of freedom). Потому что более простой вариант 2dof - не дает такого ощущения насекомого, а 4dof - излишне, 3dof и так позволяет свободно перемещать кончик ноги в 3д пространстве;
- 6 ног; снова-таки, это уже не 4 (тогда робот неуклюже скачет), но и еще и не 8, как у пауков и уже чрезмерно;
- небольшой;
- дешевый;
- минимум плат и соединений;

Пост большой.

Первой конечно нужно было выбирать motherboard для крохи. Много как хорошего так и плохого успел почитать к тому времени об Arduino. Но именно на него и смотрел, как на основной вариант. Паять контроллеры самому - времени не было, а брать более продвинутые платы с ARM cpu, например - дорого, да и разбираться, как их программить, как работать с ШИМ выводами и т.п. А ардуина: IDE запустил, код напедалил, upload нажал - и привет, оно тебе уже моргает. Красота! ;)

Сначала я начал смотреть на arduino mega и клонов, т.к. кол-во ШИМ выходов, которыми можно рулить сервами у них было предостаточно. Напомню, что для 3dof гексапода нужно 3*6 = 18 сервов, и раздельных каналов управления ими. Но потом я нашел настоящий Яззь среди arduino mega, это плата от Dagu, звать которую Red Back Spider Controller. Вот она на ebay.

Она предлагает все свои выходы в виде готовых 3-х штырьков (земля, питание, сигнал), и разввязку по питанию. Питание самого контроллера стабилизировано, а на разъемы двиглов идет как есть (UPD: не как есть, а тоже стабилизированные 5 вольт. И повидимому развязано с питанием контроллера, т.к. помех в работу контроллера 18 одновременно работающих сервов не вносят). Это позволяет просто подать на клемму питания 7-30 вольт достаточной мощности (питальника от eee pc 901 на 12В и 3А - оказалось достаточно для жужжания всеми 18 сервами) и не морочить голову с раздельным питанием логики и двиглов. Также это позволит в будущем легко посадить все это чудище на пачку Li-Po аккумуляторов на 7.4 вольт. И при всем этом, с программной точки зрения - это обычная ардуино мега, совместимая с софтом и либами, да и железом (кроме шилдов, устанавливающихся прямо на оригинальную mega - они не покатят). Правда цена еще выше чем даже оригинальная мега, но все остальные плюсы перевесили это.

Далее сервоприводы. На ebay по запросу micro servo их много разных. Я взял самые мощные из самых маленьких и дешевых, весом 9 грамм, пластмассовыми редукторами. Если брать лоты где их пачками шлют - выходит дешевле. Я брал 3 пачки по 6 кажется, и вышло меньше $2 штука. Забегая вперед, скажу, что жалею что не потратил больше и не взял сервы с металлическими шестернями и шариковыми подшипниками. У этих пластмассовых оказались довольно заметные люфты, и характерный хруст при чрезмерном усилии когда шестерни проскакивают. Из-за люфтов - кинематику довольно тяжело настроить точно (да это вообще самое тяжелое оказалось).

Вот собственно и все что я заказал, с доставкой это вышло примерно $100. Батарейки и передатчики\приемники для контроля и радиоуправляемости - оставил на потом. Потому что радиоуправляемая машинка у меня есть и не интересна, а что меня действительно интересовало - это ноги! Видео плавно ходящих гексаподов на ютубе - завораживало , я смотрел его, пересматривал, и каждый раз слезы котились по щекам, и я сдавлено хрипел «хочу!». Хочу не заказать такую готовую штуку, а хочу сделать самому что-нибудь такое!

Пока ждал заказа, читал, как же просвященные люди оживляют свои творения. Конечно сразу же всплыла инверсная кинематика (перевод). Если сказать просто и сразу про шарнитные «конечности», то прямая кинематика - это когда на вход подаются углы шарниров, а на выходе мы имеем модель конечности в пространстве, и координаты крайней точки конечности. Обратная же кинематика - очевидно работает наоборот - на вход поступают координаты крайней точки конечности, куда нам надо дотянуться, а на выходе мы получаем углы, на которые нужно повернуть шарниры, чтобы это осуществить. Сервоприводы как раз получают на вход угловое положение, в которое им нужно повернуться (по одному сигнальному проводу, закодированное ШИМ / PWM).

Начал писать. Начал с того, о чем читал: продумывать реализацию ИК по методу, описанному там . Но быстро пришло ощущение, что для моего случая он чрезмерно сложен. Причем как громоздок в реализации, так и вычислительно очень сложен - расчет идет итеративно. А у меня 6 ног, для каждой из которых нужно считать ИК, и всего 16Мгц не самой шустрой архитектуры AVR. Но и всего 3 степени свободы. И несложно догадаться, что до произвольной точки в «области дотягивания» можно дотянуться только одним способом. Решение уже созрело в голове.

Но тут пришел февраль и посылки - одна из китая, другая из UK. Первым делом я конечно просто поигрался с платой ардуино - поморгал светодиодом и попиликал в подключеный туда динамик. Потом занялся реализацией собственно ИК, уже в железе. Для чего соорудил прототип ноги из подручных материалов (довольно мягкая пластмасска, которую легко резать ножницами, шурупы и насадки - все из комплектов сервоприводов). Эту ногу терминатора закрепил прямо на плату ардуины. Можно рассмотреть, как бюджетно выполнены сочленения.

Полюбовался на это дело, и помечтал, что если я на основе этого робота в будущем спаяю терминатора, который объявит войну человечеству, то потом Джон Коннор со Шварцнеггером вернутся ко мне сюда в прошлое, и отберут этот прототип и расплавят его в Ородруине. Но никто не вернулся, ничего не отобрал, и я спокойно продолжил.

Оказалось, что ИК совсем не нужно бояться, в моем случае все свелось к банальной геометрии-тригонометрии. Чтобы проще было обращаться к суставам, обратился к википедии и почитал про насекомых. У них есть специальные названия для элементов конечности:

На русском тоже есть свои и очень интересные названия для этого, но «тазик», «вертлуг», «голень» и т.п., находясь в коде, не давали бы мне заснуть. Потому я 3-х конечностям и соответствующим сервам оставил названия Coxa, Femur, Tibia. Из прототипа ноги выше видно, что у меня для coxa даже нет отдельной детали. Это просто два серва, скрепленных резинками. Femur - реализован полоской пластика, к которой с обоих сторон крепятся рычаги сервов. Таким образом, последний оставшийся серводвижок - является началом tibia, для удлинения которой к нему прикручен еще кусок пластика.

Запустил редактор, не мудствуя создал файл Leg.h, И в нем класс Leg. Ну и кучу вспомогательной мути.) Пускай в пространстве есть точка A(ax, ay, az), к которой нужно дотянуться. Тогда вид сверху выглядит так:

На рисунке я сразу показал и способ вычисления первого угла - это угол поворота серва, управляющего Coxa, вращающего всю конечность в горизонтальной плоскости. На схеме красным сразу обозначены переменные, используемые в коде (далеко не все). Не очень математично, зато удобно. Видно, что интересующий нас угол находится элементарно. Сначала primaryCoxaAngle - находится просто углом (0;A) к оси X (что эквивалентно углу точки A в полярных координатах). Но на схеме видно, что при этом сама нога - не распаложена под этим углом. Причина в том, что ось вращения coxa не находится на «линии ноги» - не знаю как это правильно сказать. Не находится в плоскости, в которой вращаются остальные 2 сустава и находится кончик ноги, вот. Это можно легко компенсировать, посчитав additionalCoxaAngle (как его считать - даже не утруждаюсь останавливаться, ну ведь все же были в школе, правда?).

Итого, у нас есть первый кусочек кода, это внутренности метода reach(Point& dest):

Float hDist = sqrt(sqr(dest.x - _cStart.x) + sqr(dest.y - _cStart.y)); float additionalCoxaAngle = hDist == 0.0 ? DONT_MOVE: asin(_cFemurOffset / hDist); float primaryCoxaAngle = polarAngle(dest.x - _cStart.x, dest.y - _cStart.y, _thirdQuarterFix); float cAngle = hDist == 0.0 ? DONT_MOVE: primaryCoxaAngle - additionalCoxaAngle - _cStartAngle;

Здесь dest - это точка, куда нажо тянуться, _cStart - координаты точки крепления (и центра вращения) coxa, в hDist считаем расстояние от _cStart до dest в горизонтальной плоскости. DONT_MOVE - это просто флаг, означающий что coxa не нужно никуда вращать, а оставить в текущем положении (т.к. dest - где-то прямо на оси вращения coxa - редко, но бывает). Вот cAngle - это уже тот угол, на который нужно будет отклониться сервоприводу от его начального угла (который находится в середине его рабочего диапазона). Видно что также юзается _cStartAngle - это угол в пространстве, на который повернут серво по деволту, при монтаже. Про _thirdQuarterFix расскажу позже, если не забуду.

При этом, задача внезапно сведется к поиску точки пересечения 2-х окружностей. Одна - в точке, откуда «растет» наша femur, вторая - точка, куда нам надо дотянуться (с уже локальным 2d координатами). Радиусы окружностей - длины femur и tibia соответственно. Если окружности пересекаются - то в одной из 2х точек можно расположить сустав. Мы всегда выбираем верхнюю, чтобы «колени» у чудища были выгнуты вверх, а не вниз. Если не пересекаются - то мы не дотянемся до целевой точки. Еще немного кода, переход в плоскость производится элементарно, только пара подводных камней еще учтена и задокументирована в коментарии, чтобы я не ломал голову потом, разбирая код. Для простоты, в этой локальной координатной «плоскости ноги» я выбрал началом координат точку, откуда растет femur:

// Moving to local Coxa-Femur-target coordinate system // Note the case when hDist <= _cFemurOffset. This is for the blind zone. // We never can"t reach the point that is nearer to the _cStart then // femur offset (_fStartFarOffset) float localDestX = hDist <= _cFemurOffset ? - _fStartFarOffset: sqrt(sqr(hDist) - sqr(_cFemurOffset)) - _fStartFarOffset; float localDestY = dest.z - _fStartZOffset; // Check reachability float localDistSqr = sqr(localDestX) + sqr(localDestY); if (localDistSqr > sqr(_fLength + _tLenght)) { log("Can"t reach!"); return false; }

Теперь localDestX и localDestY - это координаты целевой точки. Все что осталось - найти точку пересечения окружностей с центрами в (0,0) и (localDestX, localDestY), и радиусами _fLength и _tLength (соответственно длина femur и длина tibia). С этим тоже школьник справится, но тут я допускал довольно много ошибок, потому для проверки себя и вообще чтобы любой мог проверить, что это за стремные формулы, оставил ссылки на источники, где ясно и понятно разжована эта элементарная геометрическая задача:

// Find joint as circle intersect (equations from http://e-maxx.ru/algo/circles_intersection & http://e-maxx.ru/algo/circle_line_intersection) float A = -2 * localDestX; float B = -2 * localDestY; float C = sqr(localDestX) + sqr(localDestY) + sqr(_fLength) - sqr(_tLenght); float X0 = -A * C / (sqr(A) + sqr(B)); float Y0 = -B * C / (sqr(A) + sqr(B)); float D = sqrt(sqr(_fLength) - (sqr(C) / (sqr(A) + sqr(B)))); float mult = sqrt (sqr(D) / (sqr(A) + sqr(B))); float ax, ay, bx, by; ax = X0 + B * mult; bx = X0 - B * mult; ay = Y0 - A * mult; by = Y0 + A * mult; // Select solution on top as joint float jointLocalX = (ax > bx) ? ax: bx; float jointLocalY = (ax > bx) ? ay: by;

Все, осталось еще чуть-чуть - по полученным координатам вычислить собственно углы для femur и tibia сервов:

Float primaryFemurAngle = polarAngle(jointLocalX, jointLocalY, false); float fAngle = primaryFemurAngle - _fStartAngle; float primaryTibiaAngle = polarAngle(localDestX - jointLocalX, localDestY - jointLocalY, false); float tAngle = (primaryTibiaAngle - fAngle) - _tStartAngle;

Опять элементарщина - угловые координаты и всё. Я надеюсь, именование переменных уже должно быть понятным, к примеру, _fStartAngle - это femur start angle, угол на который femur направлен по дефолту. И последняя строчка метода reach() (он сказал поехали, и махнул рукой):

Move(cAngle, fAngle, tAngle);

Метод move уже непосредственно отдает команды сервам. На самом деле, в нем еще потом пришлось добавить всякие штуки для защиты от нехороших углов (на которые серво повернуться не может, но будет пытаться), а также для других ног, которые заркально расположены и/или направлены в другие стороны. Но пока же мы работаем с одной только лапой.
Эти куски - это уже финальный код, который далек от совершенства, и наверняка его можно значительно улучшить. Но он работает! Ни разу не выйдя за школьный курс геометрии-тригонометрии, мы реализовали полнофункционалную инверсную кинематику для 3dof ноги! Да еще и получаем решение сразу, за одну итерацию. Чтобы это все работало, ногу нужно было тщательно измерить, и сконфигурировать класс полученными данными. в том числе угловыми, которые сложнее всего измерять на готовом изделии. Может если проектировать в автокаде и наделать красивых рендеров - было бы легче с измерением углов, но у меня не было ни времени, ни желания заниматься этим пафосом.

Февраль только начался, а видео с ногой было уже готово. Для проверки ИК, я заставлял ногу описывать всякие фигуры в пространстве (для этого нужно было последовательно вызывать reach, обходя точки на прямоугольнике, или окружности, код скучен и уныл, потому не привожу (а закончив эксперименты с обведением примитивов, я его вообще выпилил)):

Дальше нужно было заканчивать играться с этой поделкой, на одной ноге далеко не упрыгаешь (хотя такой робот вышел бы действительно интересным). Но мне нужен гексапод. Отправился на ближайшую барахолку искать оргстекло. Нашел 2 отличных куска - один 3 мм толщиной (как раз для туловища, подумал я), другой 2 мм и синий (отличные конечности, в тон сервоприводам). Еще через пару недель я выкроил вечер, чтобы что-нибудь сделать из этого. Сделал наброски на бумаге. примерил - вроде все ок, дальше дело за ножовкой.

И вот оно, чудище заморское, шестилапое. Когда я тестил одну ногу, я питал это дело каким-то левым питальником от внешнего винта. Хватало. Но питать 6 ног от него было уже страшновато. Потому я на некоторое время повесил руки, думая что мне нужно еще раздобыть подходящий питальник. Но оказалось все гораздо проще, я выше уже упоминал - подошел питальник от eee pc 901. Ну и отлично.

Отладить работу 6-ти ног оказалось еще сложнее, чем написать движок одной ноги. Половина ног была зеркально отражена относительно другой. Кроме того направлены все в разные стороны. Вобщем конфигурировал и настраивал я все очень долго, и это меня не очень вдохновляло, т.к. средств удобной отладки не было, максимум на что я мог расчитывать - вывод лога в Serial. И тот нормально работал из основного *.ino файла, а из подключенного Leg.h - уже не виделся нужный объект. Наворотил костылей для лога (facepalm). Со временем отрефакторю. А тут еще и весна пришла, велосезон был открыт в полную силу, и я забросил своего шестилапого питомца в шкаф. Так прошло все лето и теплая часть осени.

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

А polarAngle у меня была наивная - она возвращала углы от -пи до пи, относительно оси X. И, если иногда одной из этих 2-х ног нужно было повернуться во II-ю четверть, то значение polarAngle прыгало от -пи до пи, что собственно негативно влияло на дальнейший расчет. Пофиксил костылем - для этих 2-х ног polarAngle считается «иначе». Стыдно, стыдно мне за код, но весь проект - это proof of concept, единственная цель которого - просто понять, могу я собрать реалистично двигающегося гексапода или нет. Потому код должен работать, и прямо сейчас. А уж потом рефакторинг - перерефакторинг.

Справившись с 3-й четвертью, начал педалить паттерны шага. Для этого ввел в класс Leg точку default, т.е. в которой нога находится, когда робот стоит смирно и ровно. Эту точку можно тюнинговать, главное чтобы все ноги были на одной z координате (чтобы при этом ноги реально физически находились на одной плоскости, у Leg есть еще самая низкоуровневая tuneRestAngles()). А в пределах одной Z координаты, их можно двигать почти как угодно. Почти - потому что диапазон движения не бесконечен, и чтобы при шаге не выходить за рамки этого диапазода - default положение ног старался разместить где-то поближе к центру этого диапазона.

Код тут в тексте уже не привожу, он слишком элементарен, и я в конце приведу ссылки на полную версию всех сорцов - заодно научусь пользоваться github.

Последовательность шага выбрал простую - 3 ноги на земле, 3 - в воздухе переставляются. Таким образом, координаты ног относительно их default положения - можно разделить на 2 группы. Для этих двух групп я и проворачивал шаг в цикле (см функцию walk() в Buggy.ino). А в итоге, каждая нога вычисляла себе свою индивидуальную координату, исходя из своей default координаты.

И он пошел! Но пока только вперед. На ноги надел ему резинки, чтобы не так скользил на линолеуме. И бросился снимать это на видео, чтобы показать друзьям.

До а-пода, конечно, далеко. Но я же не закончил еще.) Попедалил еще вечер - и добавил возможность двигаться в любом направлении (но не поворачивая корпус.)). Плюс для сглаживания между движениями добавил функцию (smoothTo()), которая аккуратно перемещает ноги (поднимая вверх, опять в 2-х группах, одна из которых всегда внизу, тварь на ней стоит, пока другая поднимается и перемещается) в новое положение. Это нужно чтобы тварь не дергала резко ногами, сменяя направление движения (этой фичи ох как не хватает многим игровым персонажам прошлых лет). И он резво забегал в любом направлении - вбок, по диагонали:

Оба грандиозных файла сорцов можно смотреть


Для тех, кто решил проверить свои силы в области роботостроения и заодно желает изучить возможности платформы Ardunio, есть отличный способ это сделать, собрав робота-паука, который будет описан в этой статье. В качестве основных силовых элементов, благодаря которым робот будет передвигаться, являются сервоприводы. Что касается мозга, то здесь в качестве него выступает Arduino , а также Fischertechnik. По словам автора, робот получился довольно интересным и перспективным.

Материалы и инструменты для изготовления:
- набор лезвий;
- термоклей;
- дремель (нужны очень тонкие сверла);
- винтоверт;
- дрель со сверлом 7/32;
- крестообразная отвертка;
- лезвие;
- отсек для батареек;
- макетная плата.


Из электроники понадобится:
- восемь микросервоприводов с кронштейнами;
- 6 батареек типа АА и прищепка;
- много перемычек и контактных разъемов.

В качестве программной части будет нужна Arduino с блоком питания.

И запчастей необходим набор Fischertechnik.

Процесс изготовления робота. :

Шаг первый. Создаем каркас робота
Чтобы изготовить каркас понадобится набор Fischertechnik. Как он должен выглядеть, можно увидеть на фото. Для создания каркаса нужны три высоких «кирпичика», между ними должно иметься четыре отверстия. Конкретно в этой самоделке будет использоваться элемент с 11-ю вырезами. Важно убедится в том, чтобы все сервоприводы были рабочими.








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

Второй сервопривод устанавливается на другой стороне вспять.








Шаг третий. Установка одного серводвигателя на другой
В первую очередь нужно разобраться с элементами крепления сервоприводов. Если двигатель вращается в противоположную сторону, его нужно повернуть до упора вправо. Как это сделать, можно увидеть на фотографии.

Конкретно в данном случае винт сервопривода должен выступать над пластиком, благодаря этому он будет подвижным. В корпусе второго сервопривода нужно проделать углубление под головку винта.
Что










Что-бы соединить два сервопривода используется горячий клей.

Шаг четвертый. Подсоединяем ноги
Как изготовить ноги, можно увидеть на фото. Всего их должно быть четыре.






После того как ноги будут собраны и подсоединены к роботу, конструкция должна выглядеть так, как на фото.


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


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

Контакты сервопривода Vcc и GND нужно соединить с контактами макета Vcc и GND. Также к каналам макета GND и Vcc подключается источник питания мощностью 7.5В.

Провода для управления сервоприводом окрашены в оранжевый и желтый цвет. Они подключаются к контактам 2 и 9. К примеру, контакт от первого двигателя подключается ко второму контакту на Arduino. Второй двигатель подключается уже к третьему контакту и так далее.



Шаг седьмой. Настраиваем сервоприводы.
Теперь настало время создать программный код для робота. В первую очередь на Arduino нужно создать новый проект, чтобы синхронизировать двигатели. Как должен выглядеть код, можно увидеть на фото. Благодаря этому коду происходит выравнивание ног робота.


Чтобы паук мог подняться, нужно создать еще один проект под названием Up и Down. Благодаря этому коду ноги паука смогут двигаться вверх и вниз.


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


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

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

Прошивка: (скачиваний: 152)

Четырехногий робот-паук создан для демонстрации работы сервомашинок под управлением контроллера Arduino (для кружка робототехники).

У робота два режима:

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

Использовались сервомашинки Turnigy TGY-9025MG металлическим редуктором.

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

Корпус был сделан из упаковочного материала для компов. Для сервомашинок требуется отдельное питание. В качестве источника питания используется Li-po батарея Turnigy 2S 1600 mAh.

Вот вид сверху и снизу робота в процессе сборки.

Для управления сервоприводом в Arduino имеется стандартная библиотека Servo. На платах, отличных от Mega, использование библиотеки отключает возможность использования analogWrite() (PWM) на пинах 9 и 10 (вне зависимости подключены к этим пинам сервы или нет). На платах Mega, до 12 серв могут использоваться без влияния на функциональность PWM, но использование от 12 до 23 сервомашинок отключит PWM на пинах 11 и 12. Cервопривод подключается 3-мя проводами: питание, земля и сигнальный. Питание – красный провод. Черный(или коричневый) провод – земля подключается к GND выводу Arduino, сигнальный(оранжевый/желтый/белый) провод подключается к цифровому выводу контроллера Arduino. Будем использовать выводы 5,6,7,8 Arduino.

Напряжение выдаваемое батареей 7.4 – 8.4 В. Т.к. для питания сервоприводов необходимо напряжение 4.8 – 6.0 В будем использовать стабилизатор напряжения 5В, собранный на микросхеме L7805. Одна микросхема постоянно перегревалась, проблема решилась установкой параллельно двух микросхем L7805.

Для обнаружения препятствий будем использовать ультразвуковой датчик HC-SR04, который позволяет определять расстояние до объекта в диапазоне от 2 до 500 см с точностью 0.3 см. Если расстояние до препятствия меньше 10 см, робот делает поворот и движется дальше вперед.

В качестве пульта используется пульт lg, приемник ИК-сигналов - TSOP31238(1-GND, 2 - +5V, 3-OUT).

Схема электрическая

И весь робот в сборе (плата Arduino питается от батарейки Крона).

Приступим к написанию скетча

Для управления сервоприводами используется Arduino библиотека Servo. Нам необходимо реализовать совокупность движений сервоприводов для движения робота-паука вперед, назад, поворота по часовой стрелке и поворота против часовой стрелки. Кроме того необходимо реализовать функции остановки робота, а также для экономии электроэнергии предусмотрим режим засыпания (когда сервоприводы находятся в режиме detach) и пробуждения (перевод сервоприводов в режим attach). Поэтому каждое движение робота состоит из нескольких шагов.

Например движение вперед состоит из следующих шагов:

  1. левая передняя нога вперед;
  2. правая передняя нога вперед;
  3. левая задняя нога вперед;
  4. правая задняя нога вперед;
  5. четыре ноги вместе назад (что приведет к перетаскиванию тела робота-паука).

Данные для угла поворота каждой сервы на каждом шаге для каждого движения робота-паука хранятся в трехмерном массиве arr_pos.

Int arr_pos={ { // forward {90,90,90,90},{45,90,90,90},{45,135,90,90}, {45,135,45,90},{45,135,45,135},{135,45,135,45} }, { // back {90,90,90,90},{90,90,90,45},{90,90,135,45}, {90,45,135,45},{135,45,135,45},{45,135,45,135} }, { // circle_left {90,90,90,90},{0,90,90,90},{0,0,90,90}, {0,0,0,90},{0,0,0,0},{180,180,180,180} }, { // circle_right {90,90,90,90},{180,90,90,90},{180,180,90,90}, {180,180,180,90},{180,180,180,180},{0,0,0,0} } }; int pos_stop={{90,90,90,90}};

Процедура course(int variant)реализует перемещения сервоприводов для каждого шага следующих движений робота-паука: вперед, назад, поворота по часовой стрелке и поворота против часовой стрелки.

Void course(int variant) { int i=0; for(i=1;i<6;i++) { if(arr_pos[i]!=arr_pos) {myservo11.write(arr_pos[i]);} if(arr_pos[i]!=arr_pos) {myservo12.write(arr_pos[i]);} if(arr_pos[i]!=arr_pos) {myservo13.write(arr_pos[i]);} if(arr_pos[i]!=arr_pos) {myservo14.write(arr_pos[i]);} delay(200); } }

Для остановки, засыпания и пробуждения робота-паука существует процедура go_hor_all()

Void go_hor_all() { myservo11.write(pos_stop); myservo12.write(pos_stop); myservo13.write(pos_stop); myservo14.write(pos_stop); delay(500); }

Реализуем простое ИК-управление с пульта. Выбираем 7 клавиш, данные о кодах заносим в скетч в виде констант. И в цикле loop() реализуем логику выбора движений робота-паука при нажатии клавиш ИК-пульта. Программа получения кода get_ir_kod() вызывается по прерыванию CHANGE на входе 2. Используется Arduino библиотека IRremote.

К режиму управления робота с ИК-пульта добавим автономный режим. В автономном режиме робот будет двигаться вперед, при достижении препятствия робот будет делать поворот и опять двигаться вперед. Ультразвуковой датчик HC-SR04 позволяет определять расстояние до объекта в диапазоне от 2 до 500 см с точностью 0.3 см. Сенсор излучает короткий ультразвуковой импульс (в момент времени 0), который отражается от объекта и принимается сенсором. Расстояние рассчитывается исходя из времени до получения эха и скорости звука в воздухе. Если расстояние до препятствия меньше 10 см, робот делает поворот и движется дальше вперед. Переход из режима ИК-управления в автономный режим производим нажатием клавиш "желтая" и "синяя".

Для работы с датчиком HC-SR04 будем использовать Arduino библиотеку Ultrasonic. Конструктор Ultrasonic принимает два параметра - номера пинов к которым подключены выводы Trig и Echo:

#include "Ultrasonic.h" // trig -12, echo - 13 Ultrasonic ultrasonic(12, 13);

Получается такой код

// коды клавиш ИК пульта // lg 6710v00090d #define FORWARD 32 // pr + #define BACK 33 // pr - #define CIRCLE_LEFT 17 // vol- #define CIRCLE_RIGHT 16 // vol+ #define STOP 54 // зеленая #define SLEEP 55 // красная #define AWAKE 37 // ок #define EXT 50 // желтая #define AUTO 52 // синяя... .... ..... void loop() { delay(1000); if(ext==0) { float dist_cm = ultrasonic.Ranging(CM); Serial.print("dist_cm=");Serial.println(dist_cm); if(dist_cm<10.0) ir_kod=CIRCLE_LEFT; else ir_kod=FORWARD; } if(ir_kod!=0) { Serial.print("ir_kod=");Serial.println(ir_kod); switch(ir_kod) { case FORWARD: // вперед course(1); Serial.print("forward\n"); break; case BACK: // назад course(2); Serial.print("back\n"); break; case CIRCLE_LEFT: // вращение влево course(3); Serial.print("circle_left\n"); break; case CIRCLE_RIGHT: // вращение вправо Serial.print("circle_right\n"); course(4); break; case STOP: // остановка ir_kod=0; go_hor_all(); Serial.print("pause\n"); break; case SLEEP: // засыпание ir_kod=0; go_hor_all(); myservo11.detach();myservo12.detach(); myservo13.detach();myservo14.detach(); digitalWrite(13,LOW); Serial.print("sleep\n"); break; case AWAKE: // пробуждение ir_kod=0; myservo11.attach(5);myservo12.attach(6); myservo13.attach(7);myservo14.attach(8); digitalWrite(13,HIGH); go_hor_all(); Serial.print("awake\n"); break; case AUTO: // режим автономный //ir_kod=FORWARD; ext=0; myservo11.attach(5);myservo12.attach(6); myservo13.attach(7);myservo14.attach(8); Serial.print("auto\n"); break; default: break; } } } // получить код переданный с ИК пульта void get_ir_kod() { detachInterrupt(0); // отключить прерывание 0 if (irrecv.decode(&results)) { //Serial.println(results.value); if (results.value > 0 && results.value < 0xFFFFFFFF) { ir_dt = results.value; if(ir_dt==EXT && ext==0) {ir_kod = SLEEP;ext=1;} else if(ext==1) { if(ir_dt==FORWARD || ir_dt==BACK || ir_dt==CIRCLE_LEFT || ir_dt==CIRCLE_RIGHT || ir_dt==STOP || ir_dt==SLEEP || ir_dt==AWAKE || ir_dt==AUTO) ir_kod = ir_dt; } else ; } irrecv.resume(); } attachInterrupt(0, get_ir_kod, CHANGE); }

Архив со скетчем и библиотеками Ultrasonic и IRremote можно скачать ниже