Басня о «домашней» робототехнике

Вот уже более года я очень продуктивно открываю для себя возможности Arduino. А началось всё ещё раньше, когда я случайно наткнулся на Хабре на статью про роботов, а после неё – на сайт, посвященный BEAM – роботам. Сразу возник вопрос: «А реально ли это – заниматься робототехникой, во-первых не в специализированных условиях, а во-вторых – не имея особо знаний в этой области?».

В течении нескольких недель я рыскал по интернету, буквально пожирая все предлагаемые там статьи для новичков типа «сделай робота дома сам». Каждую я прочитывал, выписывал наиболее популярные компоненты, составлял примерные списки того, что я хочу для себя приобрести. В это же время я решился сделать первого простейшего BEAM – робота на одной микросхеме: двухколесную платформу, ездящую за лучом света (вот такого). За пару вечеров я управился с постройкой, пару вечеров с ним поигрался, НО разве я стану останавливаться на таком детском достижении?

Во многих статьях, которые я прочитал, были упомянуты микроконтроллеры на чипе Atmel — различные ATmeg’и. Нарыв в интернете схем и руководств, я отправился в магазин за самой «маленькой» такой микросхемой: за ATmega16. И каково же было моё состояние, когда бородатый продавец, вручая мне микросхему, спросил: «Странно, но такое маленькое количество обычно не берут. Вы что, частник?»

«Нет», — ответил я, — «я просто решил заняться робототехникой, как хобби. Сначала вот буду с этой микросхемой разбираться…»

«Похвально, ну а программатор вы уже приобрели?» — перебил он оживлённо. Я сразу вспомнил о них, так как читал много статей, где предлагались схемы самодельных программаторов.

«Или вам знакомый будет прошивать?» — продолжил он. «Если что, у нас есть программаторы от 10 до 60 тысяч рублей, а вообще и это не предел.»

Я прямо осел, «как», говорю, «а как мне быть, я же только начинаю. Мне же просто не резонно вкладывать сразу такую кучу денег в вещь, в которой я ещё ничего не смыслю. А может мне не понравится, и тогда что, пролетел я?»

Продавец улыбнулся. «А вы что, о платах Arduino не слышали? Ну вы даёте, это ж спасение таким как вы, это самая универсальная вещь, которую я знаю: это и микроконтроллер, и программатор, язык написания универсальный. Чип там – как раз ATmega. Это просто замечательное во всех отношения устройство! Взгляните сюда, вот у нас есть несколько штук.» И я купил самую простую из представленных: Arduino Nano v2.

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

За год «знакомства» с Arduino я опробовал себя в создании многих десятков «строений». От простой системы управляемых светодиодов до Бог знает чего. Всё делалось «по кусочкам»: то есть например сначала я соображал алгоритм движения и управления манипулятором, потом прикидочно собирал его из палочек для эскимо и микро-сервомашинок, а после «полировки» кода я приобретал мощные сервомашинки и собирал 4-х степенной манипулятор в надежном пластиковом корпусе, ну а после этого я «сажал» манипулятор на старую машинку и получалась большая мега-игрушка J . Это лишь словесный пример, да и фотографий не получилось, потому что мысль – как вихрь, а набор деталей сами понимаете – один. Да и такие мгновенные устройства, как вы может быть заметили, объединяло одно: все они не имели алгоритмов самостоятельного поведения, они были лишь ведомыми устройствами под моим управлением.

А сейчас я хотел бы рассказать и показать построение мной робота сумоиста для участия в популярных нынче (в соответствующих кругах) соревнованиях по робо-сумо. Решение сконструировать автономного робота вынашивалось с самого начала моей робо-практики и зависело не только от фазы луны, но и от степени изученности мною необходимых в таком роботе разделов. Для сумоиста это: качественная работа с дальнометрами, датчиками линии, сервомашиками и силовой установкой – гусеничной платформой.

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

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

Ну, лирическое отступление закончено, теперь всё сначала, конкретно по теме. Робот сумоист должен иметь два важнейших датчика:

Дальнометр (лучше два) для поиска противника. Себе я выбрал три: один дальнобойный, чтобы искать вдали, и два «ближних», чтобы вблизи не потерять противника.
Датчик черной/белой линии, чтобы не вывалиться за ограничительную линию ринга.
Етественно, у робота должна быть ведущая часть — некая платформа. У всех участников, как я обращал на соревнованиях внимание, были разные платформы: было много двухколесных, много гусеничных, были даже и четырёхколесные. Для себя я выбрал гусеничный вариант, как самый надёжный (практически идеальное сцепление) и простой в использовании.

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

Если кому-то интересно, то вот список деталей, которые использовал я:

Наименование:

Количество:

Дальнометр Sharp2 шт.
Дальнометр Sharp1 шт.
Сдвоеднный редуктор1 шт.
Гусеницы1 комплект
Микросхема L293D для драйвера двигателей1 шт.
Датчики линии2 шт.
Arduino Nano1 шт.
Провода (рекомендую мягкие)много
Распиленные брусочки (стойки)Распиленные тонкие фанерки (перекрытиия)в ассортименте

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

Итак, первым пунктом в моём коде стоит опрос дальномеров и преобразование их показаний в метрическую величину – в сантиметры. У меня эта задача сначала вызвала недоумение, но потом за два дня я быстро научил датчики показывать довольно правдивое расстояние до объектов.

// Эта часть статьи уже не очень актуальна, ибо здесь приведён код для вычисления
// расстояния лишь в определенных границах, а у меня уже есть код, по которому
// можно получить ЛЮБОЕ расстояние, технически доступное дальнометру

Первый шаг – это опрос детонометра ( неважно, дальний он или ближний):

int Sharppin = 1;
float sens;
sens = AnalogRead(Sharppin);

Далее надо преобразовать выданное значение в вольты, чтобы потом ими оперировать. Факт, что датчик может выдавать значение от 0 до 5 вольт, а Arduino считывает показания в виде от 0 до 1024. По этому я поступил следующим образом:

float voltage;
voltage = sens * 5 / 1024;

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

Serial.begin (9600);
 
Serial.print ("sens: ");
 
Serial.println (sens);
 
Serial.print ("voltage: ");
 
Serial.println (voltage);
 
Serial.println (v);

Теперь у нас есть несколько значений. Вот, взгляните на мои измерения для датчика Sharp GP2D120. f(x) — это вольтаж, соответствующий оределенному расстоянию.

f(4) = 2.65
f(5) = 2.25
f(6) = 1.94
f(7) = 1.69
f(8) = 1.5
f(9) = 1.35
f(10) = 1.23
f(11) = 1.13

Строим график. Он получается мало похожим на какой либо известный. А теперь нам предстоит сделать из него линейный график, для того промежутка расстояний, который мы будем использовать в сумоисте. Для себя я разбил график на два промежутка: до 1.4 вольт и после. В сантиметрах это от [4; 7) до [7; 11]. Теперь просто проводим две прямые через то большинство точек, которое на ней укладывается.

А теперь используя знания алгебры примерно 8 – 9 класса задаем уравнениями эти прямые. Для первой (до 1.4 вольт) у меня получилось:

voltage = - 8 / 23 * distance + 4

Отсюда выражаем дистанцию:

float distance; 
distance = (4 – voltage)*23/8

Для отрезка после 1.4 вольт аналогичным образом получаем:

voltage = - 7/44*distance + 2.8; 
distance = (2.8 - voltage)*44/7;

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

if (voltage > 1.4 && voltage < 2.70)
{
distance = (4 - voltage)*23/8;
}
else if (voltage < 1.4 && voltage > 0.6)
{
distance = (2.8 - voltage)*44/7;
}

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

if ((float)analogRead(Sharppin) * 5 / 1024 &gt; 1.4 &amp;&amp; (float)analogRead(Sharppin) * 5 / 1024 &lt; 2.70)
{
distance = (4 - (float)analogRead(Sharppin) * 5 / 1024)*23/8;
}
else if ((float)analogRead(Sharppin) * 5 / 1024 &lt; 1.4 &amp;&amp; (float)analogRead(Sharppin) * 5 / 1024 &gt; 0.6)
{
distance = (2.8 - (float)analogRead(Sharppin) * 5 / 1024)*44/7;
}

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

Если хотите проще, то смотрите:

int led = 1;
int photor = 2;
pinMode (led, OUTPUT);
pinMode (photor, INPUT);
digitalWrite(led, HIGH);
if  (digitalRead(photor) ==HIGH )
{
//значит датчик над белой линией
}

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

int photoval;     //сюда записывается показание датчика
int photor = 0;  //аналоговая ножка, к которой подключен фоторезистор
int phblack = … ;  // показание датчика над черной поверхностью
int phwhite = … ;  // показание над белой
photoval = AnalogRead(photor);
if (photoval > phblack && photoval < phwhite + 50)
{
// значит над белой
}

Единственно, здесь надо уделить внимание на задаваемые значения показаний датчика над белой и черной линией. Эти значения надо очень внимательно вымерить. Всё, с датчиком линии мы закончили.

Датчики линии и дальнометры – единственные датчики на роботе такого типа, поэтому теперь мы перейдём к его алгоритмам поведения. Весь смысл, вся суть робо-сумо заключена в выталкивание соперника за пределы ринга. И я думаю, что на словах у всех людей алгоритм для сумо выглядел бы так:

  1. Поиск противника на ринге.
  2. Выталкивание противника за предел ринга.

 

Теперь «расшифруем» это, добавим конкретики:

  1. Поворачиваться на месте, пока не будет замечен противник.
  2. (Противник замечен) Движение вперед на противника.
  3. Если противник уходит/виляет, то корректировка движения: поворот за противником по ходу движения
  4. Если «замечена» граница ринга, то поворот в противоположную от границы сторону.
  5. Если противник потерян, то пункт 1, иначе 2.

 

Конкретно код для движения я написал так, что в нём учтено «случайное замечание» противника. В этом случае одно движение заменяется другим. Вот для одного дальнометра – для основного (дальнобойного):

if (distance > distmax)   //дальнее расстояние
{
left();
distance = (2.8 - (float)analogRead(4) * 5 / 1024)*44/7;
Serial.println("distance > distmax");
}
 
if (distance < distmax) //близкое расстояние
{
forward();  //вперёд - "нападение"
distance = (4 - (float)analogRead(4) * 5 / 1024)*23/8;
Serial.println(" distance < distmax ");
}

Это кусок основной части, а вот заявленные подпрограммы:

int mR = 4;    // правый мотор вперед
int mRB = 5;   // правый назад
int mL = 6;    // левый вперед
int mLB = 7;   // левый назад
 
void left()
{
stop();    // остановка всех движущихся моторов – на всякий случай
while (distance > distmax)
{
digitalWrite(mR, HIGH);
digitalWrite(mLB, HIGH);
Serial.println ("m(left)");
distance = (2.8 - (float)analogRead(4) * 5 / 1024)*44/7;
}
digitalWrite(mR, LOW);
digitalWrite(mLB, LOW);
}
 
void forward()
{
stop();
while (distance < distmax)
{
digitalWrite(mL, HIGH);
digitalWrite(mR, HIGH);
Serial.println ("m(forward)");
distance = (4 - (float)analogRead(4) * 5 / 1024)*23/8;
}
digitalWrite(mR, LOW);
digitalWrite(mL, LOW);
}
 
void stop()
{
digitalWrite(mR, LOW);
digitalWrite(mLB, LOW);
digitalWrite(mL, LOW);
digitalWrite(mRB, LOW);
}

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

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

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

Вот фото второй, улучшенной версии, пускай ещё и недоделанной:

Похожие записи:

Если вам понравилась статья, вы можете подписаться на RSS или E-mail рассылку. Для получения обновлений по электронной почте, введите ваш e-mail адрес в эту форму (Доставка от FeedBurner):

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *