Собираем роботов-самоходов на Arduino

26.01.2011, 09:18
Источник:

Обычно, в статьях, я стараюсь излагать материал в порядке его разработки, но думаю, что это не тот случай. Поэтому, пропустим этапы проектирования принципиальной электрической схемы, разводки печатной платы и всего прочего. На рисунке 1 смотрим какое «безобразие» у меня получилось.

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

Теперь все по порядку. На микроконтроллер Attiny2313 с двух инфракрасных датчиков поступает сигнал о препятствии (логическая единица или нуль). Затем, согласно, прошивки микроконтроллер управляет микросхемой драйвер двигателя L293D (ток управления до 1 Ампера). На рисунке 3 представлена фотография перевернутого робота.

Основой конструкции самодельного робота является согнутая в трапецию металлическая полоска. Угол изгиба порядка 120°. Принципиально важно, чтобы с обеих сторон получился одинаковый изгиб, иначе робот будет двигаться не прямолинейно. Хотя, с другой стороны, что плохо сделал механик или электроник, иногда может загладить программист, скажем, с помощью ШИМ добиться прямолинейного движения робота

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

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

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

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

В этой статье мы рассмотрим несколько схем роботов, в которых реализованы следующие варианты поведения:
1. Объезжает препятствие при контакте с ним "усиками".
2. Избегает препятствия без контакта (ИК бампер).
3. Упирается "усиками" в препятствие, отъезжает назад, делает поворот, затем продолжает движение.
4. Избегает препятствие с разворотом (ИК бампер).
5. Следует за объектом, сохраняя дистанцию (ИК бампер).

Перед тем как приступить к рассмотрению схем давайте кратко разберем особенности микросхемы L293.

Рис.1. Расположение выводов микросхемы L293D

Внутри нее имеется два драйвера для управления электромоторами.
Моторы подключаются к выходам OUTPUT. Мы имеем возможность подключить два двигателя постоянного тока.
8-й и 16-й выводы микросхемы подключаются к плюсу питания. Поддерживается раздельное питание, т.е. 16-й вывод (Vss) предназначен для питания самой микросхемы (5 вольт), а контакт Vs (8-й вывод) можно подключить к источнику питания для двигателей. Максимальное напряжение силовой части составляет 36 вольт.
Я их разделять не буду и во всех схемах подключу к общему источнику питания.
Минус питания или земля (GND) подключается к выводам № 4, 5, 12, 13. Эти контакты, кроме того, обеспечивают теплоотвод микросхемы, поэтому при пайке на плату для этих выводов желательно выделить увеличенную металлизированную область.
Еще микросхема имеет входы ENABLE1 и ENABLE2.
Для включения драйверов, необходимо наличие логической единицы на этих выводах, проще говоря 1-й и 9-й выводы подключаем к плюсу питания.
Также имеются входы INPUT для управления двигателями.

Рис.2. Таблица соответствия логических уровней на входах и выходах.

Выше представлена таблица, по которой можно понять, что если на вход INPUT1 подать логической единицу, т.е. соединить с плюсом источника питания, а вход INPUT2 - с минусом, то мотор М1 начнет вращаться в определенную сторону. А если поменять местами логические уровни на этих входах, то мотор М1 будет вращаться в другую сторону.
Аналогично происходит и со второй частью, к которой подключается мотор М2.

Именно эта особенность и использована в представленных схемах роботов.

Схема №1. Робот объезжает препятствие при контакте с ним "усиками".

Рис.3. Схема №1. С механическими датчиками препятствий.

После подачи питания моторы будут вращаться в определенную сторону, двигая робота вперед. Это происходит за счет того, что на INPUT1 через резистор R2 поступает сигнал высокого уровня, так же как и на входе INPUT4. Транзистор VT1 надежно закрыт, база стянута на минус питания, на коллектор ток не втекает.
Объяснять я буду по левой части, т.к. обе части симметричны.
На входе INPUT2 через резистор R3 устанавливается логический 0. Судя по таблице (рис.2) мотор вращается в определенную сторону. В правой части схемы происходит тоже самое и робот едет вперед.
В схеме имеются ключи (SB1, SB2), в качестве которых применены SPDT переключатели. На них с помощью термоклея прикрепляются скрепки и получаются датчики препятствий.

Рис.4. Из скрепок сделаны датчики "усики".

Когда такой датчик упирается в препятствие, ключ замыкается и вход INPUT2 оказывается подключенным к плюсу питания, т.е. подается логическая "1". В этот же момент времени открывается и транзистор, вследствие чего логическая единица на входе INPUT1 сменяется логическим нулем. Мотор при нажатой кнопке вращается в другую сторону. Рывками происходят микропереключения и мотор разворачивает робота от препятствия, до того момента, пока датчик перестанет соприкасаться с препятствием.

Как вы уже догадались, переключатели или сами моторы нужно расположить крест-накрест.

Схема №2. Робот избегает препятствия без контакта (ИК бампер)

Еще более интересное поведение можно реализовать, если в качестве датчиков использовать TSOP-приемники для приема инфракрасных сигналов. Это будет некое подобие ИК-бампера.
Итак, теперь схема выглядит таким образом.

Рис.5. Схема №2. С инфракрасными датчиками препятствий.

"Модуль приема ИК" работает так: при поступлении инфракрасного сигнала на TSOP-приемник на его выходе появляется отрицательное напряжение, которое отпирает PNP транзистор, и ток с плюса питания поступает на входную цепь микросхемы. Если в прошлый раз были использованы механические переключатели, с так называемыми усиками из скрепок, то новая схема позволит роботу не врезаться в препятствие, а реагировать на него с некоторой дистанции. Это выглядит так:

Приемная часть выполнена таким образом: два абсолютно одинаковых модуля (левый и правый) скрепленные между собой (рис.8).

В качестве приемников использованы TSOP1136 с рабочей частотой 36 кГц. Расположение выводов представлено на рисунке ниже.

Рис.6. TSOP1136.

С приемниками мы разобрались, но для обнаружения препятствий нужно в пространство перед роботом посылать инфракрасное излучение с определенной частотой. Рабочая частота приемников бывает разная, в моем случае она составляет 36 кГц. Поэтому на микросхеме NE555 был собран генератор импульсов на данную частоту, а к выходу подключены излучающие диоды инфракрасного диапазона.


Рис.7. Схема излучателя на NE555.

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

Рис.8. ИК бампер.

После подачи питания робот может попятиться назад, это из-за слишком большой чувствительности TSOP-приемников. Они воспринимают отраженный сигнал даже от пола, стен и других поверхностей. Поэтому в схеме излучателя ИК-сигнала (рис.7) использован подстроечный резистор, с помощью него уменьшаем яркость инфракрасных диодов и добиваемся желаемой чувствительности.

Схема №3. Такой робот отъезжает назад от препятствия, делая поворот.

Давайте рассмотрим еще одну интересную схему.

Рис.9. Схема №3.

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

Эта схема тоже полностью совместима с инфракрасным бампером, от предыдущей схемы.

В схеме появились электролитические конденсаторы между эмиттером и базовыми резисторами транзисторов VT1 и VT2. Появились диоды VD1, VD2 и светодиоды HL1, HL2.
Давайте по порядку разберем, зачем нужны эти дополнительные компоненты.
Итак, когда замыкается переключатель SB1, т.е. первый датчик, ток от плюса питания через диод VD1 и токоограничивающий резистор R1 поступает на базу транзистора. Он открывается, меняя логический уровень на входе INPUT1, на входе INPUT2 уровень тоже меняется.
В этот момент ток также поступает на конденсатор C1 и он заряжается. Мотор М1 резко меняет направление вращения и робот отъезжает назад от препятствия. На видео можно заметить, что второй мотор тоже меняет направление движения, но на более короткий промежуток времени. Это происходит из-за того, что при замыкании датчика SB1, ток от плюса питания поступает также и на правую часть схемы, через светодиод HL2. Светодиоды не только подают кратковременный сигнал о столкновении с препятствием, но и являются гасителем напряжения, поступающего на противоположную половину схемы. Проще говоря, при замыкании ключа SB1, конденсатор C2 заряжается меньше, чем C1. А при замыкании ключа (датчика) SB2 происходит тоже самое, но наоборот - С2 заряжается больше (т.е. напряжение на его обкладках больше). Это позволяет не только отъехать от препятствия, но и немного отвернуться от него. Угол этого отворачивания зависит от емкости конденсаторов C1 и С2. Конденсаторы емкостью 22 мкФ, на мой взгляд, являются оптимальными. При емкости 47 мкФ угол поворота будет больше.
Также на видео можно заметить, что после того, как робот отъезжает назад от препятствия, то присутствует небольшая пауза перед тем как он поедет вперед. Это происходит из-за разрядки конденсаторов, т.е. в некоторый момент времени логические сигналы на входах INPUT уравновешиваются и драйвер на секунду перестает понимать в какую сторону вращать мотор. Но когда C1 и С2 разрядятся, на входах INPUT установятся первоначальные логические уровни.
Диоды VD1 и VD2 препятствуют разрядке конденсаторов через светодиоды HL1, HL2. Без светодиодов схема не работает.

Схема №4. Предыдущая схема с ИК бампером.

Эта схема отличается от предыдущей тем, что вместо механических датчиков здесь использованы инфракрасные (ИК бампер).

Рис.10. Схема №4.

Коллекторы PNP транзисторов VT1 и VT2 при обнаружении препятствия, подадут сигнал на входную цепь микросхемы. Далее всё происходит также, как было описано ранее, только такой робот при обнаружении препятствия перед собой отъезжает назад, делает поворот, затем продолжает движение.
Поведение показано на анимации ниже:

У робота будет более резкое поведение, если уменьшить емкость конденсаторов C1 и C2 например до 1 мкФ (минимальная емкость 0,22 мкФ).

Как сделать так, чтобы робот следовал за объектом?

Во всех схемах, представленных выше, датчики-сенсоры или сами моторы должны быть расположены крест-накрест. А при прямом подключении (когда левый датчик "командует" левым двигателем, правый - правым) робот будет не избегать препятствие, а наоборот следовать за ним. Благодаря прямому подключению можно добиться очень интересного поведения робота - он будет активно преследовать объект, сохраняя определенную дистанцию. Расстояние до объекта зависит от яркости ИК диодов на бампере (настроить).

Еще немного фотографий:

В шасси использованы металлические детали от конструктора. Макетная плата откидывается для удобства замены батареек.

Питание робота осуществляется от 4-х батареек АА.

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

К этой статье имеется видео, в котором подробно описана работа схем и продемонстрированы разные варианты поведения робота.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
Элементы схемы №1 и №2 (кроме ИК бампера)
VT1, VT2 Биполярный транзистор

2N3904

2 В блокнот
R1, R2, R4, R6 Резистор

10 кОм

4 В блокнот
R3, R5 Резистор

4.7 кОм

2 В блокнот
C1 100 мкФ 1 В блокнот
Элементы "модуля приема ИК" на схеме №2, №4
VT1, VT2 Биполярный транзистор

2N3906

2 КТ361, КТ816 В блокнот
R1, R2 Резистор

100 Ом

2 В блокнот
C1, C2 Электролитический конденсатор 10-47 мкФ 2 В блокнот
Элементы "модуля излучения ИК сигнала" рис.7
R1 Резистор

1 кОм

1 В блокнот
R2 Резистор

1.5 кОм

1 В блокнот
R3 Переменный резистор 20 кОм 1 для настройки яркости FD1, FD2 В блокнот
C1 Конденсатор керамический 0.01 мкФ 1 В блокнот
C2 Конденсатор керамический 0.1 мкФ 1 В блокнот
FD1, FD2 ИК диод 2 Любой

Камрад SWG решил тоже побаловаться самобеглыми тачанками. И достал с антресоли давнюю разработку.

SWG:

Глядя на вашу бурную активность, я тоже решил шевельнуть ластами. Достал со шкафа сделанную еще в 2006г простенькую тележку (к коробке от CD-ROMа прикручены 2 самодельных колеса, 2 движка ДПМ-25-Н1-7Т с редукторами (27v, но неплохо тянут уже при 12, надо будет больше — сделаю преобразователь 12->27 ), и самодельный поворотный узел с роликом (третье колесо).

Потребление от 12v: 33 мА при выкл. двигателях, при макс. скорости без нагрузки (колеса не касаются пола) = 103 мА вперед, 115 мА назад. При одном заклиненном колесе — 300 мА, при обоих заклиненных колесах = 500 мА.
L293DN чуть теплая. Будет греться — приклею радиатор. Да, частоту ШИМ взял пока 500 Гц. (период 2 мс). Померяю скорость нарастания тока в двигателях — определю более оптимальную (За самый короткий импульс ток в двигателе должен успеть достигнуть максимума).
Максимальная скорость движения по полу сейчас 15-20 см/сек. Больше мне пока ни к чему, слишком быстро будет комнату пробегать. Диаметр колес = 80мм (резиновые “бублики” вроде от какой-то сантехники, полно на базаре).


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

SWG:

А также сделанную в том же году плату контроллера привода, которая в дальнейшем должна будет управляться уже от центрального контроллера, сама же имеет микроконтроллер PIC16F873 с двумя ШИМ ; L293DN ; MAX232 для RS232 ; стабилизатор LM2931 (5v) для питания микросхем; маленькую пищалку; а также разьемы для подключения двигателей (и довольно сложные фильтры для них); разьем, на который выведен порт B, земля и +5v, для подключения датчиков и приемника радиоуправления; разьем RS232 (Для связи с компьютером и выдачи отладочной информации); разьем с шинами I2C и SPI (для связи в будущем с центральным контроллером и прочей периферией).


Мыслим похоже, даже более чем. У меня сходная архитектура. Только я SPI не выводил. UART да i2c и преобразовние на RS232 повесил на кабель. А так почти то же самое, только контроллер AVR , а не PIC




SWG:

Еще на этой платке (50×85×15мм) есть делитель напряжения батареи с подстроечником, подключенный к одному из каналов АЦП PIC16F873 , для контроля напряжения аккумулятора (12v 1,3 А/ч, 95×40×50мм).
Ну и, конечно, разьем для подключения этой батареи. Для ускорения “оживления”, а также чтобы пощупать, что реально получилось, решил попробовать МикроПаскаль. На днях набросал несколько строк программки для инициализации ШИМ, UART , и простенький главный цикл, в котором проверяется состояние линий порта B, кнопки на которых пока задают команды “Вперед”, “Назад”, “Разворот на месте влево”, “Разворот на месте вправо”, “Скорость больше”, “Скорость меньше”. Отсутствие команд переводит в состояние “Стоп”.
При изменении коэффициента ШИМ в канал RS232 выдаю “#” и два байта — коэффициенты левого и правого ШИМ . Пока для начала оба меняю одинаково. Для того, чтобы задавать одним байтом значение ШИМ , ограничился интервалом 0-255. Подумывал даже сделать всего 16 ступенек, тогда бы одним байтом можно было бы хранить значения обоих ШИМ (в младшей и старшей тетрадах), но решил, что пока экономить рано.

При проверке кнопок сделал защиту от дребезга по 1мсек. Для замедления работы главного цикла ввел в него задержку 50 мсек. В дальнейшем эти процедуры опроса линий порта B и управление ШИМ ом посажу на многозадачное прерывание от таймера, которое будет обслуживать часы, календарь, и с десяток программных таймеров от милисекунд до секунд.
Еще один таймер, имеющий выход на С0, заведен у меня на пищалку, через сьемную перемычку, конденсатор и ограничительный резистор.

Сегодня зашил программку в микросхему, собрал все в кучку, включил — все работает, как и должно. (Естественно, только то, что уже написано в программе). Движки по командам крутятся вперед, назад, в разные стороны, ускоряют и замедляют вращение.При изменении параметров ШИМ вижу новые значения в компьютере (через “Гипертерминал”, на 9600 бод). Просмотрел все сигналы осциллографом — все, как и должно быть.
Даже не интересно. Нет, чтобы помучаться, понастраивать… К сожалению, уже лет 20 лишен такого удовольствия. Обычно все работает сразу. Сказывается наличие опыта… Ничего, когда понавешаю датчиков, всех тех заморочек, что запланировал, вот тогда и начнется настоящая работа над машинным интеллектом. Будет труднее, но интересней.

Я вот сейчас тоже хочу заказать парочку сонаров. Потом разведу плату датчиков и будет веселуха:) Ну и попутно отладочный модуль делаю.

SWG:

Немножко технических данных. Кварц пока поставил 4,0 Мгц. Это 1.000.000 команд/сек, для ровного счета. Будет мало — поставлю 8, 16 или 20. Микросхемы PIC16F873A и PIC16F876A на 20Мгц у меня есть, кварцы тоже.
Программа, хоть и на Паскале, заняла пока 583 байта (14%) ПЗУ, и 32 байта (18%) Озу. Если поставить вместо 873 -> 876, у него памяти в 2 раза больше, остальное то же самое. Листинг программы, (не считая комментариев) = 110 строк. Скомпилированный в ассемблерный — раз в 5 больше. (с комментариями асс. листинг = 930 строк, Паскалевский — 180). HEX — код на эмуляторе (PIC Simulator IDE v6.65) пролетел без проблем.

Начало положено, продолжение следует…



В нашем полку терминаторов прибыло? ;)

Post navigation

61 thoughts on “Робот на контроллере PIC от SWG”

  • Этот сайт использует Akismet для борьбы со спамом.

    Вступление

    В эллинистическую эпоху, на острове Фарос был маяк, на котором были установлены четыре статуи. Эти статуи через определённые промежутки времени, поворачиваясь, отбивали склянки; в ночное же время они издавали трубные звуки, предупреждая мореплавателей о близости берега.

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

    1495 год. Леонардо да Винчи разрабатывает детальный проект механического человека, способного двигать руками и поворачивать голову. Механизм выглядит как бронированный рыцарь.

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

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

    Цели, задачи, а также приветствие

    Здравствуйте, многоуважаемые радиокоты и радиокошки! Так как сам я ещё котёнок, как в области радиолюбительства, так и в области моего физического возраста, то и устройства, создаваемые мной, должны быть детскими и выполнять роль игрушки(да и вообще, данная статья будет интересна только начинающим). А что будет выполнять роль игрушки, вы уже, наверное, догадались. Что же оно будет делать? Хм... О! А пусть оно следует за нарисованной линией, ведь это почти следование по заданной траектории! (можно будет заставить его таскать бутерброды от холодильника к рабочему месту, что бы не отвлекаться от любимого занятия:)) И так, мы вплотную подошли к целям моей работы, а точнее цели :

    • Создать робота (действующую модель), который будет следовать за нарисованной на белом листе бумаги линией.

    Задачи:

    • Создание принципиальной электрической схемы
    • Создание программы для созданной платформы
    • Сборка робота, согласно схеме
    • Тестирование, отладка
    • Анализ результатов

    Создание действующей модели робота

    Итак, создание принципиальной электрической схемы:

    Начальная схема выглядит так:

    Главная часть схемы - 8- битный МК семейства mega от фирмы Atmel. Именно он выполняет функцию контроллёра поведения робота. В нём заложена программа. Он получает сигналы от двух датчиков - фототранзисторов L32P3C (можно любые другие, лишь бы реагировали на свет). Когда фототранзистор освещён, он пропускает ток, и импульс появляется на выводе МК. МК, получив сигнал высокого уровня, в зависимости от того есть ли сигнал на другом фототранзисторе, посылает сигнал на входы драйвера двигателей L293D, который усиливает эти сигналы (т.к. выводы МК не способны выдерживать ток больше 20мА) и передаёт их на двигатели M1 и M2, которые вращаются. Z1, C1 и C2 задают тактовую частоту МК, в данном случае она установлена на 4МГц, то есть контроллёр будет выполнять 4 миллиона операций в секунду. Всем известно, что правильное питание - залог здоровья, поэтому C3, C4 и VR1 выполняют функцию стабилизатора напряжения, для уничтожения нежелательных помех.

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


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

    Алгоритм работы:

    Алгоритм работы достаточно прост(подразумевается, что датчики находятся по разные стороны линии)

    Небольшие поясниения:

    Если участок линии, на которой находится робот, прямой, то от обоих датчиков будет идти сигнал.

    Соответственно нужно вращать оба мотора.

    Если участок линии, направлен влево, то на левом датчике будет отсутствовать сигнал.

    Тогда нужно подать напряжение на правый двигатель.

    Если же отсутствует сигнал на правом датчике, то имеет место поворот направо.

    Естественно, нужно вращать левый мотор.

    Собственно, разработка программы.

    В качестве языка разработки был выбран распространённый и мощный язык программирования C.

    Разберу, только основной блок, весь код смотрите ниже.

    while (1)
    {
    PORTC.0 = PIND.0;
    PORTC.2 = PIND.1;
    }

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

    Загружая из порта D (ответственен за датчики) в необходимые выводы порта C (именно он ответственен за движение робота) мы заставляем робота реагировать как на одиночные импульсы от разных датчиков, так и от обоих вместе.

    Итак, мы подошли к сборке робота, согласно схеме.

    Сборка управляющей платы.

    Управляющая плата, это плата с микроконтроллером, которая будет контролировать поведение робота. Её схема:

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

    Сборка стабилизотора напряжения и драйвера двигатетей.

    На схеме это:

    Собирается так же недолго, вот, что у меня получилось:

    Сборка блока датчиков.

    Блок датчиков отвечает за приём информации о мире. На схеме это:

    Схема настолько проста, что собирается в течении 3-х минут. Конечный результат:

    После соединения всех блоков получаем:


    Естественно, я никого не заставляю собирать робота именно таким образом, просто сборка данным образом даёт некую "взрослую" систематизацию.

    Тестирование, отладка.

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

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

    Естественно, я ошибался. Робот не то что медленно ехал, он просто стоял на месте.

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

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

    Отладка датчиков

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

    Переменные резисторы позволяют настроить чувствительность. Затем можно померить сопротивление переменного резистора и поставить уже постоянный. Кстати, оптимальное сопротивление резистора в моём случае равно 9.1 кОм. Также были добавлены светодиоды, которые позволили датчикам работать даже в тёмных помещениях. Конечный результат:

    Отладка программы

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

    Была разработана функция:

    void PWM (unsigned char vector)

    Return ;

    Опытный радиолюбитель скажет, что никакой это не ШИМ, и он будет прав. Но всё же данная функция позволяет регулировать скорость робота. (конечный код смотрите ниже в списках файлов)

    И вот когда сборка и отладка закончены, настаёт время проверить работоспособность робота (там на фоне играла музыка, но youtube её убрал =()

    Анализ результатов

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

    • Создание программы.
    • Создание электромеханической платформы . Остановимся на этом моменте поподробнее. Конечная ЭМП получилась такой, что её можно применять для решения таких простых задач как: прохождение лабиринта, как двухмерного, так и трёхмерного, следование за источником света, он может рисовать (достаточно прикошачить присобачить к корпусу фломастер), робот даже может участвовать в таких робототехнических соревнованиях, как кегельринг.
    • Отладка системы.
    • И самое главное - робот двигается по линии.

    Заключение

    В заключение обязательно нужно что-то сказать. А скажу я вот что:

    Дело это:

    • Финансово затратное
    Начнем с концепции: мы хотим робота, который может самостоятельно передвигаться по комнате, при этом объезжать все препятствия, встречаемые на своем пути.
    Задачу поставили. Теперь бегом по магазинам! 1) Платформа. Есть такие варианты: сделать самому всё, купить детальки (например Tamiya) и собрать из них, либо же купить готовое. Я остановился на последнем варианте. Вид танка, ну или трактора мне почему-то пришелся более по душе, и в итоге я остановился на таком варианте (платформа от DF robot ):

    В комплекте - платформа (по одному мотору на каждой гусенице) и отсек для батареек.
    Ну, тут ничего сложного, поехали дальше.

    Дальномер
    Сонар (он же дальномер, он же Ultrasonic module) В качестве дальномера изначально выбор был между ультразвуковым и инфракрасным. Поскольку характеристики ультразвукового существенно лучше (максимальная дальность около 4-5 метров, против 30-60 см), а цена примерно одинаковая, то выбор пал на Ultrasonic. Наиболее распространена модель HC-SR04 .

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

    Подаем на ножку Trig сигнал, длительностью 10мкс, что запускает генератор, создающий пачку коротких импульсов на передатчике (8 шт). Далее, приемник получает отраженный сигнал и на ножке Echo генерируется прямоугольный сигнал, длина которого пропорциональна времени между излучением импульсов и детектированием их приемником.

    Реальное время, за которое звук дойдет до приемника, конечно же, составит копейки. Что бы по нему определить расстояние, можно воспользоваться нехитрой формулой:

    s=vt/2 , s - расстояние, v - скорость звука, t - время получения сигнала на приемнике.

    Ну почему пополам делим, думаю всем понятно. Только в данном случае эта формула не нужна. Привожу ее здесь исключительно для понимания физики процесса.
    С выхода Echo идет уже сформированный сигнал, с достаточно большой длительностью. Заглянув в даташит, мы увидим формулу пересчета: s = t/58 , s - расстояние, t - длительность импульса Echo, s - расстояние в сантиметрах.

    Ок, вроде все основы разобрали. Перейдем к коду под Arduino:

    Const int Trig = 3; // обозначим к какой ножке и что подключаем const int Echo = 2;
    void setup()
    {
    pinMode(Trig, OUTPUT);
    pinMode(Echo, INPUT);
    Serial.begin(9600); // Инициализируем сериал порт, дабы вывести результат на монитор
    }

    Unsigned int time_us=0; // Переменная для хранения временного интервала
    unsigned int distance_sm=0; // Переменная для хранения расстояния в сантиметрах

    Void loop()
    {
    digitalWrite(Trig, HIGH); // Подаем сигнал на выход микроконтроллера
    delayMicroseconds(10); // Удерживаем 10 микросекунд
    digitalWrite(Trig, LOW); // Затем убираем
    time_us=pulseIn(Echo, HIGH); // Замеряем длину импульса
    distance_sm=time_us/58; // Пересчитываем в сантиметры
    Serial.print(distance_sm); // Выводим на порт
    Serial.print(" ");
    delay(500);
    }

    Драйвер
    Ну что же, с сонаром вроде разобрались. Продолжим.
    Платформа содержит 2 мотора. Ими надо как-то управлять. Казалось бы - подключил их напрямую, подавай то HIGH то LOW и радуйся. Тут одно существенное «НО» - с атмеги не получишь ток выше ~40мА, а мотору надо где-то на порядок больше.

    Как быть? Первое что приходит в голову это - поставить на выход микроконтроллера транзистор и с него уже питать моторы. Это конечно хорошо, но не прокатит, если мы захотим мотор в другую сторону пустить… Зато с этой задачей хорошо справится H - мост, который представляем собой немного более сложную схему, чем пара транзисторов. Но в данном случае их полно в виде готовых интегральных схем, так что думаю велосипед изобретать незачем - купим готовый. К тому же цена располагает - 2-3 доллара…

    Двинемся дальше. Для этих целей я себе купил микросхему L293D , собственно о которой речь дальше и пойдет. Она проста в использовании, повсеместно доступна и имеет удобный корпус Dip16.
    Её максимальный ток сравнительно небольшой (600 мА), что для конкретной задачи более чем достаточно. Если нужно больше, то есть, например, L293B (1А) и т.д…
    Чуть не забыл, сей мост позволяет подключить к нему 2 мотора, по одному с каждой стороны.
    Что бы понять, как взаимодействовать с ним, я нашел , ею и воспользуемся:

    Все просто и наглядно. Внимательно изучив первую часть статьи, остановим взор на рисунке:

    Схема включения данной микросхемы, собственно, взятая из даташита.

    Кратко пробежимся по её ножкам:

    1) Инициализация мотора1. Пока вы не подадите на эту ножку HIGH, что бы вы не делали с остальными, моторчик не заработает. Хоть и написано 1,2E - мотор там один. Не путайте. Дело в том, что для управления одним мотором вам понадобится 2 ножки микроконтроллера, а соответственно и H - моста. Подадим на одну ножку HIGH, другую LOW - мотор закрутился в одну сторону. Подадим на первую LOW, вторую HIGH - закрутится в противоположную. подадим на обе LOW - остановится.
    2) 1A . На эту ножку вы будите посылать сигнал с микроконтроллера(слаботочный) для управления 1 входом мотора.
    3) 1Y . А это уже сигнал(большой ток), который идет непосредственно на мотор. По своему виду он полностью повторяет сигнал, подаваемый на вход 1A .
    4) - 5) Земля
    6) 2Y Сюда подключаем вторую ножку мотора.
    7) 2A Сигнал с микроконтроллера для управления втором входом мотора.
    8) Сюда мы подаем напряжение, которым будут питаться моторы. По-сути, что подадим на этот вход, то и будет отпираться на ножках 1Y , 2Y .
    9) - 16) Полная аналогия с первыми восемью, но для второго мотора.

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

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

    Const int motor1Pin = 3; // H-bridge leg 1 (pin 2, 1A)
    const int motor2Pin = 4; // H-bridge leg 2 (pin 7, 2A)
    const int enablePin = 9; // H-bridge enable pin
    void setup()
    { // set all the other pins you"re using as outputs:
    pinMode(motor1Pin, OUTPUT);
    pinMode(motor2Pin, OUTPUT);
    pinMode(enablePin, OUTPUT); // set enablePin high so that motor can turn on:
    digitalWrite(enablePin, HIGH);
    }

    Void loop()
    { // Вращаем мотор в одну сторону
    digitalWrite(motor1Pin, LOW); // set leg 1 of the H-bridge low
    digitalWrite(motor2Pin, HIGH); // set leg 2 of the H-bridge high delay(1000); // А через секунду в другую digitalWrite(motor1Pin, HIGH); // set leg 1 of the H-bridge high
    digitalWrite(motor2Pin, LOW); // set leg 2 of the H-bridge low delay(1000);
    // А теперь всё сначала
    }

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

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

    Черный - GND
    Красный - 5V
    Белый - Сигнал

    Мотор управляется контроллером (не пугайтесь - ничего покупать не надо, он уже есть внутри серво), который, получая внешний сигнал - контролирует, что бы мотор повернулся на заданный угол. Для этих целей с мотора заведена обратная связь на контроллер, которая представляет собой переменный резистор, меняющий своё сопротивление в зависимости от угла поворота. Сам контроллер управляется длиной входного импульса. Как правило: 380 - 400 мкс - 0 градусов, 2200мкс - 180 градусов. Приведем простой алгоритм управления серво для Arduino:

    #define ServoPin 2 // На эту ножку мы подключим наше серво (его белый провод)
    void setup()
    {
    pinMode(2,OUTPUT);
    }

    Void Servo_motion(int angle) // функция управления серво
    {
    int time=390+10*angle; // Пересчитываем заданный угол поворота в длину импульса, который подадим на //серво
    digitalWrite(ServoPin, HIGH); // Сигнал пошел
    delayMicroseconds(time); // Удерживаем его заданное время
    digitalWrite(ServoPin, LOW); // Выключаем его
    delayMicroseconds(20000-time); // Даем серво время, что бы повернуться (20000 мкс - 50 гц)
    }

    Void loop()
    {

    For(int i=0;i<=180;i++)
    {
    Servo_motion(i); // Прокрутим серво в одну сторону
    delay(10); // C задержкой 10 миллисекунд на каждом градусе
    }

    For(int i=180; i>=0; i--)
    {
    Servo_motion(i); // Затем в другую сторону
    delay(10);
    }

    Но в дальнейшем, мы будем использовать специальную библиотеку для управления серво, вот её описание:

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

    Myservo.attach(9); // attaches the servo on pin 9 to the servo object

    А то ничего не заработает. И последнее что хотелось бы добавить - данный пример доступен как по вышеуказанной ссылке, так и в среде разработки Arduino во вкладке «Examples».

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

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

    4 ножки - входы H моста, по 2 на каждый мотор:
    1A - 11
    2A - 6
    3A - 10
    4A - 5

    EnablePin - 12

    1 Ножка под 1,2EN и 3,4EN - посадил их вместе, так как оба мотора все равно по отдельности нам не нужны. В принципе вообще, можно эти 2 ножки моста к Arduino не подключать, а просто подать на них 5V.

    2 ножки для сонара:
    Trig - 3
    Echo - 2

    Ножка для подключения серво:
    Servo - 8

    На этом вроде бы и всё. Далее, в процессе сборки робота, я столкнулся с одной проблемой - периодически робот останавливался, Arduino перезагружалось. Немного подумав, я понял что Arduino nano неспособен питать всю эту систему (H-мост, серво, сонар) от своего штатного стабилизатора. Потому на помощь мне пришел стабилизатор напряжения 7805 (L7805, LM7805). Прибор прост в применении, имеет 3 ножки: вход(6 - 35 В), земля, выход(~5В). Даташит к нему можно повсеместно найти в интернете. Объединив его землю, с землёй Arduino и, соответственно с минусом аккумулятора тоже. Я сделал так - от Arduino я питаю только H - мост, а всё остальное (серво, сонар) от стабилизатора. После этого робот стал отлично работать без сбоев. Да, не забывайте важное правило - земля в любой схеме должна быть общей для всех элементов! Ну, по поводу самих моторов, я думаю понятно - подаем напряжение с аккумулятора на вход моста - Vcc2. Ну вроде с подключением разобрались, проиллюстрирую вышесказанное фотографиями:

    Вся схема:

    Стабилизатор напряжения (конденсаторы можно не ставить):

    Шлейф от сонара:

    H – мост:

    Немного о самой конструкции: обошлось без излишеств). Вырезал из пластика крышку на платформу, в ней было проделано отверстие для крепления серво. Из того же пластика выгнута (предварительно нагрев промышленным феном) Г - образная скобка. К ней приклеен четырехжильный шлейф (под PLS вилку, с шагом 2.54мм), в который уже и вставляется сам сонар.

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

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

    Объявление переменных:
    Переменная, для реализации алгоритма работы сонара - unsigned int time_us=0;
    Расстояние, определяемое сонаром - unsigned int distance_sm=0;
    Данная переменная используется в цикле loop для того, что бы при включении робот «осмотрелся» на месте, а потом уже поехал -
    unsigned int circle=0;
    Расстояние до ближайшего объекта спереди - unsigned int dist_f=0;
    Расстояние до ближайшего объекта слева - unsigned int dist_l=0;
    Расстояние до ближайшего объекта справа - unsigned int dist_r=0;
    Расстояние до ближайшего объекта под углом 45 градусов - unsigned int dist_45=0;
    Расстояние до ближайшего объекта под углом 135 градусов - unsigned int dist_135=0;

    Константа времени(мс), определяющая минимальный шаг движения робота. Подобрана экспериментально. В зависимости от скорости движения и скорости вращения серво вашего робота, возможно придется её изменить. Позже станет более понятно для чего она нужна -
    unsigned int t=15;

    Функции:
    sonar() - реализует алгоритм работы сонара, возвращает расстояние [см].
    forward (), back (), right (), left () - наши базовые функции движения.
    Основная функция, реализующая движение -

    Void motion (char dimention, int prev_angle, int next_angle, int time)
    {
    /*Данная функция одновременно управляет как и вращением моторов, так и серво.
    char dimention - направление движения
    int prev_angle - предыдущее положение серво
    int next_angle - положение, на которое хотим установить серво
    int time - временной шаг одного движения робота*/

    // Величина, на которую изменяется угол в процессе движения -
    int a;
    if(next_angle>=prev_angle)
    a=15;
    else
    a=-15;
    if (dimention=="f")
    {
    // Если сказано двигаться вперед, то
    int i=prev_angle;
    while(i!=next_angle)
    {
    /*Пока не достигли заданного значения угла, будем в цикле постепенно изменять текущее положение серво на величину a*/
    i+=a; myservo.write(i); // И передавать это значение на серво
    forward(); // После чего делаем движение вперед
    delay(time); // В течении временного интервала time
    }
    }

    /* Аналогичный алгоритм для движения влево, вправо, назад и стоянии на месте*/

    Void front_motion(int time)
    {
    /* Функция, которая осуществляет небольшой «доворот» робота в одну из сторон, если объект расположен под углами 45 и 135 градусов*/
    if(dist_45<=9)
    { // Если расстояние до объекта под углом 45 градусов меньше 9см, поворачиваем налево
    left();
    delay(3*time); // В течении трех минимальных интервалов движения
    }
    /* Аналогичный алгоритм для «доворота» вправо */

    }
    void motion_back(int time)
    {
    /* Движение робота назад в течении времени 2*time, с поворотом серво от угла 180 градусов, на угол 180 градусов*/
    motion("b",180,90,2*time);
    }
    void loop()
    {
    // Наша главная функция, реализующая итоговый алгоритм работы
    if (circle==0)
    {
    //Если робота только что включили, установим серво в начальное положение.
    myservo.write(0); //И «осмотримся» по сторонам
    dist_r=sonar();
    motion("w",0,45,t);
    dist_45=sonar();
    motion("w",45,90,t);
    dist_f=sonar();
    motion("w",90,135,t);
    dist_135=sonar();
    motion("w",135,180,t);
    dist_l=sonar(); } // Больше мы данное действие производить не будем
    circle++; i
    f(dist_f>=25)
    { // Если до ближайшего объекта спереди более 25 сантиметров
    a: //Двигаемся вперед, при этом осуществляем поворот серво от 180 до 135 градусов
    motion("f",180,135,t); //Сделаем замер расстояния до объектов под углом 135 градусов
    dist_135=sonar(); //Если необходимо, сделаем доворот
    front_motion(t); //Далее аналогично, но с другими значениями
    motion("f",135,90,t);
    dist_f=sonar();
    front_motion(t);
    motion("f",90,45,t);
    dist_45=sonar();
    front_motion(t);
    motion("f",45,0,t);
    dist_r=sonar();
    front_motion(t);
    motion("f",0,45,t);
    dist_45=sonar();
    front_motion(t);
    motion("f",45,90,t);
    dist_f=sonar();
    front_motion(t);
    motion("f",90,135,t);
    dist_135=sonar();
    front_motion(t);
    motion("f",135,180,t);
    dist_l=sonar(); front_motion(t); // Если расстояние спереди все еще больше 25 сантиметров, то вернемся в точку "a"
    if (dist_f>=25)
    goto a;
    }
    else
    { //Если нет
    if(dist_f<5)
    { // Если робот уже слишком близко к ближайшему объекту, то делаем движение назад
    motion_back(t);
    // Производим новый замер расстояния
    dist_f=sonar();
    } //При этом поворачиваем в ту сторону, где больше свободного места
    if(dist_l>=dist_r || dist_135>dist_r)
    {
    motion("l",180,90,t);
    dist_f=sonar();
    }
    if(dist_l {
    motion("r",180,90,t);
    dist_f=sonar();
    }
    } // Далее новый круг
    }

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