Оглавление:

DuvelBot - Робот для раздачи пива ESP32-CAM: 4 шага (с изображениями)
DuvelBot - Робот для раздачи пива ESP32-CAM: 4 шага (с изображениями)

Видео: DuvelBot - Робот для раздачи пива ESP32-CAM: 4 шага (с изображениями)

Видео: DuvelBot - Робот для раздачи пива ESP32-CAM: 4 шага (с изображениями)
Видео: Трактористы (комедия, реж. Иван Пырьев, 1939 г.) 2024, Июнь
Anonim
DuvelBot - Робот для раздачи пива ESP32-CAM
DuvelBot - Робот для раздачи пива ESP32-CAM

После тяжелого рабочего дня ничто не сравнится с тем, чтобы потягивать любимое пиво на диване. В моем случае это бельгийский светлый эль "Duvel". Однако после почти полного обрушения мы сталкиваемся с очень серьезной проблемой: холодильник, содержащий мой Duvel, находится в 20 футах от упомянутого дивана.

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

Пора выламывать паяльник и клавиатуру…

DuvelBot - это простая в использовании веб-камера для вождения на базе AI-Thinker ESP32-CAM, которой вы можете управлять со своего смартфона, браузера или планшета.

Эту платформу легко адаптировать или расширить для менее употребления алкоголя (например, SpouseSpy, NeighbourWatch, KittyCam…).

Я построил этого робота в основном для того, чтобы немного узнать обо всем, что касается веб-программирования и Интернета вещей, о которых я ничего не знал. Итак, в конце этого руководства дается подробное объяснение того, как это работает.

Многие части этого руководства основаны на прекрасных объяснениях, которые можно найти на сайте Random Nerd Tutorials, так что, пожалуйста, посетите их!

Запасы

Что вам нужно:

Список деталей не высечен на камне, и многие детали можно получить в тоннах разных версий и из разных мест. Больше всего закупал у Али-Экспресс. Как сказал Мачете: импровизировать.

Аппаратное обеспечение:

  • Модуль AI Thinker ESP32-CAM. Вероятно, он мог бы работать с другими модулями ESP32-CAM, но это то, что я использовал
  • Плата драйвера двигателя L298N,
  • Дешевая платформа для 4-х колесной робототехники,
  • Корпус с большой плоской поверхностью, такой как Hammond Electronics 1599KGY,
  • Преобразователь USB-to-3.3V-TTL для программирования.
  • Для освещения: 3 белых светодиода, BC327 или другой NPN-транзистор общего назначения (Ic = 500 мА), резистор 4k7k, 3 резистора 82Ом, монтажная плата, кабели (см. Схему и изображения).
  • Тумблер включения / выключения и нормально разомкнутая кнопка для программирования.

По желанию:

  • Камера типа «рыбий глаз» с более длинным гибкостью, чем стандартная камера OV2460, снабженная модулем ESP32-CAM,
  • Вот такая антенна WiFi с подходящим длинным кабелем и сверхминиатюрным коаксиальным разъемом. ESP32-CAM имеет встроенную антенну, а корпус пластиковый, так что антенна на самом деле не нужна, но я подумал, что это выглядит круто, так что …
  • Бумага с наклейками для струйной печати для дизайна верхней обложки.

Обычные аппаратные инструменты: паяльник, сверла, отвертки, плоскогубцы…

Шаг 1. Создание платформы для роботов

Создание платформы для роботов
Создание платформы для роботов
Создание платформы для роботов
Создание платформы для роботов
Создание платформы для роботов
Создание платформы для роботов

Схема:

В схеме нет ничего особенного. ESP32-cam управляет двигателями через плату драйвера двигателя L298N, которая имеет два канала. Двигатели левой и правой стороны размещены параллельно, каждая сторона занимает один канал. Как всегда, рекомендуется использовать четыре небольших керамических конденсатора 10..100 нФ рядом с выводами двигателя для противодействия радиочастотным помехам. Кроме того, большой электролитический колпачок (2200… 4700 мкФ) на питании платы двигателя, как показано на схеме, хотя и не является строго необходимым, может немного ограничить пульсации напряжения питания (если вы хотите посмотреть фильм ужасов, тогда попробуйте Vbat. с осциллографом при включенных двигателях).

Обратите внимание, что оба вывода канала двигателя ENABLE управляются одним и тем же выводом с широтно-импульсной модуляцией (PWM) ESP32 (IO12). Это связано с тем, что модуль ESP32-CAM не имеет тонны GPIO (схема модуля включена для справки). Светодиоды робота управляются IO4, который также управляет встроенным светодиодом вспышки, поэтому удалите Q1, чтобы светодиод не загорелся в закрытом корпусе.

Кнопка программирования, переключатель включения / выключения, разъем для зарядки и разъем для программирования доступны под роботом. Я мог бы гораздо лучше поработать с разъемом для программирования (разъем 3,5 мм?), Но пиво больше не могло ждать. Также было бы неплохо установить обновления по воздуху (OTA).

Чтобы перевести робота в режим программирования, нажмите кнопку программирования (при этом IO0 понизится), а затем включите его.

Важно: для зарядки никель-металлгидридных аккумуляторов робота используйте лабораторный источник питания (без нагрузки) примерно на 14 В и ограниченный током до 250 мА. Напряжение будет адаптироваться к напряжению аккумуляторов. Отключите его, если робот станет горячим или если напряжение аккумулятора достигнет примерно 12,5 В. Очевидным улучшением здесь будет установка подходящего зарядного устройства, но это выходит за рамки данной инструкции.

Оборудование:

См. Также примечания на фотографиях. Корпус устанавливается на базу робота с помощью 4 болтов M4 и самоконтрящихся гаек. Обратите внимание на резиновую трубку, используемую в качестве дистанционной прокладки. Надеюсь, это также придаст Duvel некоторую подвеску, если поездка окажется ухабистой. Модуль ESP32-CAM и плата двигателя L298N устанавливаются в корпус с помощью пластиковых липких ножек (не уверен в правильном названии на английском языке), чтобы избежать необходимости сверлить дополнительные отверстия. Также ESP32 смонтирован на собственной монтажной плате и подключаемых пинхэдерах. Это упрощает замену ESP32.

Не забывайте: если вы собираетесь использовать внешнюю антенну WiFi вместо встроенной, то также припаяйте перемычку выбора антенны на нижней стороне платы ESP32-CAM.

Распечатайте верхний логотип из файла DuvelBot.svg на бумаге для струйных наклеек (или создайте свой собственный), и все готово!

Шаг 2: запрограммируйте робота

Запрограммируйте робота
Запрограммируйте робота

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

Вам потребуются следующие программные инструменты:

  • IDE Arduino,
  • Библиотеки ESP32, SPIFFS (файловая система последовательной периферийной флэш-памяти), библиотека ESPAsync Webserver.

Последний можно установить, следуя этому рандомизированному руководству до раздела «Организация файлов» включительно. Я действительно не мог объяснить это лучше.

Код:

Мой код можно найти по адресу:

  • Скетч Arduino DuvelBot.ino,
  • Подпапка данных, в которой хранятся файлы, которые будут загружены во флэш-память ESP с помощью SPIFFS. Эта папка содержит веб-страницу, которую будет обслуживать ESP (index.html), изображение логотипа, являющееся частью веб-страницы (duvel.png), и каскадную таблицу стилей или файл CSS (style.css).

Чтобы запрограммировать робота:

  • Подключите преобразователь USB-TTL, как показано на схеме,
  • Файл -> Открыть -> перейти в папку, в которой находится DuvelBot.ino.
  • Измените свои сетевые учетные данные в скетче:

const char * ssid = "yourNetworkSSIDHere"; const char * password = "yourPasswordHere";

  • Инструменты -> Плата -> «AI-Thinker ESP-32 CAM» и выберите соответствующий последовательный порт для вашего компьютера (Инструменты -> Порт -> что-то вроде / dev / ttyUSB0 или COM4),
  • Откройте последовательный монитор в Arduino IDE, нажав кнопку PROG (которая подтягивает IO0 к низкому уровню), включите робота,
  • Проверьте на последовательном мониторе, что ESP32 готов к загрузке,
  • Закройте последовательный монитор (иначе загрузка SPIFFS не удастся),
  • Инструменты -> «Загрузка данных эскиза ESP32» и дождитесь его завершения,
  • Выключите и снова включите, удерживая кнопку PROG, чтобы вернуться в режим программирования,
  • Нажмите стрелку «Загрузить», чтобы запрограммировать скетч, и дождитесь его завершения,
  • Откройте последовательный монитор и сбросьте ESP32, выключив / включив,
  • После загрузки запишите IP-адрес (например, 192.168.0.121) и отключите робота от преобразователя USB-TTL,
  • Откройте браузер по этому IP-адресу. Вы должны увидеть интерфейс, как на картинке.
  • Необязательно: установите MAC-адрес ESP32 на фиксированный IP-адрес в вашем маршрутизаторе (зависит от маршрутизатора, как это сделать).

Вот и все! Читайте дальше, если хотите узнать, как это работает…

Шаг 3: как это работает

Теперь мы подошли к самому интересному: как все это работает вместе?

Я попытаюсь объяснить это шаг за шагом, но имейте в виду, что Кайняпс не специалист по веб-программированию. Фактически, изучение веб-программирования было основной предпосылкой создания DuvelBot. Если я допущу очевидные ошибки, оставьте, пожалуйста, комментарий!

Хорошо, после включения ESP32, как обычно при настройке, он инициализирует GPIO, связывает их с таймерами PWM для управления двигателем и светодиодами. См. Здесь дополнительную информацию об управлении двигателем, это довольно стандартно.

Потом камера настроена. Я намеренно оставил разрешение довольно низким (VGA или 640x480), чтобы избежать вялого отклика. Обратите внимание, что на плате AI-Thinker ESP32-CAM есть чип последовательной оперативной памяти (PSRAM), который она использует для хранения кадров камеры с большим разрешением:

if (psramFound ()) {Serial.println ("PSRAM обнаружен."); config.frame_size = FRAMESIZE_VGA; config.jpg_quality = 12; config.fb_count = 2; // количество буферов кадра см.: https://github.com/espressif/esp32-camera} else {Serial.println ("PSRAM не найден."); config.frame_size = FRAMESIZE_QVGA; config.jpg_quality = 12; config.fb_count = 1; }

Затем инициализируется файловая система последовательной периферийной флэш-памяти (SPIFFS):

// инициализируем SPIFFS if (! SPIFFS.begin (true)) {Serial.println («Произошла ошибка при монтировании SPIFFS!»); возвращение; }

SPIFFS действует как небольшая файловая система на ESP32. Здесь он используется для хранения трех файлов: самой веб-страницы index.html, каскадного файла таблицы стилей style.css и изображения в формате-p.webp

Затем ESP32 подключается к вашему маршрутизатору (не забудьте указать свои учетные данные перед загрузкой):

// здесь меняем учетные данные вашего маршрутизатораconst char * ssid = "yourNetworkSSIDHere"; const char * password = "yourPasswordHere"; … // подключаемся к WiFi Serial.print («Подключение к WiFi»); WiFi.begin (ssid, пароль); в то время как (WiFi.status ()! = WL_CONNECTED) {Serial.print ('.'); задержка (500); } // теперь подключен к маршрутизатору: ESP32 теперь имеет IP-адрес

Чтобы сделать что-то полезное, мы запускаем асинхронный веб-сервер:

// создаем объект AsyncWebServer на порту 80AsyncWebServer server (80); … Server.begin (); // начинаем прослушивать соединения

Теперь, если вы введете IP-адрес, который был назначен маршрутизатору ESP32 в адресной строке браузера, ESP32 получит запрос. Это означает, что он должен отвечать клиенту (вам или вашему браузеру), обслуживая его чем-то, например веб-страницей.

ESP32 знает, как отвечать, потому что при настройке ответы на все возможные разрешенные запросы были зарегистрированы с помощью server.on (). Например, главная веб-страница или индекс (/) обрабатываются следующим образом:

server.on ("/", HTTP_GET, (AsyncWebServerRequest * запрос) {Serial.println ("/ запрос получен!"); запрос-> отправить (SPIFFS, "/index.html", String (), false, процессор);});

Поэтому, если клиент подключается, ESP32 отвечает, отправляя файл index.html из файловой системы SPIFFS. Обработчик параметров - это имя функции, которая предварительно обрабатывает html и заменяет любые специальные теги:

// Заменяет заполнители в HTML, например% DATA% //, на переменные, которые вы хотите показать //

Данные:% DATA%

Строковый процессор (const String & var) {if (var == "DATA") {//Serial.println("in processor! "); return String (dutyCycleNow); } return String ();}

Теперь давайте удалим саму страницу index.html. Вообще всегда есть три части:

  1. html-код: какие элементы показывать (кнопки / текст / слайдеры / изображения и т. д.),
  2. код стиля, либо в отдельном файле.css, либо в разделе…: как должны выглядеть элементы,
  3. javascript a… раздел: как должна работать веб-страница.

Как только index.html загружается в браузер (который знает, что это html из-за строки DOCTYPE), он попадает в эту строку:

Это запрос таблицы стилей css. Расположение этого листа указано в href = "…". Итак, что делает ваш браузер? Правильно, он запускает еще один запрос к серверу, на этот раз для style.css. Сервер перехватывает этот запрос, потому что он был зарегистрирован:

server.on ("/ style.css", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("css-запрос получен"); request-> send (SPIFFS, "/style.css", "text / css" ");});

Аккуратно, да? Между прочим, это могло быть href = "/ some / file / on / the / other / side / of / the / moon", если ваш браузер не заботился об этом. Он бы так же успешно получил этот файл. Я не буду объяснять таблицу стилей, поскольку она просто контролирует внешний вид, поэтому здесь это не очень интересно, но если вы хотите узнать больше, посмотрите этот учебник.

Как появляется логотип DuvelBot? В index.html у нас есть:

на что ESP32 отвечает:

server.on ("/ duvel", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("запрос логотипа duvel получен!"); request-> send (SPIFFS, "/duvel.png", "image /-p.webp

..другой файл SPIFFS, на этот раз полный образ, как указано в ответе "image / png".

Теперь мы подошли к действительно интересной части: коду кнопок. Сфокусируемся на кнопке ВПЕРЕД:

ВПЕРЕД

Имя class = "…" - это только имя, чтобы связать его с таблицей стилей для настройки размера, цвета и т. Д. Важными частями являются onmousedown = "toggleCheckbox ('forward')" и onmouseup = "toggleCheckbox ('stop') ". Они составляют действия кнопки (то же самое для ontouchstart / ontouchend, но для сенсорных экранов / телефонов). Здесь действие кнопки вызывает функцию toggleCheckbox (x) в разделе javascript:

функция toggleCheckbox (x) {var xhr = new XMLHttpRequest (); xhr.open ("ПОЛУЧИТЬ", "/" + x, истина); xhr.send (); // могли бы что-то сделать и с ответом, когда он будет готов, но мы этого не делаем}

Таким образом, нажатие кнопки «Вперед» немедленно приводит к вызову toggleCheckbox ('forward'). Затем эта функция запускает XMLHttpRequest «GET» с местоположением «/ forward», который действует так же, как если бы вы набрали 192.168.0.121/forward в адресной строке браузера. Как только этот запрос поступает в ESP32, он обрабатывается:

server.on ("/ forward", HTTP_GET, (AsyncWebServerRequest * запрос) {Serial.println ("получено / переадресовано"); actionNow = FORWARD; request-> send (200, "text / plain", "OK вперед. ");});

Теперь ESP32 просто отвечает текстом «ОК, вперед». Обратите внимание, что toggleCheckBox () ничего не делает с этим ответом (и не ожидает его), однако может, как показано ниже в коде камеры.

Сама по себе во время этого ответа программа только устанавливает переменную actionNow = FORWARD, как реакцию на нажатие кнопки. Теперь в главном цикле программы эта переменная отслеживается с целью увеличения / уменьшения ШИМ двигателей. Логика такова: пока у нас есть действие, которое не является STOP, увеличивайте двигатели в этом направлении, пока не будет достигнуто определенное число (dutyCycleMax). Затем поддерживайте эту скорость, пока actionNow не изменился:

недействительный цикл () {currentMillis = millis (); if (currentMillis - previousMillis> = dutyCycleStepDelay) {// сохраняем время последнего выполнения цикла previousMillis = currentMillis; // mainloop отвечает за ускорение / замедление двигателей if (actionNow! = previousAction) {// замедление, затем останов, затем изменение действия и нарастание dutyCycleNow = dutyCycleNow-dutyCycleStep; if (dutyCycleNow <= 0) {// если после замедления постоянный ток равен 0, установить новое направление, начать с минимального рабочего цикла setDir (actionNow); previousAction = actionNow; dutyCycleNow = dutyCycleMin; }} else // actionNow == previousAction нарастает, кроме случаев, когда направление STOP {if (actionNow! = STOP) {dutyCycleNow = dutyCycleNow + dutyCycleStep; if (dutyCycleNow> dutyCycleMax) dutyCycleNow = dutyCycleMax; } else dutyCycleNow = 0; } ledcWrite (pwmChannel, dutyCycleNow); // регулируем рабочий цикл мотора}}

Это медленно увеличивает скорость двигателей, вместо того, чтобы просто запускать на полной скорости и проливать драгоценный драгоценный Duvel. Очевидным улучшением было бы переместить этот код в программу обработки прерывания по таймеру, но она работает как есть.

Теперь, если мы отпустим кнопку «Вперед», ваш браузер вызовет toggleCheckbox ('stop'), что приведет к запросу GET / stop. ESP32 устанавливает для actionNow значение STOP (и отвечает «OK, остановка»), что заставляет основной цикл замедлить двигатели.

А как насчет светодиодов? Тот же механизм, но теперь у нас есть слайдер:

В javascript отслеживается настройка ползунка, так что при каждом изменении происходит вызов «/ LED / xxx», где xxx - это значение яркости, на которое должны быть установлены светодиоды:

var slide = document.getElementById ('слайд'), sliderDiv = document.getElementById ("sliderAmount"); slide.onchange = function () {var xhr = new XMLHttpRequest (); xhr.open («ПОЛУЧИТЬ», «/ LED /» + this.value, true); xhr.send (); sliderDiv.innerHTML = this.value; }

Обратите внимание, что мы использовали document.getElementByID ('slide'), чтобы получить сам объект слайдера, который был объявлен с и что значение выводится в текстовый элемент с каждым изменением.

Обработчик в скетче улавливает все запросы яркости, используя "/ LED / *" в регистрации обработчика. Затем последняя часть (число) разделяется и преобразуется в int:

server.on ("/ LED / *", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("светодиодный запрос получен!"); setLedBrightness ((request-> url ()). substring (5).toInt ()); запрос-> отправить (200, «текст / обычный», «ОК светодиоды.»);});

Подобно описанному выше, радиокнопки управляют переменными, которые устанавливают значения ШИМ по умолчанию, так что DuvelBot может медленно подъехать к вам с пивом, осторожно, чтобы не пролить это жидкое золото, и быстро вернуться на кухню, чтобы принести еще.

… Так как же обновить изображение с камеры, не обновляя страницу? Для этого мы используем технику под названием AJAX (асинхронный JavaScript и XML). Проблема в том, что обычно соединение клиент-сервер следует фиксированной процедуре: клиент (браузер) делает запрос, сервер (ESP32) отвечает, дело закрыто. Выполнено. Больше ничего не происходит. Если бы мы могли каким-то образом обмануть браузер, заставив его регулярно запрашивать обновления от ESP32… и именно это мы будем делать с этим фрагментом javascript:

setInterval (function () {var xhttp = new XMLHttpRequest (); xhttp.open ("GET", "/ CAMERA", true); xhttp.responseType = "blob"; xhttp.timeout = 500; xhttp.ontimeout = function () {}; xhttp.onload = function (e) {if (this.readyState == 4 && this.status == 200) {// см.: https://stackoverflow.com/questions/7650587/using… // https://www.html5rocks.com/en/tutorials/file/xhr2/ var urlCreator = window. URL || window.webkitURL; var imageUrl = urlCreator.createObjectURL (this.response); // создаем объект из большого двоичного объекта document.querySelector ("# camimage"). src = imageUrl; urlCreator.revokeObjectURL (imageurl)}}; xhttp.send ();}, 250);

setInterval принимает в качестве параметра функцию и выполняет ее время от времени (здесь один раз в 250 мс, что дает 4 кадра в секунду). Выполняемая функция делает запрос двоичного «блоба» по адресу / КАМЕРА. Это обрабатывается ESP32-CAM в скетче как (из Randomnerdtutorials):

server.on ("/ CAMERA", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("запрос камеры получен!"); camera_fb_t * fb = NULL; // esp_err_t res = ESP_OK; size_t _jpg_buf_len = 0; uint8 * _jpg_buf = NULL; // захват кадра fb = esp_camera_fb_get (); if (! fb) {Serial.println («Не удалось получить буфер кадра»); return;} if (fb-> format! = PIXFORMAT_JPEG) / / уже в этом формате из конфигурации {bool jpeg_converted = frame-j.webp

Важными частями являются получение кадра fb = esp_camera_fb_get (), преобразование его в-j.webp

Затем функция javascript ожидает прибытия этого изображения. Затем нужно немного поработать, чтобы преобразовать полученный «blob» в URL-адрес, который можно использовать в качестве источника для обновления изображения на странице html.

уф, мы закончили!

Шаг 4: идеи и остатки

Идеи и остатки
Идеи и остатки

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

  • Реализуйте «настоящую» потоковую передачу с камеры, как описано здесь и здесь, и переместите ее на второй сервер, как описано здесь, на том же ESP32, но на другом ядре ЦП, затем импортируйте поток камеры в html, обслуживаемый 1-м сервером, используя…. Это должно привести к более быстрому обновлению камеры.
  • Используйте режим точки доступа (AP), чтобы робот был более автономным, как описано здесь.
  • Расширьте возможности измерения напряжения батареи, возможности глубокого сна и т. Д. Это немного сложно на данный момент, потому что AI-Thinker ESP32-CAM не имеет большого количества GPIO; требуется расширение через uart и например подчиненный arduino.
  • Превратитесь в робота, ищущего кошек, который время от времени выбрасывает кошачье лакомство нажатием лапы на большую кнопку, транслируйте тонны красивых картинок кошек в течение дня …

Прокомментируйте, если вам понравилось или у вас есть вопросы, и спасибо за чтение!

Рекомендуемые: