KN34PC – Arduino-управление на модел на танк Т200

KN34PC - Arduino-управление на модел на танк Т200 Роботы

Arduino танк, управляемый акселерометром android

Добрый день, сегодня я хочу поделиться инструкцией по изготовлению игрушечного танка, управляемого акселерометром Android телефона. Основу танка будем изготавливать из покрашенной фанеры толщиной 3 мм. Гусеницы и сдвоенный мотор-редуктор известной фирмы Tamiya. Выпускающая качественные и недорогие детали.

Для танка нам понадобится:
– Tamiya 70168 сдвоенный редуктор
– Tamiya 70100 набор катков и гусениц
– Tamiya 70157
– Фанера 10 мм (небольшой кусочек)
– Arduino Pro Mini 5V AtMega 328
– DRV 8833
– Bluetooth модуль HC-06 или аналог
– USB-UART для прошивки Arduino
– Светодиоды прямоугольные красный и зеленый
– Светодиоды белые 5 мм 2шт.
– Резисторы 3х 150 Ом
– Аккумуляторы Li-ion 18650
– Коннекторs Dupont папа-мама
– Провода разных цветов
– Припой
– Канифоль
– Паяльник
– Болтики 3х40, 3х20, гайки и шайбы к ним
– Саморезы 2х10 по дереву
– Сверла по дереву 3 мм и 6 мм
– Электролобзик
– Краска акриловая

Шаг 1 Сборка мотор-редуктора.
Мне нравится использовать мотор-редукторы фирмы Tamiya. Стоят приемлемо, собираются легко. У Tamiya 70168 четыре варианта сборки. В зависимости от нужного передаточного числа и положения выходных валов.

Внутри коробки с редуктором вложена подробная инструкция. Нам необходимо, чтобы выходные валы располагались ближе к двигателям, а передаточное число 114.7:1. Выбираем нужный нам вариант и собираем все по инструкции, кроме установки моторов. Моторы удобнее поставить потом, кроме того, к ним надо припаять провода и конденсаторы, перед установкой.

Шаг 2 Изготовление деталей корпуса.
Корпус будем изготавливать из фанеры толщиной 3 мм. Скачиваем нижеследующую картинку и распечатываем ее на листе A4 в масштабе 102%.

Теперь берем два куска фанеры достаточных размеров, кладем одну на другую, сверху прикладываем нашу картинку. В местах отмеченных жирной точкой необходимо проделать отверстия 3 мм. Чтобы обе детали были одинаковы, вначале просверливаем лист и две фанеры в одной из точек, вставляем туда болтик, и скручиваем картинку и два куска фанеры вместе. Затем второе отверстие, и также вставляем туда болтик. После этого просверливаем все остальные. Обратите внимание на самое левое отверстие, ему необходимо придать форму овала. Это нужна для регулирования натяжения гусениц. Теперь берем электролобзик, и вырезаем сразу две боковые детали корпуса, следуя по жирной линии картинки. Должны получится две такие детали:

Смотрите про коптеры:  Что делать, если пылесос не выключается: быстрые решения

Далее необходимо проделать все выше описанное, только на этот раз вырезаем две детали прикрывающие гусеницы. Резать надо по малому овалу, нарисованному на картинке. В итоге получаем еще две детали:

Теперь берем лист фанеры в один слой и вырезаем прямоугольник размерами 168 х 54 мм. Это будет низ нашего танчика и деталь к которой крепится мотор-редуктор:

Для начала сборки нам понадобятся все описанные выше детали:

Можно оставить все детали как есть, но я предпочитаю их покрасить. Для покраски подходит акриловая краска. Она быстро сохнет и не пахнет, а значит можно красить в любом помещение не боясь отравиться. Итак, красим вырезанные детали:

Теперь нам понадобится фанера толщиной 10 мм или деревянная палочка подходящего размера. Необходимо вырезать прямоугольник размерами 54 х 15 мм и толщиной 10 мм. Эта деталь необходима для соединения корпуса воедино. Изготовив прямоугольник просверливаем два отверстия на расстоянии 15 мм от края вначале сверлом 3 мм и затем 6 мм, но не насквозь, а только на половину глубину. В полученные отверстия вставляем гайки и фиксируем их с помощью клея. Нам необходимо четыре таких детали:

Опять берем фанеру толщиной 3 мм. Вырезаем прямоугольник 107 х 60 мм. Отступая по 15 мм от краев сверли отверстия 3 мм, эту будет верхняя крышка:

Режем следующий прямоугольник размером 33 х 60 мм. Отступая по 15 мм от краев сверлим два отверстия диаметром 5 мм. Вырезав и зачистив деталь красим ее. Затем в проделанные отверстия вставляем светодиоды белые 5-ти миллиметровые. Спаиваем их параллельно и фиксируем при помощи термоклея:

Шаг 3 Сборка корпуса.
Подготовив мотор-редуктор и детали переходим к сборке всего воедино. Для начала берем нижнюю деталь корпуса и прикручиваем к нему мотор-редуктор:

И чуть покрупнее:

Затем крепим боковые детали, используя для этого уголки от детского железного конструктора и болтики 3х20 мм:

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

Берем моторчики, идущие в комплект с катками и гусеницами. Припаиваем к контактным площадкам провода, а параллельно им конденсатор 0.1 мкф. После этого устанавливаем моторчики в мотор-редуктор:

Перейдем к аккумуляторам. Спаиваем наши Li-ion 18650 аккумуляторы параллельно и выводим провода для удобства. Скручиваем их изолентой:

Размещаем их внизу корпуса, радом с моторчиками:

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

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

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

Также использую термоклей крепим переднюю деталь с фарами:

Шаг 4 Электрика
Электродвигатели при своей работе создают помехи, а при пуске возникает падение напряжения. Чтобы при каждом пуске двигателей Arduino не перегружалась, разделим питание. Arduino запитаем от 9-ти вольтовой батарейки типа кроны, а моторчики от аккумуляторов. Аккумуляторы мы уже разместили, крону будем размещать в передней части танчика:

Установив батарейку закрываем ее верней крышкой:

Соединяем все вместе по схеме:

Немного поясню. Левый двигатель через драйвер подключаем к 5 и 6 pin. Правый – к 9 и 10. Плюс от красного светодиода через резистор к 3 pin, минус к GND. Плюс от зеленого светодиода, также через резистор, к 4 pin. Фары к 2 pin.

Работа Bluetooth модуль осуществляется через библиотеку SoftwareSerial. Мы будем использовать программный com-port. Контакты подключения можно изменить в скетче. Подключаем модуль следующим образом:

Arduino Pro Mini – Bluetooth
D7 – RX
D8 – TX
5V – VCC
GND –GND

Собрав все вместе размещаем электрику в центральной части:

Шаг 5 Программные средства.
Для работы со скетчем необходимо скачать Arduino IDE. Заходим на официальный сайт проекта и скачиваем последнюю версию:

Затем нужно добавить библиотеку. SoftwareSerial уже должна быть в Arduino IDE. Но на всякий случай выложу ее:

Если Arduino IDE, при компиляции скетча выдает ошибку и ругается на отсутствующую библиотеку, распаковываем скачанный архив в папку «libraries», находящуюся в папке с установленной Arduino IDE.

Шаг 6 Подготовка Bluetooth модуля.
Настройки Bluetooth модуля по умолчанию отличаются от тех, что нужны нам. Поэтому вначале необходимо установить связь Bluetooth модуля с компьютером и изменить настройки. Заливаем скетч Send_ AT_Bluetooth в Arduino:

Arduino будет выступать в роли связующего звена между Bluetooth и компьютером. Запускаем Arduino IDE, открываем Монитор порта. Для HC-06, выбираем в настройках монитора порта скорость 9600, NL и CR не нужен. Если с модулем не установлена Bluetooth соединение, он находится в режиме ввода AT команд. Возможно с первого раза модуль не отзовется. Тогда попробуйте перегрузить его, отключив и подключив снова плюсовой провод. Все команды вводятся без кавычек, не забудьте нажать enter для отправки. Вводим следующие команды:

«AT» – без кавычек, должен прийти ответ «OK».
«AT NAME<имя>» – введите имя модуля, чтобы вы смогли легко его найти. Обязательно латинским буквами, без скобок.
«AT BAUD7» – устанавливаем скорость 57600.
«AT RESET» – перегружаем модуль.

Если что-то пошло не так, или не помните настройки:
«AT ORGL» – возвращение модуля к заводским настройка.

Шаг 7 Заливка скетча.
Закончив настройку Bluetooth модуля, переходи к заливке основного скетча:

Шаг 8 Подготовка Android телефона.
Перед использование убедитесь, что у вашего Android телефона или планшета есть акселерометр. Для начала добавляем Bluetooth устройство танчика в Android. Заходим в настройки Bluetooth, находим названный вами Bluetooth модуль и подключаемся. Пароль для соединения «1234» или «0000», у разных моделей бывает по-разному. Теперь устанавливаем программу управления. Нам понадобится Arduino Bluetooth RC Car или BT Controller. Обе программы бесплатные, у них есть возможность управлять Bkuetooth устройством через акселерометр, и они есть в Google play. Скачиваем понравившуюся вам программу на телефон или планшет. В меню настройки программы вводим следующие команды:

W – вперед
S – назад
A – влево
D – вправо
F или G– стоп
K – включение фар
L – выключение фар

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

И добавить в него Bluetooth модуль, следуя по еще одной инструкции.

Kn34pc – arduino-управление на модел на танк т200


Arduino-управление на модел на танк Т200
/radiocopter.ru/конструкции/

Част I
Част II

Част III

Посвещавам тази статия на моя приятел
Николай Др. Николов, с когото направихме
много устройства в моделистиката в младежките ни години.

Още със завършването на моя експеримент за управление на постояннотоков мотор с драйвери L9110 и MC33152, описан в статията
“Arduino-управление на
постояннотоков електромотор с H-Bridge драйвер”
ми хрумна идеята да развия
създадения вече скеч в програма за управление на два мотора. Естествено, това
продължение на експеримента позволява задвижване на робот и изпълнение на повече
команди от вече описаните.

Не след дълго се захванах с доработката на скеча, добавих още
един драйвер и още един мотор. Бързо и лесно повторих част от командите, които
позволяваха това, но се затрудних с командите за завой наляво и надясно.
Затруднението беше за кратко. След което чрез няколко реда в скеча обърнах
посоките на двата мотора, добавих нови бутони за управление и резултатът вече
беше налице. Промяната на посоките осъществих като включих в скеча допълнителни
състояния на командите SWITCH … CASE.

След като завърших основната част на програмирането, включих
два мотора и експериментирах резултата. Всъщност интересната част за мене беше
обръщането на посоките на въртене на двата мотора. Резултатът беше повече от
очевиден. Тогава се замислих за добавяне на команди за скорост на въртене
(движение).

Признавам си тази част от скеча ми отне две седмици. Не бях
правил никога подобни експерименти, но с упоритост всичко се постига. Така
добавих още два бутона (двата в левия долен ъгъл на снимката в ляво) с които
постигнах това управление. Определянето на стъпките, през които се променяше
скоростта, ми отне много малко време и така получих пет скорости на задвижване,
като при първоначално включване на платката Arduino скеча придава стойност малко
над половината от скоростта на въртене на моторите, а обхвата на промяната е от
160 до 240 нива (160-180-200-220-240).

Експериментите с двата мотора извърших като монтирах всички
модули на един малък бредборд, който се оказа достатъчен. Управлението и
софтуера се извършваше от платка Arduino UNO R3. Захранването на целия комплект
е с 12V постоянно напрежение, което позволява консумация до 2А.

Припомням, че драйверите на H-Bridge MC33152 позволяват
захранване в интервала 6,5V ÷ 18V и максимален ток на консумация до 1,5А. За мен
тези параметри бяха достатъчни, тъй като позволяваха захранване на конструкцията
с батерия с напрежение 12V, която дори при спад на напрежението до 7V щеше да
задвижва моторите. От друга страна напрежението на батерията, захранването на
моторите и входното максимално напрежение на платката Arduino са еднакви – също
12V, като по този начин предвиждах да използвам само един единствен източник на
захранване.

Дали на шега или е истина, но често се казва, че татковците
често купуват на децата си играчките, които самите те харесват!? И аз не знам
как ми хрумна да използвам този скеч за управление на танк, но идеята узря
изведнъж, именно защото скеча е изключително подходящ, управлявайки два мотора,
съответно управлявайки две задвижващи колела с две вериги. Ето така се зарових в
интернет и не след дълго намерих доста модели на танкове. Избрах си един, който
намерих като подходящ за моите цели и го поръчах. Естествено от Китай. След две
седмици пратката пристигна, а вътре в нея в няколко пликчета имаше безброй “джуджавки”,
тоест пристигна в разглобено състояние. Сглобяването на модела обаче, се
превърна в елемент от малкото щастие да притежаваш красива играчка. След няколко
вечери упорит труд ламарините, колелцата и винтчетата придобиха ето този вид:

В процеса на механичното сглобяване на модела установих, че
обтягането на веригите е от съществено значение за лекотата, с която моторите
ги задвижват (натоварването на моторите в следствие на триенето). Обаче се
оказа, че и китайския производител е предвидил този проблем като в конструкцията
осите на водещите колела на веригите бяха направени с шлицове, които позволяха
регулиране на опъна. Естествено, това не става само визуално, а чрез измерване
на тока на консумация едновременно на двата мотора и чрез регулиране на опъна на
веригите се постига еднаквост. Това от своя страна позволява една и съща скорост
на въртене на моторите и задвижване на веригите. Все пак нека да отбележа, че аз
избрах модел на танк, изработен от метал, с доста сериозна външност, а не
пластмасов евтин боклук, който едва ли щеше да издържи повече от няколко дни.
Целта ми беше да направя няколко експериментални конструкции с това метално
шаси.

KN34PC - Arduino-управление на модел на танк Т200

След като сглобих шасито на танка и настроих моторите, не се
сдържах да го изпробвам в движение и с два достатъчно дълги проводника, свързани
към двата мотора, подадох захранване и шасито се задвижи. Удоволствието от
движението и силния метален шум е изключително! Почти като истински танк! След
това чрез регулиране на захранващото напрежение от нула до 12V определих
интервала, в който шасито може да преодолява препятствия с наклон < 30 градуса
(почти в реални условия). Оказа се, че долната граница при която шасито има
стабилно движение е 7,5V. Това е от огромно значение за нивото на разряда на
батериите, при която стойност платката Arduino все още щеше да работи според
техническите данни (7V-12V).

Но в програмния код аз не променям напрежения, а коефициента
на запълване. Както ще забележите на схемата, видна по-долу, моторите са
свързани към цифровите ШИМ изводи на платката Arduino. Но независимо от това,
промяната на напрежението е един от параметрите, които трябва да осигурят
движението на машината. От друга страна, в кода поставям начално състояние на
коефициента на запълване за ШИМ около 70% с което скоростта на моторите
позволява намаляване и увеличаване, както споменах в началото в пет стъпки.
Някой би могъл да пожелае да промени тази стойност (например на 128 – в средата)
и с това ще осигури намаляване на скоростта до пълно спиране на машината.
Разбира се тази последна възможност, която съм включил в кода е една “глезотийка”,
която позволява на човешкото око да се радва на модела, който по този начин се
доближава максимално до оригинала.

На следващата цветна модулна схема ви представям свързването
на отделните елементи и блокове:

KN34PC - Arduino-управление на модел на танк Т200
tank_ok[zip,ino,fzz,jpg][312kb]

В паралел на изводите на моторите може да се включат
керамични кондензатори със стойност 47nF, които на горната схема не са показани.
Те имат за цел да филтрират искренето на контактите на ротора и до известна
степен повишават шумоустойчивостта на схемата. При наличие на качествени
елктромотори необходимостта от тях може да отпадне. Аз, например, не съм включвал
филтрови кондензатори.

В реда, в който бутоните са показани от ляво на дясно,
задават следните команди:

    – наляво (върти лявата верига назад,
а дясната напред)
– надясно (върти лявата верига
напред, а дясната назад)
– намаляване на скоростта
– увеличаване на скоростта
– назад: старт, стоп
– напред: старт, стоп

Подредбата им по функции не е била целенасочена, а позволява
какъвто и да е избран порядък. Командите се подават чрез натискане на бутоните –
подаване на логическа “0” на входовете на платката Arduino.

Следващата стъпка при осъществяване на проекта беше
свързването на електронната част с шасито и неговото задвижване. Тази приятна
задача се оказа лека и бърза и след около час прототипа на модел на танк се
получи. На следващите снимки може да се видят изглед отпред и отзад на шасито:

А тук, по-долу изглед от страни и отгоре:

И накрая остана включването на батерията и натискане на
бутона Старт. Шасито се задвижи, издавайки метален звук, наподобяващ шума от
движение на танк. Но се започна едно тичане след него из стаята и натискане на
бутоните за различните команди. Но удоволствието беше пълно. Напред, а после
назад. След това въртене наляво, надясно. Промяна на скоростта по-бързо и
по-бавно.

Но остана един елемент на неудовлетворение – трудния достъп
до командите когато шасито беше в движение. Е, все пак не е и чак толкова
атрактивно. Ето така реших да направя конструкцията на модела радиоуправляема
(щях да се спася от тичането след нея). Разбира се, точно това щеше да я направи
много по-атрактивна. Набързо закупих модули приемник и предавател на честота
433 MHz и две интегрални схеми енкодер и декодер. Целта ми беше с най-малко
елементи и средства да направя управлението на танка дистанционно. Модулите
осигуряваха четири канала за управление, а за моята конструкция това са
основните команди – напред-назад, стоп, наляво-надясно. Но докато осъществявах
на бредборд импровизирано дистанционно управление на модела на танк по
радиоканал на честота 433 MHz, попаднах и на други принципни схеми за тази цел,
които позволяваха управление с осем команди (припомням, че моя образец е с шест
команди). Е, разбира се, не всичко може да се осъществи за “нула” време и ги
оставих за близкото бъдеще. Ето така, временно елиминирах дистанционното
управление на скоростта.

Но ето модулите, които използвам:

KN34PC - Arduino-управление на модел на танк Т200

От практическа гледна точка, премахнах бутоните от бредборда,
върху който бях осъществил връзките с платката Arduino и ги преместих на друг
бредборд 440 pin-а върху който осъществих схемата на предавателя на
дистанционното управление, което имаше за задача да изпраща четирите команди до
шасито на танка. Приемникът монтирах на бредборда на танка и той имаше за задача
да приема и дешифрира тези команди като ги подава на същите пинове, на които
бяха свързани преди промяната бутоните. Тоест, изградих предаване на командите
на бутоните по радиоканал.

За тази цел освен радиочестотните модули ми бяха необходими
още две интегрални схеми комплект енкодер-декодер, така че чрез енкодера се
кодираха командите от бутоните, а в приемната част чрез декодера те дешифрираха
и отправяха към пиновете на Arduino платката. Представям конструкцията лесна за
изпълнение, но в нея има доста логика. Например, в оригиналния програмен код на
Arduino бутоните подават команди като дават цифровите пинове към маса.
Следователно при сглобяване на модулите за радиоканала, приетите от предавателя
команди също трябва да бъдат активни при ниво от “1” към “0”. По този начин се
спрягат съответните логически нива, в противен случай рискуваме платката Arduino
да не изпълнява приетите команди. Причината затова е, че цифровите пинове са
закачени чрез командата PULL-UP към високо ниво.

Следва принципната схема на свързване на елементите на
предавателя и приемника, чрез която се осъществява дистанционното управление:

KN34PC - Arduino-управление на модел на танк Т200

Както виждате, изходите на приемника D0, D1, D2 и D3 са
съответните команди, които директно се подават към цифровите пинове на Arduino.
Приемникът се захранва с напрежение 5V, което се взема от извод 5V на платката
Arduino, а предавателят се захранва от батерия 6F22 / 9V, независимо, че на
схемата е отбелязано по-ниско напрежение, енкодерът допуска захранване до 12V.

А ето промените във връзките между бредборда и платката
Arduino в приемната част върху шасито на модела на танк:

Вероятно ви прави впечатление, че на бредборда има включени
електролитни и керамични кондензатори. Погледнете принципната схема по-горе и ще
забележите, че на нея е отбелязан само кондензатора С = 0,01µF, а аз съм добавил
електролитен кондензатор със стойност 220µF/16V. Все пак, имал съм предвид, че четковите електромотори са сериозен източник на смущения, искрене в следствие на
триенето на четките по колектора на ротора. В първия момент на пуска не бях
свързал нито антени към предавателя и приемника, нито филтриращи кондензатори,
като покритието по обхват беше в рамките на една стая. В следващия момент
добавих антени и покритието се разшири до стабилно предаване на командите от
предавателя от съседната стая, а на края поставих филтриращите кондензатори
просто за да ги има или просто защото взех предохранителни мерки така, както
пише в “дебелите” книги.

На следващите снимки е показано импровизираното дистанционно
управление:

Както се вижда, захранването на предавателя се осъществява от
батерия с напрежение 9V, която е достатъчна по капацитет предвид на консумирания
ток. По-важно е, според мене, правилното оразмеряване на дължините на антените
на предавателя и приемника. Независимо, че използвах импровизирани антени от
проводници, дължината на антената е съобразена с дължината на вълната на
основната честота на радиоканала – 433,92 MHz. Тази честота отговаря на дължина
на вълната 691 mm. Антените би следвало да бъдат равни или кратни на тази
дължина. Скъсените антени могат да бъдат с дължини: 691 mm, 345 mm и 173 mm. За
тези дължини следва антените да са съгласувани. Аз използвам антена за
предавателя с дължина 172 /- 2 mm и антена за приемника 342 mm /- 2 mm. В
интернет сайтовете с публикации описващи използване на радиоканал на същата
честота колегите дават размери на антените 17 cm за предавателната и 34 сm за
приемната.

KN34PC - Arduino-управление на модел на танк Т200

Един много по-лесен начин да приложите радиоуправление е като
използвате готов четири канален модул за управление на гаражни врати. Същият се
продава като комплект дистанционно управление с четири бутона и платка-приемник:

KN34PC - Arduino-управление на модел на танк Т200

Този комплект се предлага на честота 315 MHz, като
дистанционното управление е напълно изграден модул с телескопична антена, докато
дължината на антената за приемника трябва да се изчисли по познатата формула за
дължината на вълната и би могла да бъде – 475 mm или 240 mm, последната е
четвърт вълна.

Изводите на приемника са изведени на рейка и са обозначени на
платката с бял печат:

KN34PC - Arduino-управление на модел на танк Т200

Захранването е 5V и може да се вземе от платката Arduino, а
изводите D0, D1, D2, D3 са цифровите изходи, които се свързват към цифровите
входове на Arduino и чрез които се осъществява управлението
НАПРЕД-НАЗАД-НАЛЯВО-НАДЯСНО. Но преди да свържете модула трябва да знаете, че
командите в моя скеч, постъпили от бутоните дават съответните цифрови входове
към маса, тоест от високо към ниско ниво, докато командите на този модул са от
ниско към високо. Това означава, че трябва да преработите тези команди в скеча
просто като замените състоянията на бутоните вместо “LOW” с “HIGH”.

В архива към статията е приложен и програмния код. Основната
част от него е обяснена в статията ми
“Управление на постояннотоков мотор с H-Bridge
драйвер”
. В този скеч има доста разлики, свързани с едновременното управление на
два мотора, както и с лека оптимизация на програмния код, тъй като оригиналния,
от който произхожда, беше с доста повторения на команди за да съм сигурен в
изпълнението им.

***

Пътят на
експеримента:

Изминах дълъг и труден път докато стигнах до свързването на две платки Arduino
по радиочестотен канал. Трябваше да прочета много теми и експерименти,
публикувани в интернет (виж “Литература”). Но бях се амбицирал след като
реализирах дистанционно управляем модел на танк. Тръпката се оказа много жива. И
ако в статията в Част I
радиоуправлението беше осъществено чрез специализирани интегрални схеми енкодер-декодер
HT-12E/D, съвсем естествено, бързо стигнах до идеята за свързване на две Arduino
платки чрез радиоканал.

От проучванията ми в интернет пространството се запознах с много проекти: едни,
осъществени с блутут-модули, други с безжични, трети с трансивери на 2,4GHz.
Срещнах и много комбинации на управление например като: управление от компютър
чрез блутут-модул, управление с дистанционно, или управление чрез смарт-телефон
с OS Android. Но за всички крайният резултат беше управление на една платка
Arduino от разстояние.

След като се ориентирах в интернет пространството за начините на предаване на
данни, а именно превръщане на скеча на предаващата платка Arduino в сериен поток
от данни, предаването му чрез ASK (Amplitude Shift Keying), приемането и
декодирането им от приемащата платка Arduino, която изпълнява подадените
команди. Информацията за начина на обработване на сигнала при използване на ASK
e многообразна, но най-просто може да се опише чрез поток от “1” и “0”, които
модулират ВЧ генератора на предавателя, излъчват се, приемат се от приемник, на
чийто изход след детектирането се получава същата поредица от импулси. За целта
най-евтини отново се оказаха радиомодулите предавател-приемник на 433,92 MHz (или
315 MHz).

KN34PC - Arduino-управление на модел на танк Т200

От различните проекти на същата тематика, които разгледах в интернет, ми направи
впечатление използването на няколко библиотеки, които позволяваха свързването на
две Arduino платки. Такива например са:

    – VirtualWire
– RC Switch
– RadioHead

    и други.

Някои от авторите с по-голям опит в програмирането са създали свои собствени
библиотеки, каквато е например ardubottom.h. Но аз съм начинаещ и трябваше да се
възползвам от чуждия опит. Така започнах да “опитвам” различни проекти на
принципа “copy-paste”. Реализирах 5-6 проекта на други автори, но ударих на
камък – нито един не даде резултати в моята домашна лаборатория. И така след
близо месец неуспешни опити се поразговорих с Веско, мой приятел и колега, който
ме посъветва да започна с най-простичките примери като BLINK. Но аз вече бях
преминал по този елементарен път и реших, че по-скоро е редно да спра за
известно време, да отпочина и след това да се съсредоточа в последователното
осъществяване на един проект и ако се налага, да се опитам да преработя
програмния код съобразно моите изисквания.

Като за начало реших да започна всичко отначало, да препрочета отново написаното
в интернет и да потърся грешките, които съм допуснал (или друг е допуснал). Така
се съсредоточих върху “новото” начало в управление на серво-машинка по
радиочестотен канал на 433MHz. Отново прочетох статията на руския колега Мелников,
след това я препрочетох, но не намерих заигравки или скрити подводни
камъни. Казах си – няма причини да не тръгне, нахъсах се и подготвих две Arduino
платки на два отделни бредборда – по един за всяка (предавател и приемник):

ЗАБЕЛЕЖКА: Използваните Arduino платки трябва да бъдат базирани на процесора
ATMEGA 328, каквито са Arduino Uno R3 или Arduino Nano V3. Тази забележка не е
случайна. В първите си експерименти аз се сблъсках с този феномен. Заради
по-малките си размери аз си бях закупил две платки Arduino Micro, базирано на
процесор ATMEGA 32U4. Но с него ударих на камък – програмните кодове за сериен
трансфер не работеха поради различните инструкции на процесора. Това беше една
от допуснатите грешки – моята грешка.

Поради горната забележка, започнах новите си експерименти с Arduino Nano 3.0.
Монтирах платките върху два бредборда, направих съответните кабелни връзки.
Проверих още няколко пъти монтажа за грешки и след като се уверих, че такива
няма, заредих поотделно платките със съответните скечове за предавателя и
приемника и-и-и-и-и-и до тук. Зареждането на скеча на приемника прекъсна със
съобщението:

   
Error compiling bord Arduino Nano“.

Бях наистина изненадан тъй като бях спазил всички инструкции на Мелников.

Започнах да разсъждавам, да оглеждам скеча за грешки, както мои, така и на
автора. Разбих скеча на по-малки части, започнах ръчно да вписвам ред по ред
командите и изведнъж отново получих същата грешка. Така установих, че в
изтеглената от интернет библиотека ServoTimer2 има проблем. Изтеглих и друга, но
резултатът беше отрицателен. Тогава внимателно прочетох забележките по форумите
и ми направи впечатление, че очевидно библиотеката е създавала такива проблеми и
на други любители, тъй като беше отбелязано, че програмния ред:

   
typedef uint8_t boolean;

трябва да се премахне. Отворих файла с Notepad и го демаркирах:

   
//typedef uint8_t boolean;

И с това кратко действие скечът заработи:

KN34PC - Arduino-управление на модел на танк Т200

Този, който би искал да експериментира свое устройство за управление на серво-машинка
може да намери в архива скеча с името:
2023 Virtual_Wire_ServoTimer2

http://radiocopter.ru/construct/v_terziev_arduino_tank/2/video_servo.mp4

Този експеримент имаше за цел да се уверя в работата на библиотеките и
естествено в осъществяването на комуникация между двете платки Arduino. Но за
моите цели управлението на серво-машинка не беше необходимо. По-скоро трябваше
да се съсредоточа върху управление на два мотора, такова, каквото описах в Част
I на едноименната статия. С това щях да запазя функционалността на вече
създадения модел на танк.

Осъществяване на идеята:

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

   
– СТОП
– Напред
– Назад
– Наляво
– Надясно

И ако в Част I командите се подаваха чрез бутони, тук ще използвам джойстик, с
което ще имитирам в голяма степен фабричните радиоуправляеми модели. Ето схемата
на свързване на предавателя:

KN34PC - Arduino-управление на модел на танк Т200

Батерията, която използвам за предавателя е 9V блок 6F22, акумулаторна, 280 mA/h.
За експериментите тя е достатъчна по капацитет, но имайте предвид, че
консумацията на Arduino Nano е около 30-33 mA, което предполага по-бързото й
изтощаване при по-интензивна употреба.

На следващата схема са дадени електрическите връзки в приемника. Приемната част
също се захранва с батерия с напрежение 9V, но докато в предавателя използвах
малка блок батерия 6F22, тук поради по-голямата консумация на ток (до 1А)
използвам 6 бр. х 1,5V батерии размер AA. В схемата по-долу съм използвал готов
модул Motor Shield с ИС L9110, чието максимално захранващо напрежение е 12V.
Модулът може да се замени с друг подобен, със захранващо напрежение не по-ниско
от 6V, тъй като това напрежение е най-ниското, при което Arduino платката може
да работи. Връзките на модула нарочно не са означени с номера на използваните
изводи тъй като може да се използват и какви да са други подходящи модули:
TB6612, L293, L298 или Motor Shield за Arduino. Препоръчвам преди да направите
промени в конструкцията да изпълните всички стъпки така, както съм ги описал
(поне аз така правя, когато повтарям чужда конструкция).

KN34PC - Arduino-управление на модел на танк Т200


2023_ardu_2_motors
[zip,ino,h][3kb]

Програмните кодове за този проект са два, по един за предавателя и приемника.
Използвам програмния код за предавателя без да съм нанасял в него промени,
докато в кода на приемника съм направил съществени промени – премахнал съм серво-машинката и съм добавил няколко команди с които робота придобива предварително
плануваната функционалност.

Кратко описание на предавателния код:

Преди всичко той обхваща инструкции, чиято цел е да поставят параметрите на джойстика по “Х” и “Y” координати.
Изпращането на данни към приемника се свежда
до изпращане на няколко символи F, B, L, R, N. Тоест, именно в това е хитростта
на кода – всяка буква (символ) носи в себе си команда. Тези символи се групират
в сериен изход и се изпращат през pin1 – TX, за който е свързан предавателя.
Серийната поредица се излъчва непрекъснато и се приема от приемника.
Предавателният код е включен в архива с името: “_433MHz_RC_Car_Joystick_TX“.

Кратко описания на приемния код:

Приемника се свързва към pin0 – RX на Arduino платката, през който серийния
формат данни влиза в платката за обработка. Скечът разпознава символите,
изпратени от предавателя F, B, L, R, N и към всеки един от тях прикрепя малък
скеч, с който се изпълнява определена команда. За целта отново използвам Arduino
IDE командата SWITCH … CASE. Всеки символ е отделен CASE. Символите имат
следните значения F – Forward, B – Backward, L – Left, R – Right, N – Nowhere
(последният е СТОП). Всеки един CASE съдържа комбинация от втора степен на двата
мотора: включен / изключен мотор.

Ще онагледя с два примера значението на казаното:

Ако приемника получи символ “F”, CASE изпълнява командите “включен ляв мотор” и
“включен десен мотор”. Тоест, движението е напред – FORWARD. Няма да описвам
всички CASE команди, но ще се спра на още една – например ляв завой “L” – Left.
Логично при изпълнението на тази команда предадена със символа “L” командата
CASE изпълнява следната функция: “спира ляв мотор” и “включен десен мотор”. По
описаните два начина са изградени и другите CASE команди с които се осигурява
движението на робота надясно и назад. Приемателния код е включен в архива с
името: “_433MHz_Mot_Only_Reciever“.

А сега няколко практически съвета за инсталиране на библиотеката ardubottom.h :

Библиотеките най-общо казано са системни или локални.

Системните библиотеки се инсталират в IDE чрез менюто Sketch => Include Library
=> Add .ZIP Library
… Инсталираната библиотека попада в IDE фолдера
libraries“’.
Системните библиотеки се включват в даден скеч с: #include <Servo.h>.

Локалните библиотеки се добавят във формата на файл във фолдера, в който се
намира скеча. След това в прозореца IDE на стартирания скеч се добавя нов
прозорец, в който се извиква библиотеката. Локалната библиотека се включва в
скеча с “#include “Servo.h”. Разликата е в употребата на стрелки или
кавички. Ето порядъка на инсталация на библиотеката ardubottom.h за този скеч:

Неправилната инсталация на библиотеките може да доведе до грешка при проверка на
скеча “Error compiling bord Arduino Nano“. Това съобщение за грешка не отразява
правилно причината. То не дава представа за причината на грешката – в скеча или
в библиотеката. Но когато библиотеката е инсталирана локално, функцията
“проверка” проверява не само скеча, но и библиотеката и с подчертаване с жълт
цвят може да даде по-точни указания. Именно по този начин открих грешките в
първия скеч, която се оказа в ServoTimer2.h.

А ето драйверът L9110-D, който използвам за тази конструкция:

KN34PC - Arduino-управление на модел на танк Т200

Направих експеримент и с драйвер за мотори L298, който не беше удачен:

KN34PC - Arduino-управление на модел на танк Т200

Забележка №1: Ако използвате драйвер L9110 не превишавате захранващото
напрежение над 10V поради опасност от повреда. Ако използвате драйвер TB6612
напрежението не трябва да надвишава 13V.

Забележка №2: Ако използвате драйвер TB6612 трябва да имате предвид, че той се
захранва с две напрежения: 5V от Arduino за съвместяване на логическите нива и
(4.5 ÷ 13.5)V за захранване на електромотори.

Забележка №3: Командите за управление на горните драйвери не изискват
промяна.

Забележка №4: Изборът на подходящ мотор е от изключително значение като пиковия
ток (най-често при първоначален пуск) не трябва да превишава максимално
допустимия на драйверите. В противен случай моторът няма да се завърти или
драйверът ще изгори в буквалния смисъл на думата.

Предвид на последната забележка, в процеса на реализацията на конструкцията
практически регистрирах недостатъците на китайските електромотори. Например,
редуктора, който бях закупил беше в комплектацията с такива мотори с напрежение
3-6 волта и скорост 11,200 оборота в минута, които не бяха необходими за моя
проект. По-големия недостатък е сравнително високия консумиран ток при нормално
завъртане (захранване 6 волта) който беше около 360mA, изключително висок, а
пусковия ток достигаше 10 пъти по-голяма стойност. Наложи се да го заменя с друг
по-маломощен мотор. (Токоизправителят в домашната ми “лаборатория” е със защита
с максимален ток 1.5А, при което на практика при пуска на мотора тя сработваше и
напрежението му падаше наполовина, а драйверът изгоря с пушек). На следващата
снимка съм показал отляво оригиналния мотор, а в дясно моторът с който съм го
заменил, с напрежение 12V.

KN34PC - Arduino-управление на модел на танк Т200

Сглобяването на редуктора беше цяло приключение. Самият той представлява два
редуктора с два мотора в един корпус и правилността на монтажа е от значение за
да получим еднакви предавателни числа. В случая 344:1 за да получа с избрания от
мене мотор (показан по-горе) около 1,5-2 об./сек. Скоростта на въртене има
значение за линейната скорост на робота. Например: по-малко предавателно число,
по-висока линейна скорост.

На следващите снимки може да видите редуктора преди и след сглобяване:

Преди да започна сглобяването на двата редуктора, подредих всички съставни части
и зъбчати колела по размери в две еднакви и еднотипни групи, по една за всяка
от половинките. Естествено, първо сглобих редукция с по-малко предавателно число
(144:1), при което осите се завъртяха твърде бързо. Но именно така установих, че
консумирания ток е твърде голям, съответно пусковия и-и-и-и…., както казах
по-горе, модулът “драйвер за мотори” изгоря с пушек, след което се наложи да
търся друг подходящ по размери мотор за да може да се монтира в същите фабрични
отвори. Това “маркетингово проучване” ми отне една седмица, докато попаднах на
подходящия мотор, показан по-горе със скорост на въртене 7200rpm при захранващо
напрежение 12V. На снимките все още редукторът е показан с оригиналните мотори.

Разбира се, в процеса на осъществяване на този проект всички мои проучвания бяха
така да се каже, интегрирани, тоест, знаех какво търсех и съобразявах всички
части по съвместимост. Причината е, че не исках (сърце не ми даваше) да разглобя
и разчастя металния танк, който ви представих в Част I на едноименната статия.
Така реших да го заменя с евтин пластмасов модел и закупих ново шаси и комплект
вериги и колела.

Сглобяването на шасито и напасването на веригите беше част от удоволствието да
видя крайния продукт, който излезе от ръцете ми. Аз направих промени и в
конструкцията на модела като промених местоположението на колелата, тъй като
дистанцията между осите беше малка, с които трябваше да избягна както
наклоняването напред-назад, така и затормозяване при движение по неравна
повърхност:

Оригиналния вид на шасито може да видите на следващата снимка:

KN34PC - Arduino-управление на модел на танк Т200

След всички проби, които извърших на бредборд, седнах пред компютъра и изчертах
графичен оригинал на печатна платка, която беше съобразена с размера на металния
танк от Част I, но и с по-малките размери на опитния пластмасов образец от
горната снимка.

KN34PC - Arduino-управление на модел на танк Т200

На тази платка съм монтирал Arduino Nano модул – приемник на 433MHz и два
отделни драйвера за мотори. Единият на малката платчица е фабричен с ИС L9110, а
другият вдясно е с два броя ИС MC33152, които вече описах в предишните си
конструкции за управление на мотори и модел на танк. Предвидил съм възможност за
допълнително включване на светодиод за индикация на захранването, но и самата
платка Arduino Nano също има такъв. Тази опция е по избор. Към драйверите за
мотори MC33152 съм предвидил към захранването на всяка от интегралните схеми по
един диод, свързан последователно към захранването. Причината за това решение е,
че като всеки уред и моторите имат толеранс /-10%, което означава, че броя на
оборотите при еднакво захранване е възможно да бъдат: 7200rpm до /-720rpm.
Тоест ще се различават. Компенсирам това неудобство чрез последователно включени
диоди, които при в права посока намаляват захранващото напрежение с 0,7 волта,
приблизително 10% от напрежението на батерията при напрежение 9V. Това е
необходимо за съгласуваната работа на двата мотора. Изходите на моторите и
изходите на драйверите са предпазени с искрогасящи кондензатори 100nF/63V.

На следващите снимки е показан окончателния вариант на
модела, в който като драйвер за мотор е използвана ИС TB6612:

И накрая, след всички експерименти за свързване на две платки Arduino по радиоканал, аз избрах управление на модел, тъй като е най-атрактивно. В интернет
може да намерите много полезни за дома устройства, които използват различни
радиочестотни канали. Литературата по-долу е свързана с първоначалното
запознаване с принципите на осъществяване на връзка между две (или повече)
платки Arduino. От всички модули на драйвери за управление на електромотор, за
моя проект най-удачни се оказаха драйверите ИС L9110 и TB6612. L9110 се захранва
с напрежение 9V, а TB6612 с 9V-12V. На следващите видеоклипове ще забележите, че
използвания драйвер за мотор е TB6612. В архива към статията съм приложил
графичен оригинал на печатната платка, на която съм комбинирал двата драйвера.

Следващото видео илюстрира работата на робота с експерименталното шаси.

А на видеото по-долу може да видите завършения модел на танк, показан в
Част I.

Архив [zip,pcb,fzz,jpg][468kb]

***

Оказа се, че роботостроенето е голямо забавление. С описаните
конструкции в Част II и настоящата Част III на едноименните статии си поставих
за цел да изпробвам не просто управление на робот, а осъществяване на връзка
между две платки Arduino UNO (Nano). За целта управлението е много подходящо,
тъй като резултата е не само виден, но и атрактивен за околните.

След като осъществих управление на робот по радиоканал на 433 MHz, реших да експериментирам канал на честота 2400 MHz. Закупих два модула
nRF24L01, потърсих необходимата библиотека за управление
RF24
[1]
 и подходящ скеч. Бях вече закупил шаси, комплект редуктор
(напомням, че се наложи да сменя моторите) и драйвери за управление на мотори.
Наглед простичко начало.

На следващата снимка (поглед отгоре) са отбелязани значенията
на всеки от изводите на nRF24L01:

KN34PC - Arduino-управление на модел на танк Т200

Направих съответните връзки между различните модули, но нищо
не става от първия път, ако предварително не сме проучили темата. Така се получи
и с първия ми неуспешен опит. Порових се на

RF24L01 2.4GHz Radio/Wireless Transceivers How-To

[2]
за да намеря урок относно свързване на Arduino платка с радиочестотен
модул nRF24L01. Намерих такава страница и се зачетох. В нея, се оказа, че има
доста сериозна забележка, касаеща свързване на осемте извода на RF-модула.
Тоест, в зависимост от използваната библиотека, изводите се свързват към
различни пинове на Arduino. Но ето за какво става дума:

KN34PC - Arduino-управление на модел на танк Т200

Аз бях свързал изводи 3 и 4 на модула с изводи 7 и 8 на
платката. Веднага направих корекция, както в предавателния код, така и в
приемния код, заменяйки изводи 7 => 9 и 8 => 10. Така и в предавателната и в
приемателната платка RF-модула заемат еднакви изводи –
9, 10, 11, 12, 13. IRQ8 не се използва. След това подреждане, направих промяна в
номерацията на цифровите пинове които подават командите за управление към
драйвера за мотор L298. Изходите станаха 2, 3, 4, 5, с което също се подредиха
последователно. Тук трябва да вметна забележката, че за този експеримент
използвам мощния драйвер за мотор L298, тъй като тока на моторите е доста висок,
а стартовия достига дори до 3А. Трябва да се има предвид, че драйвера има шина с
изход от вградения в него интегрален стабилизатор 7805, чието напрежение от 5V
може да се използва за директно захранване на платката Arduino. Изпробвах и този
начин на захранване, но се оказа че искренето на моторите подава грешни команди
за изпълнение, поради което в крайния вариант на експеримента захраних Arduino
през вход VIN, на който подадох напрежението от батерията, в случая 12V.

KN34PC - Arduino-управление на модел на танк Т200

Схемата на свързване на предавателя и приемника имат следния
вид като изводите 7 и 8 не са заменени с 9 и 10:

Целият експеримент е осъществен с използване на стандартни кабелчета и бредборд, а като шаси използвах вече показаното шаси на Tamyia в
предишната част.

KN34PC - Arduino-управление на модел на танк Т200

Предавателят монтирах директно с кабелчета за платката
Arduino:

KN34PC - Arduino-управление на модел на танк Т200

Монтажът на приемната част ми отне повече време, тъй като
използвах възможностите, които даваше шасито. Ползата от фабричните отвори се
оказа полезна при монтажа не само на редуктора с моторите, но и на платките Arduino и моторния драйвер L298. И двете платки монтирах върху дистанционни
шпилки във височина. По този начин драйверът за моторите се окачи над самите
мотори, а платката Arduino в предната част на щасито, като под нея се образува
достатъчно пространство, в което поместих акумулаторната Li-Ion батерия 11,2V.

KN34PC - Arduino-управление на модел на танк Т200


Архив: arh_adruino_tank_v3.zip
[zip,ino][2kb]

И тъкмо направих видео файла,
показан по-горе, и ми хрумна да експериментирам с още една функционалност. С
няколко промени в скеча реших да направя пропорционалност на телеуправлението.
За какво иде реч – пропорционално на отклонението на ръчката на джойстика да се
променя скоростта на управление на двигателите. Това позволява промяна на
скоростта на движение напред и назад от нула до максимум и от максимум до нула в
зависимост от положението на джойстика. Но в скеча, чиито функции показах с
видео файла, тази възможност не съществуваше. Движението на двигателите беше
едноскоростно – включени или изключени.

За да направя тази функционалност беше необходимо да захраня
моторите само от пинове PWM (ШИМ). До този момент двигателите се управляваха
чрез цифрови пинове 2,3,4,5. От тях пинове 3 и 5 са ШИМ. Необходими ми бяха още
като например 3,5 и 6,9. Но в скеча пиновете, с които се осъществява
командването на радиомодула (9, 10, 11, 12, 13) два с PWM (9 и 10) са заети.

Промяната която направих е следната:

а) промених обмяната на данни между Arduino и nRF24L01

Като преадресирах пиновете в ред – RF24 myRadio (9, 10); с
RF24 myRadio (8, 10); с което освободих пин9 с ШИМ за моя експеримент.

nRF24L01 Arduino pins:
1 GND
2 3V3
38
410
513
611
712

б) преадресирах пиновете за управление на моторите:

от:
int OUT1 = 2;
int OUT2 = 3;
int OUT3 = 4;
int OUT4 = 5;

със:
int OUT1 = 3;
int OUT2 = 5;
int OUT3 = 6;
int OUT4 = 9;

По този начин осъществих идеята за пропорционално управление
на скоростта на моторите. Постигнах плавна промяна на скоростта на моторите към
увеличаване или намаляване. Казано на шофьорски език: скоростта се променя в
зависимост от педала на газта.

Приложения в архива програмен код е с нанесените промени.

На следващите снимки може да видите
модела на танка в завършен вид, като за целта съм изработил печатна платка върху
която са монтирани всички модули и части:

Пожелавам успех в ардуиностроенето!

Литература:
1.

RF433 Wireless TX RX Module Pair

2. Make a
Simple RC (Remote Controlled) Robot Car

3.
A step-by-step guide to make a simple remote control car that operates in RF (radio
frequency)

4.

Remote Operated Spy Robot Circuit

5.
Валери Терзиев, Николай Николов “Приемник за пропорционално телеуправление”,
сп. “Радио, телевизия и електроника”, 1988 / кн.1

6.
Николай Николов, Валери Терзиев “Пропорционално телеуправление
– изпълнителни
механизми”, сп. “Радио, телевизия и електроника”, 1988
/ кн.4

7.
Arduino ServoTimer2 and VirtualWire 433MHz Receiver

8.
RF Joystick for Arduino

9.
Wirelessly Control A Robot Using Arduino and RF Modules

10.
Подключение к Arduino 433МГц радиопередатчика и радиоприемника. Беспроводное управление реле

11.
Arduino и беспроводной радиомодули на 433 МГц

12.
Remote controlled robot using Arduino, 555 timer circuit and 433MHz RF modules

13.
Радиоуправление на Arduino

14.
Project: Ardu-Bot-Tom – RF Link Controlled Robot


15. Arduino driver for nRF24L01
16.
RF24L01 2.4GHz Radio/Wireless Transceivers How-To

17.
Гусеницы для RC робота на arduino nrf24l01

18.
Wireless Arduino controlled Tank (nRF24L01)

Валери Терзиев
28 октомври 2023 година,
30 ноември 2023 година,
28 декември 2023 година,
доп. 16 март 2023 година, доп. 18 февруари 2023 година

Простой робот на мк esp8266 c micropython

Привет, Хабр!

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

КДПВ:

KN34PC - Arduino-управление на модел на танк Т200

Итак, в первых двух частях было описано изготовление самоходной платформы, управляемой через web интерфейс по wifi.

Задача на текущий этап — оснастить эту платформу УЗ датчиком HC-SR04, и добавить возможность работы в автономном режиме.

Для начала — механическая часть:
необходимо закрепить датчик и сервомашинку в корпусе, проектируем (я использовал для этого FreeCAD) и изготавливаем недостающие детали:

KN34PC - Arduino-управление на модел на танк Т200

KN34PC - Arduino-управление на модел на танк Т200

Потом — электрическая:
составляем схему (например, во Fritzing) и выполняем коммутацию в соответствии с ней:

KN34PC - Arduino-управление на модел на танк Т200

После чего, попытаемся заставить всё это взлететь…

Так как хотелось, что бы отдельные функции программы робота выполнялись параллельно (например, процесс сканирования дистанции до препятствий и функции движения), пришлось погрузиться в возможности модуля asyncio. Более подробно работа с asyncio описана в этой и этой статьях.

Например, для мигания светодиодом можно применить такую сопрограмм(coroutine), которая практически не отличается от синхронной:

import uasyncio as asyncio
from machine import Pin

# onboard LED is connected to D0(GPIO16)
syst_led =  Pin(16, Pin.OUT)

async def blink_led(led, interval_ms):
    led_val = True
    while True:
        led_val = not(led_val)
        led_state = led.value(int(led_val))
        await asyncio.sleep_ms(interval_ms)

# define loop
loop = asyncio.get_event_loop()

#create looped tasks
loop.create_task(blink_led(syst_led, interval_ms=250))

# loop run forever
loop.run_forever()

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

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

Callback для кнопки:

from machine import Pin

run_flag = False

# on/off button
button =  Pin(15, Pin.IN, Pin.PULL_UP) # connected to D8 (GPIO15)

# callback function for start/stop button
def callback(p):
    global run_flag
    run_flag = not(run_flag)
    print('set run_flag', run_flag, p)

# create callback for button:
button.irq(trigger=Pin.IRQ_FALLING, handler=callback)

Измерение дистанции:

import uasyncio as asyncio
from utime import sleep, sleep_us
from machine import Pin, time_pulse_us

# HC-SR04 ultrasonic sensor connected to GPIO12(D6)-trigger and GPIO13(D7)-echo
trig=Pin(12, Pin.OUT)
echo=Pin(13, Pin.IN)

async def async_measure_range():
    echo_timeout_us=500*2*30 # Timeout in microseconds to listen to echo pin.
    trig.off() # Stabilize the sensor
    sleep_us(5)
    trig.on()
    sleep_us(10) # Send a 10us pulse.
    trig.off()
    try:
        pulse_time = time_pulse_us(echo, 1, echo_timeout_us)
    except:
        pass
    dist = (pulse_time / 2) / 29.1
    return dist

Сканирование сектора (с вызовом сопрограммы измерения дистанции):

import uasyncio as asyncio
from machine import Pin, PWM

pos_actual = 75
dist_cm = 50

# servo SG90 connected to GPIO14(D5)
p14 =  Pin(14, Pin.OUT)
servo = PWM(p14, freq=50)

async def radar_scan(interval_ms):
    pos_list = [45,75,105,75]
    global pos_actual
    global dist_cm
    while True:
        if run_flag:
            for pos in pos_list:
                servo.duty(pos)
                await asyncio.sleep_ms(interval_ms)
                dist_cm = await async_measure_range()
                pos_actual = pos
                print('pos_actual = %s, dist_cm = %s' % (pos_actual, dist_cm)
        elif not run_flag:
            await asyncio.sleep(0) # do nothing

# define loop
loop = asyncio.get_event_loop(

#create looped tasks
loop.create_task(radar_scan(interval_ms=250))

# loop run forever
loop.run_forever()

В процессе отладки сенсор, время от времени, выдавал отрицательное значение дистанции. Оказалось —

«Электроника — это наука о плохих контактах»

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

Осталось прикрутить логику выбора действия на основе результатов сканирования:

avoid_left = False
avoid_right = False
avoid_backward = False

async def make_decision(interval_ms, avoid_limit_cm):
    global avoid_left
    global avoid_right
    global avoid_backward
    while True:
        if run_flag:
            # make decision what to do
            if pos_actual == 45 and dist_cm < avoid_limit_cm :
                avoid_left = True
                if debug : print('avoid_left = %s' % avoid_left)
            elif pos_actual == 45 and dist_cm >= avoid_limit_cm :
                avoid_left = False
                if debug : print('avoid_left = %s' % avoid_left)
            elif pos_actual == 75 and dist_cm < avoid_limit_cm*1.25 :
                avoid_backward = True
                if debug : print('avoid_backward = %s' % avoid_backward)
            elif pos_actual == 75 and dist_cm >= avoid_limit_cm*1.25 :
                avoid_backward = False
                if debug : print('avoid_backward = %s' % avoid_backward)
            elif pos_actual == 105 and dist_cm < avoid_limit_cm :
                avoid_right = True
                if debug : print('avoid_right = %s' % avoid_right)
            elif pos_actual == 105 and dist_cm >= avoid_limit_cm :
                avoid_right = False
                if debug : print('avoid_right = %s' % avoid_right)
            # for debuging
            if debug : print('pos = %s, dist_cm = %s' % (pos_actual,dist_cm))  
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            await asyncio.sleep(0) # do nothing

#create looped tasks
loop.create_task(make_decision(interval_ms=250, avoid_limit_cm=15))

Двигательные функции:

from random import getrandbits

async def moving(interval_ms):
    while True:
        if run_flag:
            # moving functions
            if avoid_backward :
                print('avoid_backward = %s' % avoid_backward)
                await backward(interval_ms*2)
                if bool(getrandbits(1)) :
                    await right_rotate(interval_ms getrandbits(3)*100)
                    await stop_all()
                else:
                    await left_rotate(interval_ms getrandbits(3)*100)
                    await stop_all()
            elif avoid_left :
                print('avoid_left = %s' % avoid_left)
                await left_turn(interval_ms)
            elif avoid_right :
                print('avoid_right = %s' % avoid_right)
                await right_turn(interval_ms)
            else:
                print('move_forward')
                await forward(interval_ms)
                
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            #stop all motors first
            await stop_all()
            await asyncio.sleep(0) # do nothing

#create looped tasks
loop.create_task(moving(interval_ms=1000))

И управление моторами
# nodemcu pins from the motor shield
p5 = Pin(5, Pin.OUT)  # connected to GPIO4(D1)
p4 = Pin(4, Pin.OUT)  # connected to GPIO4(D2)
revrs_L = Pin(0, Pin.OUT, value=0)  # connected to GPIO0(D3)
revrs_R = Pin(2, Pin.OUT, value=0)  # connected to GPIO2(D4) , also connected to onboard wifi LED
motor_L = PWM(p5, freq=1000, duty=0)
motor_R = PWM(p4, freq=1000, duty=0)
speed = 1023  #TODO: variable speed

async def stop_all():
    revrs_L.value(0)
    motor_L.duty(0)
    revrs_R.value(0)
    motor_R.duty(0)

async def forward(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def backward(interval_ms):
    revrs_L.value(1)
    motor_L.duty(speed)
    revrs_R.value(1)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def right_rotate(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(1)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def left_rotate(interval_ms):
    revrs_L.value(1)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def right_turn(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(0)
    await asyncio.sleep_ms(interval_ms)

async def left_turn(interval_ms):
    revrs_L.value(0)
    motor_L.duty(0)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

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

async def blink_led(led, interval_ms):
    led_val = True
    while True:
        if run_flag:
            led_val = not(led_val)
            led_state = led.value(int(led_val))
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            await asyncio.sleep(0) # do nothing

#create looped tasks
loop.create_task(blink_led(syst_led, interval_ms=250))

После чего, остаётся только собрать всё это

в одно целое
import gc
import uasyncio as asyncio
from utime import sleep, sleep_us
from machine import Pin, PWM, time_pulse_us
from random import getrandbits

# nodemcu pins from the motor shield
p5 = Pin(5, Pin.OUT)  # connected to GPIO4(D1)
p4 = Pin(4, Pin.OUT)  # connected to GPIO4(D2)
revrs_L = Pin(0, Pin.OUT, value=0)  # connected to GPIO0(D3)
revrs_R = Pin(2, Pin.OUT, value=0)  # connected to GPIO2(D4) , also connected to onboard wifi LED
motor_L = PWM(p5, freq=1000, duty=0)
motor_R = PWM(p4, freq=1000, duty=0)
speed = 1023  #TODO: variable speed

# servo SG90 connected to GPIO14(D5)
p14 =  Pin(14, Pin.OUT)
servo = PWM(p14, freq=50)
# on/off button
button =  Pin(15, Pin.IN, Pin.PULL_UP) # connected to D8 (GPIO15)
# onboard LED is connected to D0(GPIO16)
syst_led =  Pin(16, Pin.OUT)
# HC-SR04 ultrasonic sensor connected to GPIO12(D6)-trigger and GPIO13(D7)-echo
trig=Pin(12, Pin.OUT)
echo=Pin(13, Pin.IN)

#global flags and variables
run_flag = False
avoid_left = False
avoid_right = False
avoid_backward = False
pos_actual = 75
dist_cm = 50
debug = False


# callback function for start/stop button
def callback(p):
    global run_flag
    run_flag = not(run_flag)
    print('set run_flag', run_flag, p)

# sync fuctions
def stop_all_sync():
    revrs_L.value(0)
    motor_L.duty(0)
    revrs_R.value(0)
    motor_R.duty(0)
    
# async fuctions
async def stop_all():
    revrs_L.value(0)
    motor_L.duty(0)
    revrs_R.value(0)
    motor_R.duty(0)

async def forward(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def backward(interval_ms):
    revrs_L.value(1)
    motor_L.duty(speed)
    revrs_R.value(1)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def right_rotate(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(1)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def left_rotate(interval_ms):
    revrs_L.value(1)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def right_turn(interval_ms):
    revrs_L.value(0)
    motor_L.duty(speed)
    revrs_R.value(0)
    motor_R.duty(0)
    await asyncio.sleep_ms(interval_ms)

async def left_turn(interval_ms):
    revrs_L.value(0)
    motor_L.duty(0)
    revrs_R.value(0)
    motor_R.duty(speed)
    await asyncio.sleep_ms(interval_ms)

async def moving(interval_ms):
    while True:
        if run_flag:
            # moving functions
            if avoid_backward :
                print('avoid_backward = %s' % avoid_backward)
                await backward(interval_ms*2)
                if bool(getrandbits(1)) :
                    await right_rotate(interval_ms getrandbits(3)*100)
                    await stop_all()
                else:
                    await left_rotate(interval_ms getrandbits(3)*100)
                    await stop_all()
            elif avoid_left :
                print('avoid_left = %s' % avoid_left)
                await left_turn(interval_ms)
            elif avoid_right :
                print('avoid_right = %s' % avoid_right)
                await right_turn(interval_ms)
            else:
                print('move_forward')
                await forward(interval_ms)
                
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            #stop all motors first
            await stop_all()
            await asyncio.sleep(0) # do nothing


async def blink_led(led, interval_ms):
    led_val = True
    while True:
        if run_flag:
            led_val = not(led_val)
            led_state = led.value(int(led_val))
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            await asyncio.sleep(0) # do nothing
            
async def async_measure_range():
    echo_timeout_us=500*2*30 # Timeout in microseconds to listen to echo pin.
    trig.off() # Stabilize the sensor
    sleep_us(5)
    trig.on()
    sleep_us(10) # Send a 10us pulse.
    trig.off()
    try:
        pulse_time = time_pulse_us(echo, 1, echo_timeout_us)
    except:
        pass
    dist = (pulse_time / 2) / 29.1
    return dist

async def make_decision(interval_ms, avoid_limit_cm):
    global avoid_left
    global avoid_right
    global avoid_backward
    while True:
        if run_flag:
            # make decision what to do
            if pos_actual == 45 and dist_cm < avoid_limit_cm :
                avoid_left = True
                if debug : print('avoid_left = %s' % avoid_left)
            elif pos_actual == 45 and dist_cm >= avoid_limit_cm :
                avoid_left = False
                if debug : print('avoid_left = %s' % avoid_left)
            elif pos_actual == 75 and dist_cm < avoid_limit_cm*1.25 :
                avoid_backward = True
                if debug : print('avoid_backward = %s' % avoid_backward)
            elif pos_actual == 75 and dist_cm >= avoid_limit_cm*1.25 :
                avoid_backward = False
                if debug : print('avoid_backward = %s' % avoid_backward)
            elif pos_actual == 105 and dist_cm < avoid_limit_cm :
                avoid_right = True
                if debug : print('avoid_right = %s' % avoid_right)
            elif pos_actual == 105 and dist_cm >= avoid_limit_cm :
                avoid_right = False
                if debug : print('avoid_right = %s' % avoid_right)
            # for debuging
            if debug : print('pos = %s, dist_cm = %s' % (pos_actual,dist_cm))  
            await asyncio.sleep_ms(interval_ms)
        elif not run_flag:
            await asyncio.sleep(0) # do nothing

async def radar_scan(interval_ms):
    pos_list = [45,75,105,75]
    global pos_actual
    global dist_cm
    while True:
        if run_flag:
            for pos in pos_list:
                servo.duty(pos)
                await asyncio.sleep_ms(interval_ms)
                dist_cm = await async_measure_range()
                pos_actual = pos
        elif not run_flag:
            await asyncio.sleep(0) # do nothing
    
#stop all motors first
stop_all_sync()

# move servo to initial position
print('Move sensor to initial position...')
servo.duty(75)
sleep(1) #wait 1s for servo reaching initial position
print('Waiting for start button...')

#enable gc
gc.enable()

# create callback fo button:
button.irq(trigger=Pin.IRQ_FALLING, handler=callback)

# define loop
loop = asyncio.get_event_loop()

#create looped tasks
loop.create_task(blink_led(syst_led, interval_ms=250))
loop.create_task(radar_scan(interval_ms=250))
loop.create_task(make_decision(interval_ms=250, avoid_limit_cm=15))
loop.create_task(moving(interval_ms=1000))

# loop run forever
loop.run_forever()

и проверить в работе:

Однако, хотелось бы сохранить и возможность ручного управления через web-страничку…

Для этого, в отдельной сопрограмме добавим простенький веб-сервер:

async def web_page(request):
    global auto_run_flag
    motor_state="Stopped"
    if request.find('GET /?forward') > 0:
        motor_state="Going Forward"
        auto_run_flag = False
        forward_sync()
    elif request.find('GET /?left_rotate') > 0:
        motor_state="Rotate Left"
        auto_run_flag = False
        left_rotate_sync()
    elif request.find('GET /?right_rotate') > 0:
        motor_state="Rotate Right"
        auto_run_flag = False
        right_rotate_sync()
    elif request.find('GET /?left_turn') > 0:
        motor_state="Turn Left"
        auto_run_flag = False
        left_turn_sync()
    elif request.find('GET /?right_turn') > 0:
        motor_state="Turn Right"
        auto_run_flag = False
        right_turn_sync()
    elif request.find('GET /?backward') > 0:
        motor_state="Going Backward"
        auto_run_flag = False
        backward_sync()
    elif request.find('GET /?stop') > 0:
        motor_state="Stopped"
        auto_run_flag = False
        stop_all_sync()
    elif request.find('GET /?auto') > 0:
        auto_run_flag = not auto_run_flag
        if  auto_run_flag :
            motor_state="Autopilot"
        elif not auto_run_flag :
             motor_state="Stopped"
             stop_all_sync()

    html = """<html><head><title>RoboTank WEB</title> 
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="data:,"> <style>
    html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
    h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}
    .button{display: inline-block; background-color: #33c080; border: none; 
    border-radius: 4px; color: white; text-decoration: none; font-size: 30px; width:100%}
    .button2{background-color: #4286f4; width:30%}
    .button3{background-color: #eb2b10; width:35%}
    .button4{background-color: #8386f4; width:44%}
    </style></head>
    <body> <h1>RoboTank WEB</h1> 
    <p>Status : <strong>"""   motor_state   """</strong></p>
    <p><a href='/?forward'><button class="button">Forward</button></a></p>
    <p><a href='/?left_turn'><button class="button button2">LEFT</button></a>
    <a href='/?stop'><button class="button button3">STOP</button></a>
    <a href='/?right_turn'><button class="button button2">RIGHT</button></a>
    <p><a href='/?backward'><button class="button">Backward</button></a></p>
    <p><a href='/?left_rotate'><button class="button button4">L-rotate</button></a>
    <a href='/?right_rotate'><button class="button button4">R-rotate</button></a></p>
    <p><a href='/?auto'><button class="button button3">AUTO</button></a></p>
    </body></html>"""
    return html

async def web_handler(reader, writer):
    try:
        request = str(await reader.read(1024))
        #print('request = %s' % request)
        header = """HTTP/1.1 200 OKnContent-Type: text/htmlnConnection: closenn"""
        response = await web_page(request)
        await writer.awrite(header)
        await writer.awrite(response)
        await writer.aclose()
        print("Finished processing request")
    except Exception as e:
        print(e)
    
async def tcp_server(host, port):
    server = await asyncio.start_server(web_handler, host, port)

#create looped tasks
loop.create_task(tcp_server('0.0.0.0', 80))

Внешний вид интерфейса:

KN34PC - Arduino-управление на модел на танк Т200

Испытания финальной версии:

Исходники доступны

по ссылке.

Источники вдохновения:

docs.micropython.org/en/latest/library/uasyncio.html
radiocopter.ru/ru/post/484446
radiocopter.ru/ru/post/337420
radiocopter.ru/ru/post/484472
github.com/peterhinch/micropython-async/blob/master/TUTORIAL.md
github.com/rsc1975/micropython-hcsr04
medium.com/@pgjones/an-asyncio-socket-tutorial-5e6f3308b8b0

Оцените статью
Радиокоптер.ру
Добавить комментарий