Радиоуправление на ESP32: учебный стенд с ESP‑NOW
Сначала проведите три опыта в живой модели, затем соберите безопасный стенд на двух ESP32. В конце вы сможете объяснить, когда теряются отдельные пакеты, когда срабатывает failsafe и почему для FPV-дрона обычно выбирают ExpressLRS.
Проведите три опыта
Нажимайте кнопки по порядку. У каждого опыта есть одно действие, один наблюдаемый результат и короткое объяснение.
ESP‑NOW LINK LAB
Это вероятностная учебная модель, а не калькулятор дальности. Помехи и экранирование показаны условной шкалой 0–100.
seq 0
rx 0
0 / 250 мс
Что означают эти показатели?
seq. Failsafe зависит от возраста пакета, а не от одного значения LQ.Изменить условия вручную
Показать график LQ
График показывает LQ во времени. После смены условия подождите 1–2 секунды: окно из 100 пакетов обновляется постепенно.
Команда следует за стиком → при помехах появляются пропуски → после выключения TX возраст пакета доходит до тайм-аута и выход становится −1000. В модели связь восстанавливается автоматически; на реальном аппарате возврат управления должен требовать осознанного повторного разрешения.
Что именно мы строим
ESP32 — микроконтроллер с радиочастью. ESP‑NOW — способ передавать короткие кадры между ESP без точки доступа. Формат команд, подтверждение, телеметрию и безопасность вы проектируете сами.
Две платы ESP32 DevKit, два USB-кабеля, джойстик или потенциометр, светодиод с резистором и стабильное питание. Мотор, ESC и пропеллеры на этом этапе не нужны.
Минимальная разводка стенда
Номера выводов ниже подходят как понятный пример для классического ESP32 DevKit. На ESP32‑C3/S3 и других платах сначала сверяйте pinout своей конкретной платы.
Передатчик
- Ось X джойстика → GPIO34 (ADC1)
- Ось Y → GPIO35 (ADC1)
- Кнопка ARM/режим → GPIO32 с INPUT_PULLUP
- VCC джойстика → 3,3 В, GND → GND
ADC2 на классическом ESP32 конфликтует с активным Wi‑Fi-драйвером. Для стиков проще выбирать ADC1.
Приёмник
- Тестовый LED → безопасный GPIO через резистор
- Сигнал сервопривода → GPIO18
- Питание сервопривода → отдельный 5 В BEC
- Земля BEC и ESP32 → общая
Не питайте сервопривод от вывода 3,3 В ESP32. Просадка питания даст перезагрузку, которая выглядит как «плохая радиосвязь».
Как узнать MAC-адрес приёмника
Сначала прошейте плату-приёмник этим коротким скетчем, откройте Serial Monitor на 115200 бод и перепишите адрес интерфейса STA. Именно его затем добавляют как peer на передатчике.
#include <WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
delay(100);
Serial.println(WiFi.macAddress());
}
void loop() {}
Не перепутайте адреса: у STA и SoftAP одной платы разные MAC. В этой лаборатории обе платы работают в режиме STA и на одном выбранном Wi‑Fi-канале.
Если у вас ESP32-C3, S3 или другая DevKit-плата
Не переносите номера GPIO вслепую. Сверьте pinout именно своей платы: наличие ADC1, загрузочные выводы, допустимый ток и встроенный LED различаются. Радиологика урока остаётся той же, меняется разводка.
В Serial виден MAC приёмника, движение стика меняет показания ADC, а тестовый LED приёмника включается локальной командой. Только после этого добавляйте радиообмен.
Команда должна быть проверяемой
Не отправляйте «просто четыре числа». Версия формата, последовательный номер и флаги помогают отличить новый пакет от старого, увидеть пропуски и безопасно обновлять прошивку.
Минимальная структура пакета
Фиксированный размер упрощает проверку. Значения каналов удобно нормировать в диапазон −1000…1000, а throttle отдельно переводить в безопасный минимум при failsafe.
struct __attribute__((packed)) ControlPacket {
uint16_t magic; // например 0xE532
uint8_t version; // версия формата
uint8_t flags; // arm, mode, кнопки
uint32_t seq; // растёт на каждый пакет
int16_t ch[8]; // -1000 ... 1000
};
static_assert(sizeof(ControlPacket) == 24, "Packet size changed");
Что делать в callback приёмника
Callback ESP‑NOW выполняется в задаче Wi‑Fi. В нём быстро проверьте адрес источника, длину, magic/version и скопируйте данные в очередь или защищённый буфер. Управление PWM, журналирование и тяжёлые вычисления перенесите в обычный loop/task.
onReceive(info, data, len):
if source MAC is not allowed: return
if len != sizeof(ControlPacket): return
copy data to local packet
if magic/version invalid: return
if seq is old or duplicate: return
queue packet for control task
Failsafe выполняется отдельно от приёма
Главное правило: отсутствие callback тоже является событием. Поэтому таймер проверяет возраст последнего валидного пакета независимо от радиообработчика.
if (millis() - lastValidPacketMs > FAILSAFE_MS) {
output.throttle = -1000;
output.roll = output.pitch = output.yaw = 0;
output.armed = false;
linkState = FAILSAFE;
}
seq.Как превратить официальный пример в этот стенд
- Откройте актуальный пример ESP‑NOW из установленного пакета Arduino‑ESP32 и сначала добейтесь обмена тестовой строкой.
- Перейдите с broadcast на unicast и добавьте MAC приёмника как peer.
- Замените строку структурой
ControlPacket; одинаковое объявление должно быть на обеих платах. - На приёмнике принимайте пакет в callback, но применяйте его и проверяйте failsafe в обычном
loop()или отдельной задаче. - Сначала выводите
seq, возраст пакета и состояние в Serial. LED подключайте после того, как проверка длины, версии и источника уже работает.
Так меньше риск одновременно отлаживать Wi‑Fi-канал, структуру данных, ADC и выход. Актуальные сигнатуры API берите из официального примера Arduino‑ESP32: они меняются между поколениями пакета плат.
Верный новый seq обновляет выход; дубликат, неверная длина, другая версия и чужой MAC игнорируются; независимый таймер всё равно переводит выход в безопасное состояние.
ESP32/ESP‑NOW против ExpressLRS
Сравнивать «ESP32 и ELRS» напрямую не совсем корректно: первое — платформа, второе — законченная радиосистема. Но для выбора канала управления такое сравнение полезно.
| Критерий | ESP32 + ESP‑NOW | ExpressLRS |
|---|---|---|
| Что это | Собственный проект поверх протокола Espressif | Специализированная RC-система TX/RX с готовой прошивкой |
| Радиоканал | Обычно 2,4 ГГц, один заданный Wi‑Fi-канал | 2,4 ГГц, 868/915 МГц и совместимые диапазоны; частотные перестройки по протоколу |
| Пакетная частота | Задаёте сами; реальный джиттер зависит от кода и радиоэфира | Стандартизованные режимы с известной частотой пакетов |
| Метрики | Нужно самим считать seq, LQ, ACK, возраст пакета | LQ, RSSI dBm, RF mode и телеметрия уже встроены в рабочий процесс |
| Failsafe | Полностью ваша логика и ваша ответственность | Предусмотрен радиосистемой и интеграцией с FC; всё равно требует проверки |
| Интеграция с FC | Нужно реализовать PWM/UART/CRSF-подобный мост и тщательно испытать | Готовые CRSF/MAVLink/PWM-сценарии в зависимости от оборудования |
| Где уместно | Учебный стенд, робот, наземная платформа, кастомная телеметрия | FPV-дрон, самолёт, дальний и ответственный радиоканал |
| Главный риск | Ложное ощущение готовности после теста «на столе» | Ошибка target, антенны, настройки или монтажа — систему тоже надо проверять |
Если выбираете уже реальный ELRS-приёмник, не ориентируйтесь только на надпись ESP на плате. Начните с матрицы выбора target ELRS: target определяется всей аппаратной схемой, RF-чипом и разводкой, а не названием микроконтроллера.
Шесть наземных проверок
«Пакеты идут» — только начало. Хороший стенд должен предсказуемо ломаться и восстанавливаться.
Через заданный тайм-аут выход обязан перейти в заранее определённое безопасное состояние.
До первого валидного пакета никаких старых или случайных команд на выходе.
Неверный MAC, magic или ключ не должны обновлять каналы.
Счётчик seq выявляет потерянные кадры; старые пакеты не откатывают положение.
Сервопривод двигается под нагрузкой, а ESP32 не перезагружается и не теряет peer.
Решите заранее: выход оживает сразу или ждёт отдельной команды разблокировки.
Если не работает или работает нестабильно
Идите от наблюдаемого симптома. Не меняйте одновременно канал, частоту отправки, питание и структуру пакета.
Передатчик пишет SEND_FAIL
- Проверьте, что обе платы работают в совместимом Wi‑Fi-режиме и на одном канале.
- Сверьте MAC именно нужного интерфейса: STA и SoftAP имеют разные адреса.
- Убедитесь, что peer добавлен после запуска Wi‑Fi и инициализации ESP‑NOW.
- Не отправляйте новый пакет, пока callback предыдущей отправки не вернулся.
SEND_SUCCESS есть, но выход не меняется
MAC-уровень мог подтвердить кадр, но приложение могло отвергнуть его из-за длины, версии, старого seq или другого источника. Добавьте счётчики: received, valid, applied и ACK с последним применённым seq.
Связь резко хуже рядом с роутером или VTX
ESP‑NOW остаётся на выбранном Wi‑Fi-канале. Роутер или VTX 2,4 ГГц могут занимать тот же диапазон напрямую. VTX 5,8 ГГц диапазон не перекрывает, но близкое мощное радио, гармоники, плохая фильтрация или общее шумное питание всё равно способны ухудшить работу сборки. Разнесите антенны и питание, а результат оценивайте по LQ и пропускам, не только по «силе».
Для изучения радиообстановки полезно сравнить подходы из материала о снифферах ELRS, но измерительный стенд не заменяет проверку конкретной сборки.
ESP32 перезагружается при движении серво
Это почти всегда сначала вопрос питания: отдельный BEC, общий GND, достаточный ток, короткие провода и развязка. Смотрите причину сброса в Serial, а не списывайте перезапуск на радиопомеху.
LQ хороший, а управление «дёргается»
Проверьте ADC стиков, фильтрацию, калибровку центра, deadband, частоту обновления PWM и гонки между callback и loop. Высокий LQ говорит только о доле принятых пакетов, а не о качестве всей цепочки управления.
Как продолжить проект
Выберите следующий шаг по задаче, а не по тому, какой чип уже лежит на столе.
Стенд или робот
Оставляйте ESP‑NOW. Добавьте unicast, ключи PMK/LMK, ACK, журнал seq/LQ, watchdog и безопасный выход.
FPV-дрон
Переходите на ELRS и CRSF. Сравните диапазоны 433/900/2400 МГц по задаче, антеннам и разрешённым частотам.
Автопилот и данные
Не смешивайте RC и высокообъёмную телеметрию без расчёта полосы. Для ArduPilot откройте ELRS с QGroundControl и Mission Planner.
Три связанных материала
Официальные источники и важные оговорки
- Arduino‑ESP32: ESP‑NOW API и примеры.
- ESP‑IDF: ESP‑NOW — peer, канал, callback, ACK и ограничения.
- ExpressLRS: Signal Health, LQ, RSSI и чувствительность режимов.
Дальность намеренно не указана одной цифрой: она зависит от платы, антенны, ориентации, высоты, помех, питания, корпуса и выбранного режима. Любой тест на столе нужно повторять в реальных условиях, не создавая риска людям и имуществу.