Машинка на Arduino, управляемая Android-устройством по Bluetooth, — полный цикл (часть 1) +47


Введение


Подробная история того, как из трех двигателей была собрана машина на Arduino, управляемая Android-устройством по Bluetooth. В нескольких десятках абзацев постараюсь максимально пошагово изложить, куда подключить каждый из проводов, как написать фирменное приложение и на каких детских граблях пришлось попрыгать больше недели.

Немного об уровне, авторе и предостережения


Я, автор, пацан 16-17 лет с подмосковной деревни, специализируюсь на написании android-приложений (а там сложнее что-то сжечь), поэтому ответственность за оптимальный подход к решению задач с себя снимаю.

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

Задача


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

Понадобится


  1. Arduino
  2. Motor Shield (в моем случае две)
  3. Bluetooth
  4. Android
  5. Провода обычные

Основа конструкции


За основу была взята машина Lego Outdoor Challenger (в реальности выглядит менее пафосно). Все, что от нее осталось: корпус (все элементы украшения сняты) и три двигателя.
image
У машинки была своя плата, но одна из задач подразумевала универсальность: это сделал я, это смогут повторить другие. Мозги вынул, поставил 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.h> \\подключение библиотеки
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, .

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (28):

  1. Rapasantra
    /#19144857

    Моя мечта — с помощью ардуино сделать автономный мини катер, который совершит кругосветное путешествие. Это было бы действительно круто, особенно, если катер был бы с камерой, попал в крупный шторм и выжил после этого. У ардуино есть модуль GPS для навигации в любой точке земного шара. Движение корабля можно обеспечить с помощью электродвигателя и солнечных панелей. А для гуру инженерии можно сделать парусник с автономным управлением жёсткого паруса. Как бы там ни было, разработка и тесты такого корабля были бы невероятным приключением

    • DolgopolovDenis
      /#19145249

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

    • vasimv
      /#19145289 / +1

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

    • Andrus_Trash
      /#19145593 / +1

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

    • r00tGER
      /#19149779

      попал в крупный шторм и выжил после этого

      Так все же проводки из бредборда повываливаются…

    • shadovv76
      /#19151735

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

  2. kbaa
    /#19144869

    Собрался наконец-то я попробовать сделать управление ардуиной с андроида. Вышел покурить перед тем как приступить к поискам решения, открыл Хабр — ух ты, статья как на заказ. А самое интересное оказалось оставленным на 2ю часть :(
    Ладно, все равно мне надо через usb их подружить, а автору зачёт. Пока читал, вспомнил как в свои лет 14 из олдскульного конструктора (который из перфорированных алюминиевых деталей), всяких останков от игрушечных машинок, моторчиков и электротехнической мелочевки, стыренной у отца, собирал гусеничный вездеход. Оно ездило, поворачивало и светило фарами, главным недостатком было проводное управление и необходимость собирать удлиннители по всей квартире, чтобы устроить тест-драйв во дворе в песочнице (питалось это от БП на 9В). Очень хотелось приделать к этому пепелацу радиоуправление, но на это моих знаний уже не хватало. Завидую я, в общем, нынешним подросткам

  3. Amomum
    /#19145089

    Вы молодец, продолжайте в том же духе!

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

    Интересно, осознавали ли вы, что изобрели код Грея? :)
    Он используется во «взрослых» энкодерах с той же целью, что и у вас — чтобы на границе двух состояний менялся только один бит и значение не скакало слишком сильно.

    • alexhott
      /#19145119

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

    • iliasam
      /#19145169

      Судя по надписи «Lego» на плате энкодера, он уже был в оригинальной машинке.

    • DolgopolovDenis
      /#19145255

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

  4. ioppoi
    /#19146607

    спасибо

  5. Octember
    /#19146609

    Вы большой молодец! Сам ранее занимался подобной задачей. По опыту работы с arduino — наименования пинов лучше выносить в константы, хорошее видео на эту тему есть тут:
    www.youtube.com/watch?v=YLv9jyzebPc
    Возможно, вместо использования двух MS, стоит подумать над системой охлаждения, например установить радиатор и кулер (и то и другое можно вытащить из старого компьютера).
    Посмотрите также на плату WemosD1, у нее есть встроенный модуль esp8266, что позволит управлять машинкой при помощи wi-fi сети, это быстрее, чем через bluetooth.
    Напишите, пожалуйста, характеристики того, от чего вы ее питаете. Когда сами делали что-то подобное, это всегда было большой проблемой

    • DolgopolovDenis
      /#19146615

      да, возможно константы действительно правильней, но нет у меня такой привычки после андроида, буду вырабатывать
      с радиатором проблема — некуда крепить, к MS на болты не посадишь, двухсторонний скотч весь эффект теплоотдачи испортит. а кулер здоровый, только если поверх двух плат… но можете меня переубедить, буду рад. (а две платы все-равно пришлось бы ставить, так как нужно управлять тремя двигателями)
      платы esp8266 под рукой не было на начало проекта, да и сейчас нет, но буду покупать, wi-fi действительно лучше
      а питал от батареи квадракоптера) 7,4В и 1200 mA, ездила больше 10 минут

      • iig
        /#19147099

        Esp так себе решение. С включенным wifi очень прожорливая, к питанию требовательна.

      • GunFerzs
        /#19147251

        Извиняюсь. Но почему у Вас после андроида нет привычки выносить системную информацию в константы? Вы же не хардкодаете ее, или ещё хуже не заносите в ресурсы? Системной информацией я считаю как раз название пинов, или например ключи extras, ключи sharedpreferences, адреса сервер апи и т.д.

        • DolgopolovDenis
          /#19147255

          да нет, конечно вы правы, просто мне непривычна конструкция с define

      • geher
        /#19147743 / +1

        с радиатором проблема — некуда крепить, к MS на болты не посадишь, двухсторонний скотч весь эффект теплоотдачи испортит.

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

        • DolgopolovDenis
          /#19147875

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

          • geher
            /#19147889

            Только термоскотч разный бывает. Нужен именно теплопроводящий.

      • Walt_Brann
        /#19152793

        Вместо двухстороннего скотча можно использовать КПТД-2.

    • cepokko
      /#19152797

      Делал на esp8266 управление машинкой со смартфона через Blynk. Увы антенна на платке очень мала и дальность страдает, через стену от роутера уже лаги идут или неконтролируемое «залипание» газа например. Только если с внешней антенной ставить.
      Для компакнтности вместо большого шилда я использовал драйвер L298N. Он с охлаждением уже, два движка от игрушки хорошо тянул.

  6. Tyusha
    /#19147621

    Ничего не пониманию в Ардуино, но как неплохо для старшеклассника написан текст.

  7. remzalp
    /#19149887

    По моторшилдам немного удивляет. Судя по картинке это от искры (амперка), каждый шилд стоит под тысячу рублей. Итого стоимость решения 2000 рублей.


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


    Итак, альтернативы:


    1. Реле / реле шилд
      Здесь нет шаговых двигателей, сверхвысокая точность и быстрое переключение не важны — механическое реле уделает всех по эффективности (да, механический износ контактов), но при этом ток 15А без заметного нагрева.
      https://www.chipdip.ru/product/tru-5vdc-sb-cl
      Наработка на отказ 10 миллионов включений.


    2. Полевой транзистор, тот же mosfet шилд от тройки — 30А ток.
      или сравнительно слабый транзистор (17А), рядом есть и дороже и мощнее:
      https://www.chipdip.ru/product/irf530n


    3. Немного рассыпухи, взять маньячизма ради IGBT транзистор, которому потребуется за компанию только резистор, причем защитный диод там уже присутствует. Ток 20А
      https://www.chipdip.ru/product/stgp10nc60kd



    Плюсы решения на рассыпухе — можно спаять на плате (макетной или ЛУТ методом изготовленной) что-то в форм-факторе шилда под ардуину, который легко ставится на ардуину, но при этом уже можно управлять компоновкой деталей, так что воткнуть транзисторы с радиаторами будет легче, чем в бутерброде из двух этажей.


    Еще смущает, что судя по всему реверс не реализован.


    А вот как плохой программист на андроиде (0 часов опыт), было бы интересно узнать — какие есть бесплатные методы собрать небольшое кнопочное приложение для управления по Bluetooth / Wi-Fi, тут у меня провал в знаниях.

    • DolgopolovDenis
      /#19152813

      Очень интересно, спасибо за информацию, буду читать! (чтобы не совсем казаться транжирой, скажу в оправдание, что две MS уже были, покупать их не пришлось)
      а про андроид — есть готовые bluetooth и wi-fi терминалы, смотрите в Google Play. Хотя набросать свое приложение совсем не сложно, если есть хотя бы начальные знания. Если же нет, то скоро выйдет вторая часть, в которой и весь исходный код выложу (модифицируй не хочу), и подробно опишу каждую строчку

      • remzalp
        /#19152833

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


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


        А сам я веду кружок школьников-ардуинолюбителей, в качестве основного контроллера поделие на базе esp8266, поэтому вайфай есть, андроид у каждого в кармане, а вот знаний немного не хватает — как обзывается такой класс приложений?

  8. blacksoul000
    /#19152803

    вместо «бутерброда» из двух шилдов можно использовать один moto monster shield(можно найти на алиэкспрессе). Бывают на 1 канал и на 2. до 30А на каждый, стоит недорого, а заодно и снизит потерю мощности от L293D за счет гораздо меньшего внутреннего сопротивления.