Руководство · Начальный · 1 hour
Управление роботом по Bluetooth с модулем HC-05
Подключите HC-05 к Arduino, выполните сопряжение с телефоном и создайте безопасный протокол команд, сохраняющий отзывчивость робота при потере связи.
Введение
HC-05 — самый дешёвый способ добавить к роботу беспроводную связь. Это мост последовательной связи Bluetooth: всё, что отправляет телефон, приходит на последовательный порт Arduino как обычные байты, а всё, что Arduino печатает, возвращается на телефон. Ничто в скетче не обязано знать, что существует Bluetooth.
В этой простоте заключается привлекательность, но в ней же и ловушка. Радиосвязь — это не провод: она прерывается, запаздывает и отключается, пока робот ещё движется. Большая часть этого руководства посвящена именно этим различиям.
Подключение и ошибка, которую допускают почти все
Модуль HC-05 питает логику от 3.3 V, хотя плата-расширение принимает 5 V на VCC. Вывод RX не допускает 5 V.
| HC-05 | Arduino Uno / Nano | Примечания |
|---|---|---|
VCC |
5V |
Стабилизатор платы справляется с этим |
GND |
GND |
Общая земля со всем остальным |
TXD |
D10 (программный RX) |
Выход 3.3 V корректно читается входом 5 V как логический уровень HIGH |
RXD |
D11 (программный TX) через делитель |
Прямые 5 V со временем повредят модуль |
EN / KEY |
D9 (необязательно) |
Подайте HIGH при включении для входа в режим AT-команд |
Понизьте сигнал 5 V от Arduino до 3.3 V делителем из двух резисторов: 2 kΩ от вывода Arduino к RXD HC-05 и 3.3 kΩ от этой точки к земле. Это стоит двух компонентов и предотвращает сбой, который действительно невероятно трудно диагностировать: повреждённый таким образом модуль часто продолжает работать наполовину — он сопрягается, передаёт данные и молча игнорирует или портит то, что вы отправляете.
Используйте SoftwareSerial, а не выводы 0 и 1. Аппаратный последовательный порт используется совместно с USB, поэтому модуль, подключённый к нему, конфликтует с монитором последовательного порта и мешает загрузке.
#include <SoftwareSerial.h>
SoftwareSerial bt(10, 11); // RX, TX
void setup() {
Serial.begin(115200); // USB, for debugging
bt.begin(9600); // HC-05 default baud
}
Сопряжение
Включите питание робота, и светодиод (LED) модуля начнёт быстро мигать — это означает «ожидание сопряжения». На телефоне выполните сопряжение с HC-05, используя код 1234 или 0000.
Сопряжение — это не подключение. Связь открывается только тогда, когда приложение на телефоне действительно открывает последовательный порт. Для начала подойдёт любой Bluetooth-терминал; когда соединение установится, светодиод модуля начнёт мигать сдвоенными импульсами.
Проектирование протокола команд
Очевидный первый протокол — один символ на команду, и он работает примерно десять минут:
if (bt.available()) {
char c = bt.read();
if (c == 'F') forward();
else if (c == 'B') back();
else if (c == 'S') stop();
}
У него две проблемы.
Он не задаёт скорость. Каждая команда означает полный газ, поэтому робот либо стоит, либо несётся на полной. Вместо этого передавайте вместе с командой значение: одну букву и число, завершённые переводом строки, что легко разобрать и легко вводить вручную при отладке:
// "F180\n" — forward at 180 of 255
char buffer[16];
if (bt.available()) {
int n = bt.readBytesUntil('\n', buffer, sizeof(buffer) - 1);
buffer[n] = '\0';
char cmd = buffer[0];
int value = atoi(buffer + 1);
...
}
Он предполагает, что сообщение приходит целиком. Ненулевое bt.available() означает, что здесь находятся какие-то байты, а не все. Чтение по одному символу за цикл и немедленное действие приведут к обработке половины команды. Чтение до перевода строки делает разбор надёжным.
Сбой, который действительно важен: потеря связи
Проводной робот останавливается, когда вы отпускаете кнопку. Беспроводной робот продолжает выполнять последнюю команду — а если последней командой было «вперёд на полной скорости» и вы только что вышли из зоны покрытия, робот на полной скорости уезжает под диван.
Каждому беспроводному роботу нужен аварийный тайм-аут. Правило простое: если недавно не пришло ни одной команды, робот должен остановиться.
unsigned long lastCommandAt = 0;
const unsigned long TIMEOUT_MS = 500;
void loop() {
if (readCommand()) lastCommandAt = millis();
// Nothing heard recently? Assume the link is gone.
if (millis() - lastCommandAt > TIMEOUT_MS) stop();
}
Чтобы это помогало, контроллер должен постоянно общаться. Пусть телефон повторяет текущую команду — примерно каждые 100 ms, пока удерживается кнопка, — а не отправляет её один раз при нажатии и один раз при отпускании. Тогда «кнопка отпущена» и «телефон вышел из зоны покрытия» дают одинаковый безопасный результат, и вам не нужно полагаться на сообщение об отпускании, которое может не прийти.
Для этого используйте millis(), а не delay(). delay(200) в цикле — это 200 ms, в течение которых команды не читаются, тайм-аут не проверяется, а робот ничего не слышит.
Режим AT-команд
Чтобы переименовать модуль или изменить скорость передачи, удерживайте EN/KEY на HIGH при включении. Светодиод мигает медленно — примерно раз в две секунды — это показывает, что вы находитесь в режиме команд, а не данных.
AT → OK
AT+NAME=MyRobot → OK
AT+PSWD="4821" → OK
AT+UART=38400,0,0
Команды в режиме AT должны отправляться на скорости 38400 baud независимо от скорости в режиме данных, и большинство прошивок требует одновременно возврат каретки и перевод строки. Если AT не возвращает ничего, почти всегда причина в этом несоответствии.
Повышать скорость передачи данных стоит, если вы передаёте телеметрию, но пока протокол отлаживается, оставьте 9600: более быстрая связь в основном затрудняет обнаружение ошибок кадрирования.
Проверьте перед движением
Три проверки в таком порядке:
- Проверка эха. Пусть Arduino печатает всё, что получает. Если введённая строка возвращается без изменений, подключение и скорость передачи правильные.
- Проверка разбора. Напечатайте разобранную букву команды и значение. Убедитесь, что
F180даётFи180, а неFи1. - Проверка тайм-аута. Отправьте команду движения вперёд, затем закройте приложение или отойдите. Робот должен остановиться за время тайм-аута. Если нет, исправьте это до установки колёс на пол.
Когда связь станет надёжной, тот же протокол команд без изменений переносится в автономного робота: соберите беспроводной слой в проекте робота с управлением с телефона или перейдите к ESP32, который раздаёт страницу управления по Wi-Fi и вообще не требует приложения.
Исследуйте граф
Входит в эти сборки
Проекты и учебные пути, в которые входит это руководство.
Дополнительные материалы