RoboClub - Проекты

Where AI meet the real world

 
Главная страница
 

Проекты
- проект дня
- андроиды
- экоскелеты
- beam-роботы
- мобильные роботы
 

Подписка на новости
RoboClub:
Е-Mail:
Формат писем:
Подписаться
Отказаться

"Делаем робота вместе!": наша практика

Благодарим всех, кто участвует в обсуждении этого проекта!
Отдельная благодарность Михаилу Клокову и Михаилу Николаеву
за внимание к "начинающим" и полезные советы!

Концепция

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

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

Обсуждение этого проекта (как конструктивных решений, так и хода его выполнения) по-прежнему продолжается на форуме.

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

Шасси

Кандидат на переделку Электромеханическую часть было решено взять, по возможности, готовую. В качестве "кандидата" был рассмотрен радиоуправляемый джип с давным-давно потерянным пультом.
 
Джип имел привод на задние колеса с дифференциалом между полуосями; передние колеса - поворотные, с рулевой трапецией; поворот колес производится электродвигателем, при прекращении его работы колеса пружиной возвращаются в среднее положение.
 
Питание осуществлялось от 6 элементов АА, расположенных в двух отсеках (4 + 2), имелся разъем для подключения внешнего источника питания напряжением 9В.
 
"Вскрытие показало", что оба двигателя - ходовой и поворота, - находятся в рабочем состоянии, что и решило судьбу кандидата.

Система управления

Плата системы управления Для системы управления взят кусок макетной платы, такой, что на нем можно разместить систему управления двигателями и один или два микроконтроллера с соответствующей "навеской" (см. фото).

Управление двигателями

Управление обоими двигателями построено на одной микросхеме L293D (отечественный аналог - КР1128КТ4А). Схема включения - типовая для подобного случая (см. спецификацию) На фото показан один из каналов, второй - идентичен.
 
Предусмотрена возможность раздельного питания электронной части системы управления (третья снизу шина) и собственно двигателей (нижняя шина).
 
Для наглядности микросхема установлена без теплоотвода, который может быть поставлен, если в этом возникнет необходимость.
 
Схема включения приведена здесь (второй канал подключается аналогично: 10 и 15 - входы, 11 и 14, соответственно, выходы, 12, 13 - "земля", 9 - включение моста). Пока оба моста включены "принудительно" (т.е. на линии включения 1 и 9 подано напряжение питания микросхемы с "ноги" 16), в перспективе их можно будет использовать, к примеру, для управления скоростями вращения двигателей, подавая на них широтно-модулированный сигнал. Если нагрузка велика, к выводам 4, 5, 12, 13 подпаивается теплоотвод (см. спецификацию микросхемы на "Книжной полке").

Микроконтроллер

Основной критерий при выборе микроконтроллера в данном случае - простота использования для решения наших задач (с точки зрения быстродействия, объема памяти, энергопотребления и пр. здесь может быть использован практически любой современный микроконтроллер), поэтому останавливаемся на семействе AVR фирмы Atmel.

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

Плата системы управления Из практических соображений ищем контроллер в корпусе DIP с не более, чем 28 выводами. Это, к примеру, ATtiny12/26/28, AT90S1200/2313, ATmega8 и др. Из того, что есть в наличии, выбираем AT90S2313-10PI: корпус DIP20, Flash-память 2К, 15 портов ввода-вывода, напряжение питания 4.0-6.0 В.

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

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

Подключение контроллера

контроллер AT90S2313-10PI Итак, контроллер AT90S2313-10PI имеет 20 выводов из которых пять "заняты": два - питание (VCC и GND), два - для подключения "кварца" (XTAL1 и XTAL2) и "Сброс" (RESET). Остальные 15 могут быть использованы для ввода/вывода информации и представляют два порта - B (PB7..PB0) и D (PD6..PD0).
 
Порт В - это 8-битный двунаправленный порт ввода/вывода. PB0 и PB1 могут также использоваться как положительный (AIN0) и отрицательный (AIN1) входы встроенного аналогово компаратора, PB3 - для получения сигнала широтно-импульсной модуляции (OC1).
 
Порт D имеет семь двунаправленных линий ввода/вывода PD6..PD0. В то же время, PD0 может использоваться как ресивер (RXD), а PD1 - как трансивер (TXD) интерфейса обмена данными (UART), PD2 и PD3 - как входы для сигналов внешних прерываний (INT0 и INT1), PD4 и PD5 - в качестве входов таймеров/счетчиков (TO и T1), а PD6 - для управления ими (ICP). Линии PB5-PB7 используются для внутрисхемного программирования контроллера (MOSI, MISO, SCK).
 
Плата системы управления Для управления двигателями нам требуется четыре линии: "вперед", "назад","вправо", "влево". Исходя из того, что нужно оставить незанятыми вводы, которые могут понадобиться в перспективе, берем для управления двигателями линии PB4..PB7. Чтобы подключение линий PB5..PB7 к драйверу двигателей (микросхема L293D) не отражалось на работе внутрисхемного программатора, питание драйвера во время программирования лучше отключать.

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

Теперь определяемся с датчиками. Порт В не трогаем: входы аналогового компаратора (AIN0, AIN1) резервируем на будущее, три оставшихся линии PB2..PB7 могут понадобиться для подключения дополнительных выходных устройств, например, индикатора, пьезодинамика и пр.
 
Входы таймеров/счетчиков (Т0 и Т1) лучше использовать по прямому назначению, а вот входы внешних прерываний (INT0, INT1) удобно назначить для получения сигналов от контактных датчиков ("бамперов"). Соответственно линии FD0 и FD1 можно выделить для датчиков освещенности.
 
Получившаяся в результате схема подключения контроллера приведена здесь.

Программирование

Плата системы управления Убедившись, что управление двигателями работает правильно, можно переходить к написанию управляющей программы.
 
Чтобы программу было легче отлаживать, можно на время отключить двигатели и подключить вместо них по паре светодиодов, включенных встречно: в этом случае зажигание одного диода из пары будет соответствовать вращению двигателя в прямом направлении, а другого - в обратном (см. фото справа).
 
Сигналы от датчиков можно имитировать переключателями. Пример простой программы, которая определяет, на каких линиях PD0..PD3 есть сигнал и выставляет соответствующие значения на линиях PB7..PB4, приведен здесь.

Обратите внимание, что если оба сигнала управления двигателем (например, "вперед" и "назад") выключениы, либо оба включены - двигатель будет отключен.

Структура программы

Прежде всего, уточним алгоритм работы программы: при рассеянном освещении - "свободный поиск", при появлении источника света - движение к источнику, при столкновении с препятствием - отъезд.
 
Поскольку, как уже указывалось, выбранный контроллер поддерживает обработку внешних прерываний, удобно сигналы от контактных датчиков ("бамперов") подключить на входы внешних прерываний (INT0, INT1), а процедуру отъезда от препятствия оформить как программу обработки соответствующего прерывания. Задачи "свободного поиска" и "движения на свет" возложим на "основную" программу.

Максимально упрощая ситуацию, откажемся на первых порах от управления скоростью движения и углом поворота. Тогда получим следующие режимы движения:

Режим Ходовой двигатель Двигатель поворота
"вперед" (F) вперед стоп
"вперед-вправо" (FR) вперед вперед
"вперед-влево" (FL) вперед назад
"назад" (B) назад стоп
"назад-вправо" (BR) назад вперед
"назад-влево" (BL) назад назад
"стоп" (STOP) стоп стоп

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

Реализация "свободного поиска"

С тем, чтобы наша конструкция "ожила" как можно раньше, начнем со "свободного поиска".
 
В простейшем случае можно, используя генератор случайных чисел, выбирать режим движения и его продолжительность действительно случайным образом. Однако, на практике этот метод не слишком хорош по крайней мере по двум причинам: во-первых, мы хотим добиться поведения робота, которое бы выглядело "свободным", вряд ли поэтому беспорядочные рывки и метания будут хорошо смотреться; во-вторых, некоторые сочетания режимов (например, "полный назад" - "полный вперед") могут быть опасны для самой конструкции.
 
Выйти из этого положения можно разными способами. Можно, скажем, сопоставить разным режимам разные вероятности: например, сделать более вероятным движение вперед, включая повороты, и менее вероятным - движение задним ходом.
 
Наилучший же, как нам кажется, в данном случае подход - это сделать вероятность включения того или иного режима зависимой от режима текущего. К примеру, можно задать, что если в данный момент робот движется вперед, то в следующий - он с наибольшей вероятностью будет продолжать движение, с несколько меньшей - повернет направо или налево, либо остановится, но не сможет (т.е. вероятность равна 0) двинуться назад.
 
Таким образом, в качестве алгоритма "свободного поиска" удобно взять цепь Маркова, причем первого порядка для начала будет вполне достаточно.

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

Попробуем составить таблицу вероятностей переходов:

Текущее
сост.
Вероятность перехода в... (%)
STOP F FR FL B BR BL
STOP 14 29 14 14 14 7 7
F 7 36 29 29 0 0 0
FR 7 43 43 7 0 0 0
FL 7 43 7 43 0 0 0
B 29 0 0 0 29 21 21
BR 36 0 0 0 36 21 7
BL 36 0 0 0 36 7 21

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

Блок отъезда

Блок отъезда от препятствия реализовать очень просто: устанавливаем на модель передний и задний контактные датчики - "бамперы" (пример конструкции простого бампера см. в разделе "Компоненты и конструкции"). Один из контактов обоих датчиков подключаем к "земле", а другие контакты подключаем к выводам контроллера INT0 и INT1 (PD2 и PD3). Программно подключаем к этим линиям "подтягивающие" резисторы. Таким образом, при отсутствии сигнала эти входы будут установлены в "1", а при замыкании контакта - будут "сбрасываться" в "0", что и вызовет прерывание.
 
Программа обработки прерывания заставляет робота отъехать от препятствия (т.е. при срабатывании переднего датчика робот двинется назад), причем направление движения будет противоположным тому, что привело к столкновению: так, если робот в момент столкновения двигался "вперед-влево", то отъезд будет "назад-вправо".

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

Движение к источнику света

Движение на свет также для начала реализуем в простейшем варианте: подключим пару фоторезисторов между входами PD0, PD1 и "землей". Программно подключим к этим входам "подтягивающие" резисторы. Пока освещенность фоторезисторов мала, их сопротивление составляет насколько сотен килоом, поэтому за счет "подтягивающих" резисторов на входах будет высокий уровень. По мере роста освещенности сопротивление резисторов будет падать, и также падать будет напряжение на соответствующих входах, пока не достигнет порога нижнего уровня. Когда это произойдет на данном входе установится логичеcкий "0".

Изменить степень чувствительности модели к свету можно поставив переменный резистор последовательно с фоторезистором (чтобы уменьшить чувствительность), либо параллельно (чтобы увеличить ее).

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

Что у нас получилось

Электроника

Итак, вот что у нас получилось (первая схема - "контроллерная" часть, вторая - драйвер двигателей; выводы "к драйверу двигателей" с первой схемы подключаются к точкам А1, А2, В1 и В2 на второй). Выводы 16 и 17 подключаются на двигатель поворота колес (предположим, у вас это 1А и 2А), а 18 и 19 - на ходовой двигатель (тогда 1В и 2В). Какой именно из выводов куда - зависит от вашей конкретной конструкции шасси, надо только, чтобы сигнал по линии 19 вызывал движение вперед, 18 - назад, 17 - поворот вправо, 16 - влево.
 
Питание у обеих схем общее, подключается к точкам Vcc.

Схема системы управления Схема системы управления

Для повторения схем нужны:

  • MCU - микроконтроллер AT90S2313
  • ZQ1 - кварцевый резонатор на 4МГц
  • C1, C2 - конденсаторы, 22пф
  • X1 - разъем для подключения программатора (тип зависит от используемого программатора)
  • R1, R2 - фотодиоды СФ3-1
  • микросхема L293 (КР1128КТ4А)
  • VD1..VD8 - диоды MUR120 (КД212)
  • C3 - конденсатор, 1000мкф (на схеме не показан, установлен между шинами питания контроллера)

SA1 и SA2 - контактные датчики ("бамперы"). Цепь R3 (10кОм) - SB1 нужна для "сброса" микроконтроллера и использовалась только на этапе отладки.
 
Примечание: если вы используете микросхему L293D вместо L293, то диоды VD1..VD8 можно не устанавливать: эта микросхема уже их содержит!
 
С учетом того, что диоды и конденсаторы были взяты из сгоревшего блока питания от компьютера, светодиоды, использовавшиеся на этапе отладки - из разбитой клавиатуры, ну и так далее, - весь проект (включая макетную плату) обошелся нам менее, чем в 300 рублей.

Программа

Программа также получилась несложной (вот готовый файл прошивки - at03.hex). При начале работы в программе производится установка режимов работы портов, разрешаются прерывания по входам INT0 и INT1, устанавливается режим запроса на прерывание по этим входам и разрешается обработка прерываний.
 
После этого в бесконечном цикле запускается подпрограмма walk(), реализующая "свободный поиск" и движение на свет.

//
// Главная программа
//
int main(void)
{
  DDRB  = 0xff;  // назначаем все линии порта B на выход
  PORTB = 0x00;  // и устанавливаем на них низкий уровень

  DDRD  = 0x00;  // назначаем все линии порта D на вход
  PORTD = 0xff;  // подключаем внутренние "подтягивающие" резисторы

  // разрешаем прерывания по входам int0, int1
  outp((1<<INT0)|(1<<INT1), GIMSK); 
  // запрос на прерывание по спадающим фронтам на входах int0 и int1
  outp((0<<ISC00)|(1<<ISC01)|(0<<ISC10)|(1<<ISC11), MCUCR);

  sei(); // разрешаем обработку прерываний

  while(1) walk();  //"бесконечный" цикл

}

Подпрограмма основного движения walk() работает так: пока нет сигнала ни от одного из датчиков освещенности, производится запрос следующего направления движения (подпрограмма next_move()), а затем дается команда на движение в этом направлении (подпрограмма go()) в течение 2.5 секунд.
 
Если же появляется сигнал от датчика освещенности, то программа дает такое направление движения, чтобы сигнал появился на обоих датчиках, что означает движение к источнику.
 
Если при этом сигнал от датчиков пропадает, подпрограмма завершает свою работу, после чего главная программа запускает ее вновь, и опять оказывается в режиме "свободного блуждания".

Обратите внимение: исходное состояние на входах, к которым подключены датчики освещенности - логическая "1", поэтому, когда мы говорим, что на входе появился сигнал от датчика, имеется в виду, что на входе появился логический "0"!

//
// Подпрограмма основного движения
//
unsigned char walk(void){
   // "Свободное блуждание"
   while((bit_is_set(IN, LIGHT_R)) && (bit_is_set(IN, LIGHT_L))){
       go(next_move());  // определение следующего направления и движение
       Delay_10ms(250);  // задержка 2.5 сек
   }
   // Движение на свет
   while((bit_is_clear(IN, LIGHT_R)) || (bit_is_clear(IN, LIGHT_L))){
       if((bit_is_clear(IN, LIGHT_R)) && (bit_is_clear(IN, LIGHT_L))) go(F);
       else if(bit_is_clear(IN, LIGHT_R)) go(FR);
       else if(bit_is_clear(IN, LIGHT_L)) go(FL);
   }
   return(0);
}

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

// таблица вероятностей
unsigned char p[7][7] = {
{14,	43,	57,	71,	86,	93,	100},
{7,	43,	71,	100,	100,	100,	100},
{7,	50,	93,	100,	100,	100,	100},
{7,	50,	57,	100,	100,	100,	100},
{29,	29,	29,	29,	57,	79,	100},
{36,	36,	36,	36,	71,	93,	100},
{36,	36,	36,	36,	71,	79,	100},
};
// текущее направление движения
unsigned char this_move; 
//
// Выбор направления движения в следующем шаге
//
unsigned char next_move(void){
   unsigned char pp, i;

   pp = rand();  // случайное значение в диапазоне 0..100
   for (i=0;i<7;i++){
      if (p[this_move][i] > pp) break;
   }
   this_move = i;
   return(i);
}

Наконец, программа go() "преобразует" требуемое направление ("STOP" тоже условно считаем за "направление") в сигналы, выдаваемые на двигатель. Фактически она реализует таблицу, приведенную выше в разделе "Структура программы":

// возможные направления движения
enum {STOP, F, FR, FL, B, BR, BL};
//
// Подпрограмма управления двигателями
//
void go(unsigned char direction){

  switch (direction) {
  case STOP:
    cbi(OUT, MOTOR_F);
    cbi(OUT, MOTOR_B);
    cbi(OUT, TURN_R);
    cbi(OUT, TURN_L);
    break;

  case F:
    sbi(OUT, MOTOR_F);
    cbi(OUT, MOTOR_B);
    cbi(OUT, TURN_R);
    cbi(OUT, TURN_L);
    break;

  case FR:
    sbi(OUT, MOTOR_F);
    cbi(OUT, MOTOR_B);
    sbi(OUT, TURN_R);
    cbi(OUT, TURN_L);
    break;

  case FL:
    sbi(OUT, MOTOR_F);
    cbi(OUT, MOTOR_B);
    cbi(OUT, TURN_R);
    sbi(OUT, TURN_L);
    break;

  case B:
    cbi(OUT, MOTOR_F);
    sbi(OUT, MOTOR_B);
    cbi(OUT, TURN_R);
    cbi(OUT, TURN_L);
    break;

  case BR:
    cbi(OUT, MOTOR_F);
    sbi(OUT, MOTOR_B);
    sbi(OUT, TURN_R);
    cbi(OUT, TURN_L);
    break;

  case BL:
    cbi(OUT, MOTOR_F);
    sbi(OUT, MOTOR_B);
    cbi(OUT, TURN_R);
    sbi(OUT, TURN_L);
    break;
  }
}

Здесь команда sbi включает соответстующий двигатель, а cbi - выключает. Подразумевается, что OUT назначен на PORTB, IN - на PIND, MOTOR_F - на PB7 и так далее, как было определено выше.

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

Блок отъезда

Блок отъезда, как уже отмечалось, реализован в виде программы обработки прерывания. В главной программе мы подали на линии INT0 и INT1 положительное напряжение через "подтягивающие" резисторы, поэтому изначально на них присутствует логическая "1". При столкновении с препятствием контакты бампера замыкают соответствующий вход на "землю", и по спадающему фронту сигнала (так мы задали при инициализации) происходит прерывание. В этот момент основная программа приостанавливается и начинает работать программа обработки прерывания, в данном случае - программа отъезда от препятствия:

//
// Обработка прерывания от переднего бампера (INT0 = PD2)
//
SIGNAL(SIG_INTERRUPT0)
{
   if(this_move==FR) go(BL); // если двигались "вправо-вперед"
                             // отъезжаем "влево-назад"
   if(this_move==FL) go(BR); // и так далее
   else go(B);
   Delay_10ms(250);
   this_move=B;  // увеличиваем вероятность продолжения
                 // движения от препятствия 
}

//
// Обработка прерывания от заднего бампера (INT1 = PD3)
//
SIGNAL(SIG_INTERRUPT1)
{
   if(this_move==BR) go(FL);
   if(this_move==BL) go(FR);
   else go(F);
   Delay_10ms(250);
   this_move=F;
}

Когда программа обработки прерывания завершена, продолжается выполнение основной программы (т.е. свободный поиск или движение на свет) с того места, где она была приостановлена.

Подведем итоги

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

Некоторые дополнительные рекомендации

Для повышения помехоустойчивости системы необходимо сделать следующее.
1. Ко входу "сброс" микроконтроллера надо подключить безындукционный (керамический) конденсатор емкостью 0,1 ... 0,47 мкФ.
2. Питание на микроконтроллер надо подавать через LC-фильтр, где индуктивность должна быть в диапазоне 33 - 100 мкГн, а конденсатор, точнее два, безындукционный (керамический) конденсатор емкостью 0,1 ... 0,47 мкФ и танталовый, в крайнем случае алюминиевый, емкостью 33 - 100 мкФ.

Продолжение следует!

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

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