Tabla de contenido:

DuvelBot - Robot para servir cerveza ESP32-CAM: 4 pasos (con imágenes)
DuvelBot - Robot para servir cerveza ESP32-CAM: 4 pasos (con imágenes)

Video: DuvelBot - Robot para servir cerveza ESP32-CAM: 4 pasos (con imágenes)

Video: DuvelBot - Robot para servir cerveza ESP32-CAM: 4 pasos (con imágenes)
Video: Robot sirve cerveza perfecta 2024, Junio
Anonim
DuvelBot - Robot para servir cerveza ESP32-CAM
DuvelBot - Robot para servir cerveza ESP32-CAM

Después de un duro día de trabajo, nada se compara a beber su cerveza favorita en el sofá. En mi caso, esa es la cerveza rubia belga "Duvel". Sin embargo, después de todo, pero colapsando, nos enfrentamos a un problema muy serio: la nevera que contiene mi Duvel está a 20 pies infranqueables de dicho sofá.

Si bien una ligera coacción de mi lado podría mover a un adolescente ocasional que limpia la nevera para derramar la ración de Duvel para mi semana, la tarea de entregarlo a su progenitor casi exhausto es obviamente un paso demasiado lejos.

Es hora de sacar el soldador y el teclado …

DuvelBot es una cámara web de conducción sencilla basada en AI-Thinker ESP32-CAM, que puede controlar desde su teléfono inteligente, navegador o tableta.

Es fácil adaptar o expandir esta plataforma para usos menos alcohólicos (piense en SpouseSpy, NeighbourWatch, KittyCam…).

Construí este robot principalmente para aprender un poco sobre toda la programación web y las cosas de IoT, de las que no sabía nada. Así que al final de este Instructable hay una explicación detallada de cómo funciona.

Muchas partes de este Instructable se basan en las excelentes explicaciones que se encuentran en Random Nerd Tutorials, ¡así que por favor, visítalos!

Suministros

Que necesitas:

La lista de piezas no está tallada en piedra y muchas piezas se pueden obtener en una tonelada de versiones diferentes y de muchos lugares diferentes. La mayor parte la obtuve de Ali-Express. Como decía Machete: improvisa.

Hardware:

  • Módulo AI Thinker ESP32-CAM. Probablemente podría funcionar con otros módulos ESP32-CAM, pero eso es lo que usé
  • Placa de controlador de motor L298N,
  • Una plataforma robótica barata de 4 ruedas,
  • Una carcasa con una gran superficie plana como la Hammond Electronics 1599KGY,
  • Convertidor USB a 3.3V-TTL para programación.
  • Para la iluminación: 3 LED blancos, BC327 u otro transistor de propósito general NPN (Ic = 500mA), resistencia de 4k7k, 3 resistencias de 82Ohm, placa perfilada, cables (ver esquema e imágenes).
  • Un interruptor de palanca de encendido / apagado y un botón normalmente abierto para la programación.

Opcional:

  • Una cámara de ojo de pez con una flexión más larga que la cámara estándar OV2460 proporcionada con el módulo ESP32-CAM,
  • Antena WiFi con cable convenientemente largo y Conector Coaxial Ultra Miniatura, como este. El ESP32-CAM tiene una antena a bordo y la carcasa es de plástico, por lo que no se necesita una antena, sin embargo, pensé que se veía genial, así que …
  • Papel adhesivo imprimible con inyección de tinta para el diseño de la cubierta superior.

Las herramientas habituales de ferretería: soldador, taladros, destornilladores, alicates …

Paso 1: construcción de la plataforma del robot

Construyendo la plataforma del robot
Construyendo la plataforma del robot
Construyendo la plataforma del robot
Construyendo la plataforma del robot
Construyendo la plataforma del robot
Construyendo la plataforma del robot

El esquema:

El esquema no es nada especial. La leva ESP32 controla los motores a través de la placa de controlador de motor L298N, que tiene dos canales. Los motores del lado izquierdo y derecho se colocan en paralelo y cada lado ocupa un canal. Cuatro pequeños condensadores cerámicos de 10..100nF cerca de los pines del motor son, como siempre, recomendables para contrarrestar la interferencia de RF. Además, una tapa electrolítica grande (2200 … 4700uF) en el suministro de la placa del motor como se muestra en el esquema, aunque no es estrictamente necesario, puede limitar un poco la ondulación del voltaje de suministro (si desea ver una película de terror, entonces pruebe Vbat con un osciloscopio mientras los motores están activos).

Tenga en cuenta que ambos pines ENABLE de los canales del motor son controlados por el mismo pin de modulación de ancho de pulso (PWM) del ESP32 (IO12). Esto se debe a que el módulo ESP32-CAM no tiene una tonelada de GPIO (el esquema del módulo se incluye como referencia). Los LED del robot son controlados por IO4, que también activa el LED flash integrado, por lo tanto, retire Q1 para evitar que el LED flash se encienda en una carcasa cerrada.

El botón de programación, el interruptor de encendido / apagado, el conector de carga y el conector de programación son accesibles debajo del robot. Podría haber hecho un trabajo mucho mejor para el conector de programación (¿conector de 3,5 mm?), Pero la cerveza no podía esperar más. También sería bueno configurar las actualizaciones inalámbricas (OTA).

Para poner el robot en modo de programación, presione el botón de programación (esto baja IO0) y luego enciéndalo.

Importante: para cargar las baterías de NiMH del robot, utilice un juego de suministro de laboratorio (descargado) a unos 14V y corriente limitada a 250mA. El voltaje se adaptará al voltaje de las baterías. Desconecte si el robot se calienta o el voltaje de la batería alcanza aproximadamente 12,5 V. Una mejora obvia aquí sería integrar un cargador de batería adecuado, pero eso está fuera del alcance de este Instructable.

El hardware:

Consulte también las notas en las imágenes. La carcasa se monta en la base del robot mediante 4 pernos M4 y tuercas autoblocantes. Tenga en cuenta el tubo de goma utilizado como espaciadores de distancia. Con suerte, esto también le da algo de suspensión a la Duvel, en caso de que el viaje resulte accidentado. El módulo ESP32-CAM y la placa del motor L298N se montan en la carcasa con pies adhesivos de plástico (no estoy seguro del nombre correcto en inglés), para evitar tener que perforar agujeros adicionales. Además, el ESP32 está montado en su propio tablero de perfiles y cabezales de clavija enchufables. Esto facilita el cambio del ESP32.

No lo olvide: si va con una antena WiFi externa en lugar de la incorporada, suelde también el puente de selección de antena en la parte inferior de la placa ESP32-CAM.

Imprima el logotipo superior en el archivo DuvelBot.svg en papel adhesivo de inyección de tinta (o diseñe el suyo propio), ¡y estará listo para comenzar!

Paso 2: programe el robot

Programar el robot
Programar el robot

Es recomendable programar el robot antes de cerrarlo, para asegurarse de que todo funcione y no aparezca ningún humo mágico.

Necesita las siguientes herramientas de software:

  • El IDE de Arduino,
  • Las bibliotecas ESP32, SPIFFS (sistema de archivos flash de periféricos en serie), biblioteca de servidor web ESPAsync.

Este último se puede instalar siguiendo este tutorial de randomnerd hasta e incluyendo la sección "organizar sus archivos". Realmente no podría explicarlo mejor.

El código:

Mi código se puede encontrar en:

  • Un boceto de Arduino DuvelBot.ino,
  • Una subcarpeta de datos que contiene los archivos que se van a cargar en la memoria flash ESP usando SPIFFS. Esta carpeta contiene la página web que servirá el ESP (index.html), una imagen de logotipo que forma parte de la página web (duvel.png) y una hoja de estilo en cascada o un archivo CSS (style.css).

Para programar el robot:

  • Conecte el convertidor USB-TTL como se muestra en el esquema,
  • Archivo -> Abrir -> ir a la carpeta donde se encuentra DuvelBot.ino.
  • Cambie sus credenciales de red en el boceto:

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

  • Herramientas -> Placa -> "AI-Thinker ESP-32 CAM" y seleccione el puerto serie apropiado para su PC (Herramientas -> Puerto -> algo como / dev / ttyUSB0 o COM4),
  • Abra el monitor serial en el IDE de Arduino, mientras presiona el botón PROG (que tira IO0 bajo), encienda el robot,
  • Verifique en el monitor serial que el ESP32 está listo para descargar,
  • Cierre el monitor en serie (de lo contrario, la carga de SPIFFS falla),
  • Herramientas -> "Carga de datos de Sketch ESP32" y espere a que termine,
  • Apague y vuelva a encender manteniendo pulsado el botón PROG para volver al modo de programación,
  • Pulsa la flecha "Subir" para programar el boceto y espera a que termine,
  • Abra el monitor en serie y reinicie el ESP32 apagando / encendiendo,
  • Una vez que haya arrancado, anote la dirección IP (algo así como 192.168.0.121) y desconecte el robot del convertidor USB-TTL,
  • Abra un navegador en esta dirección IP. Debería ver la interfaz como en la imagen.
  • Opcional: configure la dirección mac del ESP32 en una dirección IP fija en su enrutador (depende del enrutador cómo hacerlo).

¡Eso es todo! Siga leyendo si quiere saber cómo funciona …

Paso 3: cómo funciona

Ahora llegamos a la parte interesante: ¿cómo funciona todo en conjunto?

Intentaré explicarlo paso … a … paso, pero tenga en cuenta que Kajnjaps no es un especialista en programación web. De hecho, aprender un poco de programación web fue la premisa de construir DuvelBot. Si cometo errores obvios, ¡deje un comentario!

Ok, después de encender ESP32, como es habitual en la configuración, inicializa los GPIO, los asocia con temporizadores PWM para el control del motor y el LED. Consulte aquí para obtener más información sobre el control del motor, es bastante estándar.

Entonces la cámara está configurada. Deliberadamente mantuve la resolución bastante baja (VGA o 640x480) para evitar una respuesta lenta. Tenga en cuenta que la placa AI-Thinker ESP32-CAM tiene un chip ram serie (PSRAM) que utiliza para almacenar fotogramas de cámara de mayor resolución:

if (psramFound ()) {Serial.println ("PSRAM encontrado"); config.frame_size = FRAMESIZE_VGA; config.jpg_quality = 12; config.fb_count = 2; // número de framebuffers ver: https://github.com/espressif/esp32-camera} else {Serial.println ("no se encontró PSRAM"); config.frame_size = FRAMESIZE_QVGA; config.jpg_quality = 12; config.fb_count = 1; }

Luego, se inicializa el sistema de archivos flash de periféricos en serie (SPIFFS):

// inicializar SPIFFS if (! SPIFFS.begin (true)) {Serial.println ("¡Se ha producido un error al montar SPIFFS!"); regreso; }

SPIFFS actúa como un pequeño sistema de archivos en el ESP32. Aquí se utiliza para almacenar tres archivos: la propia página web index.html, una hoja de estilo de archivo en cascada style.css y un logotipo de imagen-p.webp

A continuación, el ESP32 se conecta a su enrutador (no olvide configurar sus credenciales antes de cargar):

// cambia las credenciales de tu enrutador hereconst char * ssid = "yourNetworkSSIDHere"; const char * password = "yourPasswordHere"; … // conectarse a WiFi Serial.print ("Conectando a WiFi"); WiFi.begin (ssid, contraseña); while (WiFi.status ()! = WL_CONNECTED) {Serial.print ('.'); retraso (500); } // ahora conectado al enrutador: ESP32 ahora tiene dirección IP

Para hacer algo realmente útil, iniciamos un servidor web asincrónico:

// crea un objeto AsyncWebServer en el puerto 80AsyncWebServer server (80); … Servidor.begin (); // empieza a escuchar conexiones

Ahora, si escribe la dirección IP que el enrutador asignó al ESP32 en la barra de direcciones del navegador, el ESP32 recibe una solicitud. Esto significa que debe responder al cliente (usted o su navegador) proporcionándole algo, por ejemplo, una página web.

El ESP32 sabe cómo responder, porque en la configuración las respuestas a todas las posibles solicitudes permitidas se han registrado usando server.on (). Por ejemplo, la página web principal o el índice (/) se maneja así:

server.on ("/", HTTP_GET, (AsyncWebServerRequest * solicitud) {Serial.println ("/ solicitud recibida"); solicitud-> enviar (SPIFFS, "/index.html", String (), falso, procesador);});

Entonces, si el cliente se conecta, el ESP32 responde enviando el archivo index.html desde el sistema de archivos SPIFFS. El procesador de parámetros es el nombre de una función que preprocesa el html y reemplaza cualquier etiqueta especial:

// Reemplaza los marcadores de posición en el html como% DATA% // con las variables que desea mostrar //

Datos:% DATA%

Procesador de cadenas (const String & var) {if (var == "DATA") {//Serial.println("in processor! "); return String (dutyCycleNow); } return String ();}

Ahora, diseccionemos la página web index.html en sí. En general, siempre hay tres partes:

  1. código html: qué elementos deben mostrarse (botones / texto / controles deslizantes / imágenes, etc.),
  2. código de estilo, ya sea en un archivo.css separado o en una sección …: cómo deberían verse los elementos,
  3. javascript a… sección: cómo debe actuar la página web.

Una vez que index.html se carga en el navegador (que sabe que es html debido a la línea DOCTYPE), se encuentra con esta línea:

Esa es una solicitud de una hoja de estilo CSS. La ubicación de esta hoja se da en href = "…". Entonces, ¿qué hace tu navegador? Correcto, lanza otra solicitud al servidor, esta vez para style.css. El servidor captura esta solicitud, porque se registró:

server.on ("/ style.css", HTTP_GET, (AsyncWebServerRequest * solicitud) {Serial.println ("solicitud css recibida"); solicitud-> enviar (SPIFFS, "/style.css", "texto / css ");});

Limpio, ¿eh? Por cierto, podría haber sido href = "/ algún / archivo / en / el / otro / lado / de / la / luna", por lo que a su navegador le importó. Iría a buscar ese archivo con la misma alegría. No explicaré sobre la hoja de estilo, ya que solo controla las apariencias, por lo que no es realmente interesante aquí, pero si desea obtener más información, consulte este tutorial.

¿Cómo aparece el logotipo de DuvelBot? En index.html tenemos:

a lo que el ESP32 responde con:

server.on ("/ duvel", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("¡solicitud de logotipo duvel recibida!"); request-> send (SPIFFS, "/duvel.png", "image /-p.webp

..otro archivo SPIFFS, esta vez una imagen completa, como lo indica "image / png" en la respuesta.

Ahora llegamos a la parte realmente interesante: el código de los botones. Centrémonos en el botón ADELANTE:

HACIA ADELANTE

El nombre class = "…" es solo un nombre para vincularlo a la hoja de estilo para personalizar el tamaño, el color, etc. Las partes importantes son onmousedown = "toggleCheckbox ('forward')" y onmouseup = "toggleCheckbox ('stop') ". Estas constituyen las acciones del botón (lo mismo para ontouchstart / ontouchend pero para eso son pantallas táctiles / teléfonos). Aquí, la acción del botón llama a una función toggleCheckbox (x) en la sección de javascript:

función toggleCheckbox (x) {var xhr = new XMLHttpRequest (); xhr.open ("OBTENER", "/" + x, verdadero); xhr.send (); // también podríamos hacer algo con la respuesta cuando esté listo, pero no lo hacemos}

Por lo tanto, al presionar el botón de avance, inmediatamente se llama a toggleCheckbox ('adelante'). Esta función luego lanza un XMLHttpRequest "GET", de la ubicación "/ forward" que actúa como si hubiera escrito 192.168.0.121/forward en la barra de direcciones de su navegador. Una vez que esta solicitud llega al ESP32, es manejada por:

server.on ("/ reenviar", HTTP_GET, (AsyncWebServerRequest * solicitud) {Serial.println ("recibido / reenviar"); actionNow = FORWARD; request-> send (200, "text / plain", "OK reenviar. ");});

Ahora el ESP32 simplemente responde con un texto "OK adelante". Tenga en cuenta que toggleCheckBox () no hace nada con (o espera) esta respuesta, sin embargo, podría como se muestra más adelante en el código de la cámara.

En sí mismo durante esta respuesta, el programa solo establece una variable actionNow = FORWARD, como respuesta a presionar el botón. Ahora, en el bucle principal del programa, esta variable se monitorea con el objetivo de aumentar / disminuir la PWM de los motores. La lógica es: mientras tengamos una acción que no sea STOP, acelere los motores en esa dirección hasta que se alcance un cierto número (dutyCycleMax). Luego, mantén esa velocidad, siempre que la acción ahora no haya cambiado:

bucle vacío () {currentMillis = millis (); if (currentMillis - previousMillis> = dutyCycleStepDelay) {// guardar la última vez que ejecutó el ciclo previousMillis = currentMillis; // mainloop es responsable de acelerar hacia arriba / abajo los motores if (actionNow! = previousAction) {// disminuir, luego parar, luego cambiar la acción y aumentar dutyCycleNow = dutyCycleNow-dutyCycleStep; if (dutyCycleNow <= 0) {// si después de reducir dc es 0, se establece en la nueva dirección, comienza en el ciclo de trabajo mínimo setDir (actionNow); previousAction = actionNow; dutyCycleNow = dutyCycleMin; }} else // actionNow == previousAction ramp up, excepto cuando la dirección es STOP {if (actionNow! = STOP) {dutyCycleNow = dutyCycleNow + dutyCycleStep; if (dutyCycleNow> dutyCycleMax) dutyCycleNow = dutyCycleMax; } else dutyCycleNow = 0; } ledcWrite (pwmChannel, dutyCycleNow); // ajustar el ciclo de trabajo del motor}}

Esto aumenta lentamente la velocidad de los motores, en lugar de simplemente lanzarse a toda velocidad y derramar la preciosa y preciosa Duvel. Una mejora obvia sería mover este código a una rutina de interrupción del temporizador, pero funciona como está.

Ahora, si soltamos el botón de avance, su navegador llama a toggleCheckbox ('detener'), lo que genera una solicitud para GET / stop. El ESP32 establece actionNow en STOP (y responde con "OK stop"), lo que hace que el bucle principal haga girar los motores.

¿Y los LED? Mismo mecanismo, pero ahora tenemos un control deslizante:

En el javascript, se monitorea la configuración del control deslizante, de modo que en cada cambio ocurre una llamada para obtener "/ LED / xxx", donde xxx es el valor de brillo en el que se deben establecer los LED:

var slide = document.getElementById ('slide'), sliderDiv = document.getElementById ("sliderAmount"); slide.onchange = function () {var xhr = new XMLHttpRequest (); xhr.open ("OBTENER", "/ LED /" + este.valor, verdadero); xhr.send (); sliderDiv.innerHTML = this.value; }

Tenga en cuenta que usamos document.getElementByID ('slide') para obtener el objeto del control deslizante en sí, que se declaró con y que el valor se envía a un elemento de texto con cada cambio.

El manejador en el boceto captura todas las solicitudes de brillo usando "/ LED / *" en el registro del manejador. Luego, la última parte (un número) se divide y se convierte en un int:

server.on ("/ LED / *", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("¡solicitud led recibida!"); setLedBrightness ((request-> url ()). substring (5).toInt ()); solicitud-> enviar (200, "texto / plano", "OK Leds.");});

De manera similar a como se describió anteriormente, los botones de radio controlan las variables que establecen los valores predeterminados de PWM, de modo que DuvelBot puede conducir lentamente hacia usted con la cerveza, con cuidado de no derramar ese oro líquido y regresar rápidamente a la cocina para buscar un poco más.

… Entonces, ¿cómo se actualiza la imagen de la cámara sin tener que actualizar la página? Para eso usamos una técnica llamada AJAX (Asynchronous JavaScript and XML). El problema es que normalmente una conexión cliente-servidor sigue un procedimiento fijo: el cliente (navegador) realiza una solicitud, el servidor (ESP32) responde, caso cerrado. Hecho. Ya no pasa nada. Si de alguna manera pudiéramos engañar al navegador para que solicite regularmente actualizaciones del ESP32 … y eso es exactamente lo que haremos con esta pieza de 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) {// ver: 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); // crear un objeto desde el blob document.querySelector ("# camimage"). src = imageUrl; urlCreator.revokeObjectURL (imageurl)}}; xhttp.send ();}, 250);

setInterval toma como parámetro una función y la ejecuta cada cierto tiempo (aquí una vez cada 250ms resultando en 4 cuadros / segundo). La función que se ejecuta solicita un "blob" binario en la dirección / CAMERA. Esto es manejado por el ESP32-CAM en el boceto como (de Randomnerdtutorials):

server.on ("/ CAMERA", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("¡solicitud de cámara recibida!"); camera_fb_t * fb = NULL; // esp_err_t res = ESP_OK; size_t _jpg_buf_len = 0; uint8_t * _jpg_buf = NULL; // capturar un fotograma fb = esp_camera_fb_get (); if (! fb) {Serial.println ("No se pudo adquirir el búfer de fotogramas"); return;} if (fb-> format! = PIXFORMAT_JPEG) / / ya en este formato de config {bool jpeg_converted = frame-j.webp

Las partes importantes son obtener el marco fb = esp_camera_fb_get () convertirlo a un-j.webp

Luego, la función javascript espera a que llegue esta imagen. Luego, solo se necesita un poco de trabajo para convertir el "blob" recibido en una URL que se puede usar como fuente para actualizar la imagen en la página html.

¡Uf, hemos terminado!

Paso 4: Ideas y sobras

Ideas y sobras
Ideas y sobras

El objetivo de este proyecto para mí era aprender la programación web suficiente para conectar el hardware a la web. Son posibles varias ampliaciones de este proyecto. Aqui hay algunas ideas:

  • Implemente la transmisión de cámara 'real' como se explica aquí y aquí y muévala a un segundo servidor como se explica aquí en el mismo ESP32, pero en el otro núcleo de la CPU, luego importe el flujo de cámara en el html servido por el primer servidor usando un…. Esto debería resultar en actualizaciones de la cámara más rápidas.
  • Utilice el modo de punto de acceso (AP) para que el robot sea más independiente como se explica aquí.
  • Amplíe con medición de voltaje de la batería, capacidades de sueño profundo, etc. Esto es un poco difícil en este momento porque el AI-Thinker ESP32-CAM no tiene muchos GPIO; necesita expansión a través de uart y, por ejemplo, un arduino esclavo.
  • Conviértase en un robot que busca gatos que expulsa golosinas para gatos de vez en cuando al presionar un botón grande con la pata, transmite toneladas de bonitas fotos de gatos durante el día …

Por favor comente si le gustó o tiene preguntas y gracias por leer!

Recomendado: