Введение:
В этом уроке мы дополним робота «Малыш» модулем Bluetooth. Управление направлением и скоростью движения робота будет осуществляться с помощью приложения, установленного на телефон.
Bluetooth модуль телефона будет выполнять роль мастера, а Bluetooth модуль робота - роль ведомого. Сопряжение мастера и ведомого достаточно выполнить только один раз. В дальнейшем, при подаче питания на робота и включении Bluetooth модуля телефона, устройства будут соединяться самостоятельно и всё, что нам будет необходимо сделать, это соединиться с роботом в приложении на телефоне.
Подробно об управлении роботом и сопряжении Bluetooth модулей рассказано ниже, в разделе «Управление».
Видео:
Нам понадобится:
- Робот «Малыш» x1 шт.
- Trema-модуль Bluetooth HC-05 x1 шт.
Для реализации проекта нам необходимо установить библиотеки:
- iarduino_Bluetooth_HC05 - для работы с Trema Bluetooth модулем HC-05.
- Библиотеки SoftwareSerial входит в базовый набор Arduino IDE и не требует установки.
О том, как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Схема подключения робота «Малыш»:
Соберём механическую и электрическую части, как это описано в проектах № 1-8 в книге "Набор "Малыш"". Далее, на верхнюю стенку установим Bluetooth HC-05; модуль подключается к шине UART (в примере используется программная шина UART).
| Bluetooth | Motor Shield | |
|---|---|---|
| Bluetooth HC-05 | вывод RX | цифровой вывод D10 |
| вывод TX | цифровой вывод D9 | |
| вывод K (Key) | цифровой вывод D13 | |
| вывод V (Vcc) | любой вывод 5V на красной колодке | |
| вывод G (GND) | любой вывод GND на чёрной колодке | |
Воспользуемся схемой сборки из проекта №9 книги "Набор "Малыш"", но, вместо Trema-модуля ИК-приёмник, установим в корпус Trema-модуль Bluetooth (подключается к выводам D13, D9 и D10).

Код программы для «Малыша»:
#include <SoftwareSerial.h> // Подключаем библиотеку SoftwareSerial для общения с модулем по программной шине UART
#include <iarduino_Bluetooth_HC05.h> // Подключаем библиотеку iarduino_Bluetooth_HC05 для работы с Trema Bluetooth модулем HC-05
SoftwareSerial softSerial(9, 10); // Создаём объект softSerial указывая выводы RX, TX (можно указывать любые выводы Arduino UNO). Вывод 2 Arduino подключается к выводу TX модуля, вывод 3 Arduino подключается к выводу RX модуля
iarduino_Bluetooth_HC05 hc05(13); // Создаём объект hc05 указывая любой вывод Arduino, который подключается к выводу K модуля
//
uint8_t pinShield_H2 = 4; // Вывод, подключенный к драйверу, для задания направления вращения левым мотором
uint8_t pinShield_E2 = 5; // Вывод ШИМ, подключенный к драйверу, для задания скорости левого мотора
uint8_t pinShield_E1 = 6; // Вывод ШИМ, подключенный к драйверу, для задания скорости правого мотора
uint8_t pinShield_H1 = 7; // Вывод, подключенный к драйверу, для задания направления вращения правым мотором
uint8_t pinLED_RED = 12; // Вывод с красным светодиодом
uint8_t pinLED_BLUE = 11; // Вывод с синим светодиодом
uint16_t time_period = 200; // Частота мигания светодиодов (в миллисекундах)
uint8_t valSpeed = 255; // Максимальная скорость ШИМ (число от 0 до 255)
bool arrRoute[2] = {1, 1}; // Направление движения для каждого мотора ([0]- правый мотор, [1] - левый мотор)
uint16_t arrSpeed[2]; // Скорость для каждого мотора ([0]- правый мотор, [1] - левый мотор)
uint32_t tmrLED; // Время последнего включения светодиодов
uint32_t flgTime; // Флаг для задания времени принятия пакетов от Bluetooth телефона
uint8_t flg; // Флаг кнопок
uint32_t tmrWait; // Время до начала сопряжения с новыми устройствами
bool flg_LED; // Флаг включения светодиодов
// </iarduino_bluetooth_hc05.h></softwareserial.h>
void setup() { //
// BLUETOOTH МОДУЛЬ //
Serial.begin (9600); // Инициируем передачу данных по аппаратной шине UART для вывода результата в монитор последовательного порта
Serial.print ("begin: "); // Выводим текст "begin: " в монитор последовательного порта
if (hc05.begin(softSerial)) {Serial.println("Ok");} // Инициируем работу с Trema модулем hc05, указывая объект softSerial через который осуществляется связь по шине UART
else {Serial.println("Error");} // Если работа с модулем не инициирована, то выводим сообщение об ошибке
tmrWait = millis(); // Устанавливаем таймер ожидания сопряжения
while (!hc05.checkConnect() && millis()<tmrWait+60000) {;} // Ждём в течении 60 секунд сопряжения с последним устройством из памяти
if (millis()<tmrWait+60000) {Serial.println("Connect with last ADR");} // Если сопряжение произошло, то выдаём в монитор порта сообщение об этом
else { // Если сопряжение не произошло, то
if (hc05.createSlave("BT_CAR", "1234")) // Создаем ведомую роль модулю, указывая его имя и pin-код (в примере имя = "BT_CAR", pin-код = "1234")
{Serial.println("Slave create");} // Если ведомая роль была создана, выводим сообщение об успехе в монитор порта,
else {Serial.println("Slave not create");} // а если не была создана - выводим сообщение об ошибке в монитор порта.
} //
// МОТОРЫ //
pinMode(pinShield_H2, OUTPUT); // Конфигурируем вывод pinShield_H2 как выход (направление вращения левого мотора)
pinMode(pinShield_E2, OUTPUT); // Конфигурируем вывод pinShield_E2 как выход (скорость вращения левого мотора, ШИМ)
pinMode(pinShield_E1, OUTPUT); // Конфигурируем вывод pinShield_E1 как выход (скорость вращения правого мотора, ШИМ)
pinMode(pinShield_H1, OUTPUT); // Конфигурируем вывод pinShield_H1 как выход (направление вращения правого мотора)
// СВЕТОДИОДЫ //
pinMode(pinLED_RED,OUTPUT); // Конфигурируем вывод pinLED_RED как выход
pinMode(pinLED_BLUE,OUTPUT); // Конфигурируем вывод pinLED_BLUE как выход
tmrLED = millis(); // Устанавливаем таймер светодиодов равным millis()
flg_LED = 0; // Сбрасываем флаг светодиодов
} //
void loop() { //
if (softSerial.available()) { // Если есть принятые данные, то ...
String str; // Создаём строку str
while (softSerial.available()) { // Выполняем цикл пока есть что читать ...
str += char(softSerial.read()); // Читаем очередной принятый символ из UART в строку str
delay(5); // Задержка на 5 мс на случай медленного приёма
} // Цикл завершён, значит читать больше нечего
// КНОПКИ ДВИЖЕНИЯ //
// Флаг времени Флаг кнопки //
if (str == "II") { flgTime = millis(); flg = 1; } // Кнопка "стрелка вверх-влево"
if (str == "FF") { flgTime = millis(); flg = 2; } // Кнопка "стрелка вверх"
if (str == "GG") { flgTime = millis(); flg = 3; } // Кнопка "стрелка вверх-вправо"
if (str == "RR") { flgTime = millis(); flg = 4; } // Кнопка "стрелка влево"
if (str == "SS") { flgTime = millis(); flg = 5; } // СТОП
if (str == "LL") { flgTime = millis(); flg = 6; } // Кнопка "стрелка вправо"
if (str == "JJ") { flgTime = millis(); flg = 7; } // Кнопка "стрелка вниз-влево"
if (str == "BB") { flgTime = millis(); flg = 8; } // Кнопка "стрелка вниз"
if (str == "HH") { flgTime = millis(); flg = 9; } // Кнопка "стрелка вниз-вправо"
// КНОПКИ ДОПОЛНИТЕЛЬНЫХ ФУНКЦИЙ //
// Если кнопка нажата меняем флаг //
if (str == "SWS" || str == "SwS") {flg_LED = !flg_LED;} // Кнопка включения светодиодов
if (str == "S0S") {flg = 10; } // Ползунок скорости в положении 0
if (str == "S1S") {flg = 11; } // Ползунок скорости в положении 1
if (str == "S2S") {flg = 12; } // Ползунок скорости в положении 2
if (str == "S3S") {flg = 13; } // Ползунок скорости в положении 3
if (str == "S4S") {flg = 14; } // Ползунок скорости в положении 4
if (str == "S5S") {flg = 15; } // Ползунок скорости в положении 5
if (str == "S6S") {flg = 16; } // Ползунок скорости в положении 6
if (str == "S7S") {flg = 17; } // Ползунок скорости в положении 7
if (str == "S8S") {flg = 18; } // Ползунок скорости в положении 8
if (str == "S9S") {flg = 19; } // Ползунок скорости в положении 9
if (str == "SqS") {flg = 20; } // Ползунок скорости в положении 10
// ======================================================================================================================================================
switch (flg) {//Направление левого мотора Направление правого мотора Скорость левого мотора Скорость правого мотора
case 1: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = (valSpeed / 2); arrSpeed[0] = valSpeed; break; // С-З
case 2: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = valSpeed; arrSpeed[0] = valSpeed; break; // С
case 3: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = valSpeed; arrSpeed[0] = (valSpeed / 2); break; // С-В
case 4: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = 0; arrSpeed[0] = valSpeed; break; // З
case 5: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = 0; arrSpeed[0] = 0; break; // Стоп
case 6: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = valSpeed; arrSpeed[0] = 0; break; // В
case 7: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = (valSpeed / 2); arrSpeed[0] = valSpeed; break; // Ю-З
case 8: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = valSpeed; arrSpeed[0] = valSpeed; break; // Ю
case 9: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = valSpeed; arrSpeed[0] = (valSpeed / 2); break; // Ю-В
} //
} // =======================================================================================================================================================
if (flg == 10){valSpeed = 5;} // 0 режим скорости
else if(flg == 11){valSpeed = 30;} // 1 режим скорости
else if(flg == 12){valSpeed = 55;} // 2 режим скорости
else if(flg == 13){valSpeed = 80;} // 3 режим скорости
else if(flg == 14){valSpeed = 105;} // 4 режим скорости
else if(flg == 15){valSpeed = 130;} // 5 режим скорости
else if(flg == 16){valSpeed = 155;} // 6 режим скорости
else if(flg == 17){valSpeed = 180;} // 7 режим скорости
else if(flg == 18){valSpeed = 205;} // 8 режим скорости
else if(flg == 19){valSpeed = 230;} // 9 режим скорости
else if(flg == 20){valSpeed = 255;} // 10 режим скорости
//
if (flg_LED) { // Если флаг установлен (была нажата кнопка включения фары)
if (millis() - tmrLED > time_period) { // мигаем светодиодами с заданной частотой
tmrLED = millis(); // сохраняем время
digitalWrite(pinLED_RED, digitalRead(pinLED_BLUE)); // управляем питанием красного светодиода
digitalWrite(pinLED_BLUE, !digitalRead(pinLED_BLUE)); // управляем питанием синего светодиода
} //
} else { // если флаг сброшен, то
digitalWrite(pinLED_RED, LOW); // гасим светодиоды
digitalWrite(pinLED_BLUE, LOW); //
} //
if (flgTime > millis()) { // Если millis() переполнен, то
flgTime = 0; // сбрасываем флаг в ноль
} //
// ПОДАЧА ЗНАЧЕНИЙ СКОРОСТИ И НАПРАВЛЕНИЯ ВРАЩЕНИЯ НА ВЫВОДЫ //
if (flgTime > (millis() - 500)) { // Если сигналы с телефона приходят (в течении 50 мс)
digitalWrite(pinShield_H2, arrRoute[1]); // тогда задаем направление вращения правого мотора
digitalWrite(pinShield_H1, arrRoute[0]); // и левого мотора
analogWrite(pinShield_E2, arrSpeed[1]); // Задаём скорость вращения для правого мотора
analogWrite(pinShield_E1, arrSpeed[0]); // и для левого мотора
} else { // Если пакеты не приходят
analogWrite(pinShield_E2, 0); // Останавливаем работу моторов
analogWrite(pinShield_E1, 0); //
} //
} //
В данном коде управление роботом осуществляется в три основных этапа: получение данных с телефона; изменение значений переменных arrSpeed, arrRoute; подача питания на моторы и задание направления их вращения. Так же в коде присутствуют дополнительные блоки: включение/выключение светодиодов; изменение скорости вращения колёс; вход в режим сопряжения.
- Получение данных с пульта:
- Данный блок начинается с оператора
if, в условии которого написаноsoftSerial.available(). Это условие будет верно, если в последовательный порт будут приходить данные с телефона, в противном случае условие будет ложно; - Далее следует еще один оператор
while, условием которого опять являетсяsoftSerial.available(). Если условие верно, то значение, поступившее в последовательный порт, будет записано в переменнуюstr; задержка в 5 миллисекунд сделана для того, чтобы при низкой скорости передачи Arduino успел полностью прочитать значение из последовательного порта в переменнуюstr;
- Данный блок начинается с оператора
- Изменение значений переменных arrSpeed, arrRoute:
- Данный блок начинается с оператора
if, в условии которого написаноstr == XX. В зависимости от значенияXX, которое принимает переменнаяstr(одно из 9 для основных функций), сбрасываетсяflgTime- таймер начала выполнения функции, а так же устанавливается значение флагаflg(от 1 до 9); - Далее следует конструкция
switch...case, в которой операторswitchсравнивает значение флагаflgс операторомcaseи, в зависимости от значения флагаflg, выполняет код, где задаётся, на какой мотор будет подано питание (переменнаяarrSpeed) и с каким направлением вращения ( переменнаяarrRoute);
- Данный блок начинается с оператора
- Подача питания на моторы и задание направления их вращения:
- Данный блок начинается с оператора
if, в условии которого написаноflgTime > (millis() - 50). Это условие будет верно в течении 50 миллисекунд после начала приёма сигнала от телефона и установит на выводах Arduino значения переменныхarrSpeedиarrRoute. Если же сигнала в течении 50 миллисекунд не поступит, то операторelseсбросит значение скорости в 0 и робот остановится;
- Данный блок начинается с оператора
- Включение/выключение светодиодов:
- Данный блок включает в себя 2 части: получение сигнала с телефона и изменение флага
flg_LED; включение/выключение светодиодов; - Первая часть начинается с оператора
if, в условии которого написано( str == "SWS" || str == "SwS"). Условие будет верно, если значение переменнойstrбудет равноSWSИЛИSwS, что приведёт к установке флагаflg_LEDв противоположное от нынешнего значение; - Вторая часть начинается с оператора
if, в условии которого написано(flg_LED). Условие будет верно, если значение флагаflg_LEDбудетtrue, что приведёт к включению светодиодов. Если же значение флагаflg_LEDбудетfalse, то светодиоды погаснут.
- Данный блок включает в себя 2 части: получение сигнала с телефона и изменение флага
- Изменение скорости вращения колёс:
- Данный бок включает в себя 2 части: получение сигнала с телефона и изменение флага
flg; изменение значения переменнойvalSpeed; - Первая часть начинается с оператора
if, в условии которого написаноstr == XX. В зависимости от значенияXX, которое принимает переменнаяstr(одно из 11 для дополнительных функций), устанавливается значение флагаflg(от 10 до 20); - Вторая часть начинается с оператора
if, в условии которого написаноflg == XX. В зависимости от значенияXX, которое принимает переменнаяflg(одно из 11 для дополнительных функций), устанавливается значение переменнойvalSpeed(от 5 до 255);
- Данный бок включает в себя 2 части: получение сигнала с телефона и изменение флага
- Вход в режим сопряжения (выполняется при подаче питания на робота):
- Данный блок находится в коде
void setup()и начинается с оператораif, в условии которого написаноhc05.begin(softSerial). Это условие будет верно, если произошла успешная инициализация с Bluetooth модулем по шине UART, о чём будет выведено сообщение в монитор последовательного порта; - Далее происходит сброс таймера
tmrWaitи идёт проверка условия!hc05.checkConnect() && millis()<tmrWait+60000в операторе циклаwhile. До тех пор, пока не произойдёт сопряжения Bluetooth модуля робота и телефона И не истечёт минута(60 сек), модуль будет выполнять пустой цикл. - После цика
whileследует операторif, в условии которого написаноmillis()<tmrWait+60000. Условие будет верно, если одно из условие!hc05.checkConnect()цикла while изменится на противоположное и произойдёт это раньше, чем через 60 секунд от подачи питания на робота. Тогда в монитор последовательного порта будет выведено сообщение о том, что сопряжение произошло с ранее созданной парой из памяти устройства. - Если по истечении минуты не произошло сопряжение ранее созданной пары, то далее следует оператор
else, который выполняет вызов функцииcreateSlave("BT_CAR", "1234")объектаhc05, которая назначает Bluetooth модулю робота роль ведомого с именем "BT_CAR" и PIN-кодом "1234", разрывает ранее установленную связь с мастером (если она была) и стирает список ранее созданных пар. После этого модуль начинает ожидать подключения мастера, который правильно укажет имя и PIN-код модуля. Об успешном или, наоборот, неудачном выполнении функции будет выведено сообщение в монитор последовательного порта.
- Данный блок находится в коде
Получение данных и работа с Trema-модулем Bluetooth HC-05 осуществляется через функции и методы объекта hc05 библиотеки iarduino_Bluetooth_HC05, с подробным описанием которых можно ознакомиться на странице Wiki - Trema-модуль bluetooth HC-05.
Подключение:
Настройка Bluetooth-модуля телефона:
Установка приложения на телефон
![]() Войдите в меню магазина приложений Google Play Market; |
![]() |
![]() Нажмите на строку поиска и наберите Arduino Bluetooth RC Car и выберите первую появившуюся стоку с именем приложения; |
![]() В окне установки приложения нажмите кнопку Установить; |
![]() В появившемся окне нажмите кнопку Подтвердить установку; |
![]() После успешной установки иконка программы появится у вас на рабочем столе телефона; |
![]() Для запуска приложения достаточно один раз нажать кнопку Открыть или выбрать иконку приложения на рабочем столе; |
Настройка приложения Bluetooth RC Controller на телефоне:
Интерфейс программы на телефоне:

| Номер | Функция |
|---|---|
| 1 | Индикация сопряжения с роботом |
| 2 | Блок клавиш "движение вперёд-назад" |
| 3 | Блок клавиш "движение вправо-влево" |
| 4 | Индикация нажатия клавиш движения |
| 5 | Ползунок регулировки скорости робота |
| 6 | Клавиша включения/выключения светодиодов |
| 7 | Клавиша входа в меню настроек |
Управление:
Сразу после сборки, загрузки скетча и подачи питания на «Малыша» он не будет реагировать на команды с телефона, так как Bluetooth модулям требуется сопряжение (создание пары). Сопряжение достаточно выполнить только один раз, bluetooth модули запомнят созданную пару в своей энергонезависимой памяти и будут пытаться соединится друг с другом при каждой последующей подаче питания.
- Подключите питание робота (если оно не было подано). После подачи питания Bluetooth модуль робота будет в течении минуты (60 сек) ждать сопряжения с последним удачно подключенным устройством, а если сопряжения не произойдёт, то модуль назначит себе роль ведомого с именем «BT_CAR» и PIN-кодом «1234» и будет ожидать подключение мастера.
- Если Вы отключите телефон, то робот сразу остановится.
Управление роботом с телефона выполняется следующим образом:
- Нажимая на клавиши "вперёд/назад" (2) и "вправо/влево"(3) вы можете выбрать одно из 9 направлений движения, указанных стрелками в центре(4).
- Нажимая на клавишу (6) вы можете включить или выключить светодиоды, имитирующие спецсигнал полицейской машины;
- Зажав кнопку (5) и двигая её пальцем вправо или влево, вы можете регулировать скорость движения робота;

















Обсуждение