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