- Машинка на Arduino, управляемая Android-устройством по Bluetooth, — полный цикл (часть 1)
- Немного об уровне, авторе и предостережения
- Задача
- Понадобится
- Основа конструкции
- Установка Arduino
- Определение угла поворота
- Подключение угла и код
- Распараллеливание ходовых колес
- Подключение Bluetooth
- Система отправки команд
- Заключение первой части
- Простая Bluetooth машинка на Arduino
Машинка на Arduino, управляемая Android-устройством по Bluetooth, — полный цикл (часть 1)
Подробная история того, как из трех двигателей была собрана машина на Arduino, управляемая Android-устройством по Bluetooth. В нескольких десятках абзацев постараюсь максимально пошагово изложить, куда подключить каждый из проводов, как написать фирменное приложение и на каких детских граблях пришлось попрыгать больше недели.
Немного об уровне, авторе и предостережения
Я, автор, пацан 16-17 лет с подмосковной деревни, специализируюсь на написании android-приложений (а там сложнее что-то сжечь), поэтому ответственность за оптимальный подход к решению задач с себя снимаю.
Практически каждый из нижеописанных этапов занимал у меня больше, чем стоило бы, времени. Наверно, именно по этой причине хочу поделиться опытом. И при этом буду очень рад, если поругаете за ошибки и подскажите за оптимизацию.
Задача
Задача легчайшая – заставить ездить машинку, управляемую Arduino, а пульт заменить андроидом. Но в большинстве моментов пришлось изобретать колесо, потому что в интернетах подходящего решения найдено не было.
Понадобится
- Arduino
- Motor Shield (в моем случае две)
- Bluetooth
- Android
- Провода обычные
Основа конструкции
За основу была взята машина Lego Outdoor Challenger (в реальности выглядит менее пафосно). Все, что от нее осталось: корпус (все элементы украшения сняты) и три двигателя.
У машинки была своя плата, но одна из задач подразумевала универсальность: это сделал я, это смогут повторить другие. Мозги вынул, поставил Arduino Uno.
Установка Arduino
Создатели почему-то не предусмотрели места для Arduino, потому крепил на шурупы, просверлив пластик. Под плату подложил фанеру, чтобы ничего не закоротило. Под шурупы лучше подсунуть что-то пластиковое (кусочек бутылки), ибо плата от железный болтов не защищена.
Поверх платы сразу поставил две motor shiled, так надо. Чтобы управлять второй, придется прокинуть один провод с любого digital порта на H1 (направление) и второй с пина с поддержкой шима (помечены знаком «~», обычно 10, 11) на E1 (скорость).
Определение угла поворота
За поворот машинки отвечает на удивление не сервопривод, а обычный двигатель. Встает проблема: хорошо бы было его не сжечь, ведь угол поворота ограничен, а крутиться двигатель может сколько угодно.
Вариант с методом тыка отпадает, так как при разном уровне батареи количество тока, подаваемое на двигатель, будет изменяться, что приведет к постоянно меняющемуся углу. Крутить до упора тоже нельзя, рано или поздно рассыплются шестеренки.
Решение проблемы: отслеживать угол через замыкание. На фото продемонстрирована небольшая штучка, которая крепится недалеко от поворотного механизма. На часть, которая крутится вместе с колесами влево/вправо двигателем, прикрепляется гребешок с железными контактами.
Принцип работы: к каждой линии припаивается провод (всего их четыре), нижний подключается к плюсу (он зажат гребешком всегда, см. картинку), остальные провода уходят на минус. Когда зубик гребешка попадает и на нижний ряд, и на, допустим, третий, происходит замыкание, ток течет, это замечает Arduino.
Благодаря различным комбинациям трех полос, можно определить до семи углов. Например, когда ток есть на всех линиях, колеса повернуты в крайнее правое положение, когда ток есть только на верхней, колеса повернуты максимально влево. В таблице предоставлены все варианты.
Подключение угла и код
Для каждого уровня был выбран свой цвет: нижний – зеленый, первый снизу – красный, второй – черный, третий – белый. На начальном этапе использовались breadboard и светодиоды для визуальной отладки.
Схема подключения показана на рисунке. Плюс тянем к зеленому, остальные протягиваем к минусу. Через резистор, установленный для устранения помех и отсутствия КЗ, подключаем провода к выходам A0-A2. Выбраны они просто из экономии остальных портов.
Код дан с комментариями. Подключаем пины и опрашиваем их через digitarRead(). Если напряжение есть, вернется значение true. Далее смотрим, если результат означает, что колеса в крайних положениях, запрещаем дальнейший поворот в эту сторону.
Небольшая хитрость: поскольку выходы на 5В и 3.3В понадобятся в будущем, можно поставить плюс на один из digital-пинов. Перед каждой проверкой угла выдавать ток через digitalWrite(whitePin), потом проверять угол и убирать ток.
int speedTurn = 180; //скорость поворота, от 0 до 255 //пины для определения поворота int pinRed = A0; int pinWhite = A1; int pinBlack = A2; int pinAngleStop = 12; //выводит ток на светодиод, если достигнут максимальный угол, нужен //только для отладки void setup() < //пины поворота на считывание pinMode(pinRed, INPUT); pinMode(pinBlack, INPUT); pinMode(pinWhite, INPUT); //светодиод pinMode(pinAngleStop, OUTPUT); //пины драйвера двигателя, направление и скорость pinMode(angleDirection, OUTPUT); pinMode(angleSpeed, OUTPUT); Serial.begin(9600); >//функция вызывается из loop(), когда приходит команда с андроида void turn(int angle) < digitalWrite(pinAngleStop, HIGH); //выдаем ток на провод, подключенный к плюсу delay(5); //немного ждем, чтобы ток "успел" дойти if(angle >149) < if( digitalRead(pinWhite) == HIGH && digitalRead(pinBlack) == LOW && digitalRead(pinBlack) == LOW) < //если достигнуто крайне правое положение, выйти из функции не подавая ток, чтобы не //сжечь мотор return; >//если угол не максимальный, поворачиваем digitalWrite(angleDirection, HIGH); analogWrite(angleSpeed, speedTurn); > else if (angle < 31) < if(digitalRead(pinRed) == HIGH && digitalRead(pinBlack) == HIGH && digitalRead(pinWhite) == HIGH) < //если достигнуто крайне левого положение, выйти из функции не подавая ток, чтобы не //сжечь мотор return; >//если угол не максимальный, поворачиваем digitalWrite(angleDirection, LOW); analogWrite(angleSpeed, speedTurn); > digitalWrite(pinAngleStop, LOW); //убираем ток с определителя угла delay(5); >
Распараллеливание ходовых колес
Изначально два ходовых двигателя соединены вместе. Их рассоединил по двум причинам: поворот эффективней, если колеса крутятся в разные стороны, и два мощных двигателя одна плата не вытянет.
Проблема: у motor shield два выхода, каждый из которых выдает до 2 ампер. Каждый двигатель ест по 0,7А. Вроде меньше, но не при максимальных нагрузках. Допустим, машинка застряла в песке или уперлась, ток возрастает выше ампера. Не критично, но потенциально опасно.
А вот критичным оказалось то, что плата греется. Через минуты полторы после заезда, motor shield нагревалась и начинала работать безобразно: токи подаются не те, колеса не крутятся и прочее.
Решение обоих проблем: один двигатель подключил к одной motor shield, второй – к другой. Как ни странно, помогло. Температура упала, перегрев отсутствует. Можно было поставить радиатор, но крепить тяжело.
Подключение Bluetooth
Я использовал модель HC-05, что сыграло роковую шутку. Подключаются все блютузы одинаково: один провод на 3.3В (иногда начинал работать только от 5В), второй на минус, еще два на порт 0 и 1 (чтение и отправка соответственно). Провод, подписанный RXD на bluetooth, втыкается в TXD ардуино, а TXD в RXD (если перепутаете, то данных не увидите).
Есть оговорка: порты 0 и 1 по умолчанию используются Serial, через который заливает скетч. То есть, пока воткнут блютуз, скетч не зальется. Есть два выхода: вынимать блютуз на время заливки или переназначить входы и выходы блютуза. Второй вариант осуществляется двумя строчками
#include \\подключение библиотеки SoftwareSerial BTSerial(8, 9); \\установка 8 и 9 пина заместо 0 и 1
Подводный камень, съевший у меня трое суток работы – скорость общения. По привычке установил 9600 и пошел пробовать. То данные не приходили, то была каша символов. И в конце концов ответ – модель HC-05 общается на 38400! Очень сильно обратите внимание на то, что в Setup() я выполню BTSerial.begin(39400), хотя Serial.begin(9600).
Система отправки команд
Статья становится слишком длинной, поэтому рассмотрение кода Arduino и Android вынесу в отдельную вторую часть, а сейчас опишу принцип.
На андроид устройстве есть джойстик (круг, о реализации которого также во второй части). Андроид считывает показания с него и конвертирует их в подходящие для ардуино числа: скорость из пикселей превращает в значение от -255 до 255 (отрицательные – задний ход), а также определяет угол. Я сознательно отдал эту задачу телефону, так как он куда мощнее и спокойно справится с подсчетом нескольких сотен значений в секунду.
После установки сокета данные отправляются в следующем формате: @скорость#*угол#. @ — говорит о том, что следующие цифры содержат скорость, # — извещает об окончании значения скорости, * — начало значения угла, # — закончить запись угла. Цикл бесконечен, команды отправляются каждые 100 миллисекунд (цифра подобрана оптимальная). Если ничего не нажато на андроиде, то ничего и не отправляется.
Алгоритм приема данных подробно описан в коде скетча. Он не раз переписывался и, как по мне, работает идеально.
Заключение первой части
В этой статье я попытался раскрыть все, что касается физической части машинки. Вероятнее всего, что-то упустил, так что обязательно спрашивайте.
Но самое интересное, как по мне, осталось на второе – программа Arduino и приложение на Android, там творится настоящая магия, по крайней мере, для молодого меня.
Если вы не найдете ответа на какую-то часть и захотите потыкать меня в недостатки лично, жду – dendolg1@mail.ru, .
UPD: вторая часть уже вышла — habr.com/post/424813
Простая Bluetooth машинка на Arduino
Широкое распространение и дешевизна платформы Arduino и различных робоплатформ позволило любителям создавать радиоуправляемые машинки на любой вкус. А широкое распространение смартфонов позволило использовать их в качестве контроллеров этих машинок. Главной проблемой для многих любителей Arduino является отсутствие опыта в программировании под Android. Сегодня я расскажу, как легко решить эту проблему, используя среду визуальной разработки android-приложений App Inventor 2.
Постройку любой машинки надо начинать с «железа», поэтому вкратце опишу, что использовал для своей машинки:
arduino nano
bluetooth module HC-05
Z-Mini Motor Sensor Shield L293D
2WD Motor Chassis
Конфигурация «железа» не играет большой роли в этом проекте, поэтому шасси, шилд и саму ардуино можно заменить на любые аналоги.
Теперь перейдем к созданию приложения для Android. App Inventor — среда визуальной разработки android-приложений, работает из браузера. Заходим на сайт, разрешаем доступ к своему аккаунту в Google, нажимаем кнопку «create» и создаем новый проект. В новом проекте методом «Drag and Drop» создаем 4 кнопки для выбора направления движения и одну для подключения к нашему bluetooth модулю. Примерно так:
Далее нажимаем на кнопку «Blocks» в правом верхнем углу и все тем же методом перетаскивания элементов создаем логику работы нашего android-приложения примерно вот так:
Теперь остается скомпилировать приложение, нажав на кнопку «Build».
С написанием скетча я думаю у любителей ардуино проблем не возникнет, скажу лишь, что можно взять выбрать из готовых скетчей, где управление машинкой осуществляется с компьютера по sireal порту. Я использовал этот
int val;
int IN1 = 4;
int IN2 = 7;
int EN1 = 6;
int EN2 = 5;
void setup()
Serial.begin(9600);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(EN1, OUTPUT);
pinMode(EN2, OUTPUT);
>
void loop()
if (Serial.available())
val = Serial.read();
// Задаём движение вперёд
if (val == ‘W’) // При нажатии клавиши «W»
// Выводы конфигурируются согласно работе Motor Shield’а
// Моторы крутятся вперед
digitalWrite(EN1, HIGH);
digitalWrite(EN2, HIGH);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
>
// Задаём движение назад
if ( val == ‘S’)
digitalWrite(EN1, HIGH);
digitalWrite(EN2, HIGH);
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
>
// Задаём движение вправо
if ( val == ‘D’)
digitalWrite(EN1, HIGH);
digitalWrite(EN2, HIGH);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
>
// Задаём движение влево
if ( val == ‘A’)
digitalWrite(EN1, HIGH);
digitalWrite(EN2, HIGH);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
>
// Стоп режим
// При отпускании клавиш в программе в порт шлется «T»
if ( val == ‘T’) // При нажатии клавиши «T»
// Выводы ENABLE притянуты к минусу, моторы не работают
digitalWrite(EN1, LOW);
digitalWrite(EN2, LOW);
>
>
>
Итак, вот такая у меня получилась машинка:
Те, кому нравится дизайн в приложениях, могут немного поменять. Подробно описывать как это делать не буду, там не сложно самому разобраться. Скажу лишь, что для этого в основном нужно использовать .png файлы, вместо .jpeg, которые не поддерживают прозрачный фон. Например, сделать такой дизайн за полчаса или час сможет любой неподготовленный человек:
P.S. Для тех, кто не сталкивался с разработкой приложений в App Inventor 2, я сделал более подробный гайд по разработке этого приложения (для просмотра нужно перейти на ютуб).
P.P.S. Сборник из более 100 обучающих материалов по ардуино для начинающих и профи тут.
Онлайн курс по ардуино на гиктаймс здесь.
UPD 1.02.2017: выложил приложение на play market.
Аналогичные проекты с другими шилдами здесь.