Índice:

DuvelBot - ESP32-CAM robô que serve cerveja: 4 etapas (com fotos)
DuvelBot - ESP32-CAM robô que serve cerveja: 4 etapas (com fotos)

Vídeo: DuvelBot - ESP32-CAM robô que serve cerveja: 4 etapas (com fotos)

Vídeo: DuvelBot - ESP32-CAM robô que serve cerveja: 4 etapas (com fotos)
Vídeo: Трактористы (комедия, реж. Иван Пырьев, 1939 г.) 2024, Junho
Anonim
DuvelBot - Robô de Servir Cerveja ESP32-CAM
DuvelBot - Robô de Servir Cerveja ESP32-CAM

Após um árduo dia de trabalho, nada se compara a tomar sua cerveja favorita no sofá. No meu caso, é a ale loira belga "Duvel". No entanto, depois de tudo, exceto o colapso, somos confrontados com um problema muito sério: a geladeira que contém meu Duvel está a uns 20 pés intransponíveis de distância do referido sofá.

Embora alguma leve coerção da minha parte possa mover um ocasional limpador de geladeira adolescente para derramar minha mesada de Duvel da semana, a tarefa de realmente entregá-lo ao seu progenitor quase exausto é obviamente um passo longe demais.

É hora de usar o ferro de solda e o teclado …

DuvelBot é uma webcam simples para dirigir baseada em AI-Thinker ESP32-CAM, que você pode controlar de seu smartphone, navegador ou tablet.

É fácil adaptar ou expandir esta plataforma para usos menos alcoólicos (pense em SpouseSpy, NeighbourWatch, KittyCam …).

Eu construí este robô principalmente para aprender um pouco sobre toda a programação web e coisas de IoT, sobre as quais eu não sabia nada. Portanto, no final deste Instructable está uma explicação elaborada de como isso funciona.

Muitas partes deste Instructable são baseadas nas excelentes explicações encontradas nos Tutoriais Random Nerd, então, por favor, visite-os!

Suprimentos

O que você precisa:

A lista de peças não é gravada em pedra e muitas peças podem ser obtidas em uma tonelada de versões diferentes e em muitos lugares diferentes. Eu comprei a maior parte da Ali-Express. Como Machete disse: improvise.

Hardware:

  • Módulo AI Thinker ESP32-CAM. Provavelmente poderia funcionar com outros módulos ESP32-CAM, mas foi o que usei
  • Placa de controle do motor L298N,
  • Uma plataforma robótica barata de 4 rodas,
  • Uma caixa com uma grande superfície plana, como a Hammond Electronics 1599KGY,
  • Conversor de USB para 3,3 V TTL para programação.
  • Para a iluminação: 3 LEDs brancos, BC327 ou outro transistor de uso geral NPN (Ic = 500mA), resistor 4k7k, 3 resistores 82Ohm, perfboard, cabos (veja o esquema e as fotos).
  • Uma chave liga / desliga e um botão normalmente aberto para programação.

Opcional:

  • Uma câmera fisheye com flexibilidade maior do que a câmera OV2460 padrão fornecida com o módulo ESP32-CAM,
  • Antena WiFi com cabo adequadamente longo e Conector Coaxial Ultra Miniatura, como este. O ESP32-CAM tem uma antena interna e a caixa é de plástico, então uma antena realmente não é necessária, no entanto eu achei que ficou legal, então …
  • Papel adesivo para impressão a jato de tinta para o design da capa superior.

As ferramentas usuais de hardware: ferro de solda, brocas, chaves de fenda, alicates …

Etapa 1: Construindo a plataforma do robô

Construindo a plataforma do robô
Construindo a plataforma do robô
Construindo a plataforma do robô
Construindo a plataforma do robô
Construindo a plataforma do robô
Construindo a plataforma do robô

O esquema:

O esquema não é nada especial. O ESP32-cam controla os motores por meio da placa de driver do motor L298N, que tem dois canais. Os motores do lado esquerdo e direito são colocados em paralelo e cada lado ocupa um canal. Quatro pequenos capacitores de cerâmica 10..100nF próximos aos pinos do motor são sempre recomendados para combater a interferência de RF. Além disso, uma grande capa eletrolítica (2200… 4700uF) na alimentação da placa do motor, conforme mostrado no esquema, embora não seja estritamente necessária, pode limitar a ondulação da tensão de alimentação um pouco (se você quiser ver um filme de terror, então experimente Vbat com um osciloscópio enquanto os motores estão ativos).

Observe que os dois pinos ENABLE dos canais do motor são acionados pelo mesmo pino modulado por largura de pulso (PWM) do ESP32 (IO12). Isso ocorre porque o módulo ESP32-CAM não tem uma tonelada de GPIOs (o esquema do módulo incluído para referência). Os LEDs do robô são acionados por IO4, que também aciona o LED de flash integrado, portanto, remova Q1 para evitar que o LED de flash acenda em uma caixa fechada.

Botão de programação, interruptor liga / desliga, conector de carregamento e conector de programação podem ser acessados embaixo do robô. Eu poderia ter feito um trabalho muito melhor para o conector de programação (conector de 3,5 mm?), Mas a cerveja não podia mais esperar. Além disso, atualizações pelo ar (OTA) seriam boas para configurar.

Para colocar o robô no modo de programação, pressione o botão de programação (isso puxa IO0 para baixo) e, em seguida, ligue-o.

Importante: para carregar as baterias NiMH do robô, use um conjunto de alimentação de laboratório (sem carga) a cerca de 14V e corrente limitada a 250mA. A tensão se adaptará à tensão das baterias. Desconecte se o robô estiver quente ou se a tensão da bateria atingir cerca de 12,5V. Uma melhoria óbvia aqui seria integrar um carregador de bateria adequado, mas isso está fora do escopo deste Instructable.

O hardware:

Por favor, veja também as notas nas fotos. A caixa é montada na base do robô usando 4 parafusos M4 e porcas de travamento automático. Observe o tubo de borracha usado como espaçadores de distância. Esperançosamente, isso também dará alguma suspensão para o Duvel, caso o passeio se mostre acidentado. O módulo ESP32-CAM e a placa do motor L298N são montados na caixa usando pés adesivos de plástico (não tenho certeza do nome correto em inglês), para evitar a necessidade de fazer furos extras. Além disso, o ESP32 é montado em seu próprio perfboard e pinos conectáveis. Isso facilita a troca do ESP32.

Não se esqueça: se você for usar uma antena WiFi externa em vez da embutida, solde também o jumper de seleção de antena na parte inferior da placa ESP32-CAM.

Imprima o logotipo superior no arquivo DuvelBot.svg em papel adesivo para jato de tinta (ou crie o seu próprio) e você está pronto para começar!

Etapa 2: programar o robô

Programe o Robô
Programe o Robô

É aconselhável programar o robô antes de fechá-lo, para garantir que tudo funcione e que nenhuma fumaça mágica apareça.

Você precisa das seguintes ferramentas de software:

  • O IDE Arduino,
  • As bibliotecas ESP32, SPIFFS (sistema de arquivo flash periférico serial), biblioteca ESPAsync Webserver.

O último pode ser instalado seguindo este randomnerdtutorial até e incluindo a seção "organizando seus arquivos". Eu realmente não poderia explicar melhor.

O código:

Meu código pode ser encontrado em:

  • Um esboço do Arduino DuvelBot.ino,
  • Uma subpasta de dados que contém os arquivos que serão carregados no flash ESP usando SPIFFS. Essa pasta contém a página da web que o ESP servirá (index.html), uma imagem do logotipo que faz parte da página da web (duvel.png) e uma folha de estilo em cascata ou arquivo CSS (style.css).

Para programar o robô:

  • Conecte o conversor USB-TTL conforme mostrado no esquema,
  • Arquivo -> Abrir -> vá para a pasta onde DuvelBot.ino está.
  • Altere suas credenciais de rede no esboço:

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

  • Ferramentas -> Placa -> "AI-Thinker ESP-32 CAM" e selecione a porta serial apropriada para o seu pc (Ferramentas -> Porta -> algo como / dev / ttyUSB0 ou COM4),
  • Abra o monitor serial no IDE do Arduino, enquanto pressiona o botão PROG (que puxa o IO0 para baixo), ligue o robô,
  • Verifique no monitor serial se o ESP32 está pronto para download,
  • Feche o monitor serial (caso contrário, o upload do SPIFFS falhará),
  • Ferramentas -> "Carregamento de dados do esboço ESP32" e aguarde a conclusão,
  • Desligue e ligue novamente segurando o botão PROG para retornar ao modo de programação,
  • Pressione a seta "Upload" para programar o esboço e espere que ele termine,
  • Abra o monitor serial e reinicie o ESP32 desligando / ligando,
  • Depois de inicializar, anote o endereço IP (algo como 192.168.0.121) e desconecte o robô do conversor USB-TTL,
  • Abra um navegador neste endereço IP. Você deve ver a interface como na imagem.
  • Opcional: defina o endereço mac do ESP32 para um endereço IP fixo em seu roteador (depende de como fazer o roteador).

É isso! Continue lendo se quiser saber como funciona …

Etapa 3: como funciona

Agora chegamos à parte interessante: como tudo funciona junto?

Vou tentar explicar passo… a… passo, mas lembre-se de que Kajnjaps não é um especialista em programação web. Na verdade, aprender um pouco de programação web foi a premissa para construir o DuvelBot. Se eu cometer erros óbvios, por favor, deixe um comentário!

Ok, depois que o ESP32 é ligado, como de costume na configuração, ele inicializa os GPIOs, associa-os aos temporizadores PWM para controle do motor e LED. Veja aqui mais informações sobre o controle do motor, é bastante padrão.

Em seguida, a câmera é configurada. Eu deliberadamente mantive a resolução bem baixa (VGA ou 640x480) para evitar uma resposta lenta. Observe que a placa AI-Thinker ESP32-CAM tem um chip ram serial (PSRAM) que usa para armazenar quadros de câmera de resolução maior:

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

Em seguida, o sistema de arquivo flash periférico serial (SPIFFS) é inicializado:

// inicializar SPIFFS if (! SPIFFS.begin (true)) {Serial.println ("Ocorreu um erro ao montar SPIFFS!"); Retorna; }

O SPIFFS atua como um pequeno sistema de arquivos no ESP32. Aqui, ele é usado para armazenar três arquivos: a própria página da web index.html, um arquivo em cascata stylesheet style.css e um logo de imagem-p.webp

Em seguida, o ESP32 se conecta ao seu roteador (não se esqueça de definir suas credenciais antes de fazer o upload):

// altere as credenciais do seu roteador hereconst char * ssid = "yourNetworkSSIDHere"; const char * password = "yourPasswordHere"; … // conectar ao WiFi Serial.print ("Conectando ao WiFi"); WiFi.begin (ssid, senha); while (WiFi.status ()! = WL_CONNECTED) {Serial.print ('.'); atraso (500); } // agora conectado ao roteador: ESP32 agora tem endereço IP

Para fazer algo realmente útil, iniciamos um servidor da web assíncrono:

// cria um objeto AsyncWebServer na porta 80AsyncWebServer server (80); … Server.begin (); // comece a escutar conexões

Agora, se você digitar o endereço IP que foi atribuído ao ESP32 pelo roteador na barra de endereços de um navegador, o ESP32 receberá uma solicitação. Isso significa que ele deve responder ao cliente (você ou seu navegador) servindo-o de algo, por exemplo, uma página da web.

O ESP32 sabe como responder, porque na configuração as respostas a todas as solicitações permitidas possíveis foram registradas usando server.on (). Por exemplo, a página da web principal ou índice (/) é tratado assim:

server.on ("/", HTTP_GET, (AsyncWebServerRequest * pedido) {Serial.println ("/ pedido recebido!"); pedido-> enviar (SPIFFS, "/index.html", String (), falso, processador);});

Portanto, se o cliente se conectar, o ESP32 responderá enviando o arquivo index.html do sistema de arquivos SPIFFS. O processador de parâmetros é o nome de uma função que pré-processa o html e substitui quaisquer tags especiais:

// Substitui marcadores de posição no html como% DATA% // pelas variáveis que você deseja mostrar //

Dados:% DATA%

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

Agora, vamos examinar a própria página index.html. Em geral, há sempre três partes:

  1. código html: quais elementos devem ser mostrados (botões / texto / controles deslizantes / imagens etc.),
  2. código de estilo, em um arquivo.css separado ou em uma seção …: como os elementos devem ser,
  3. seção javascript a…: como a página da web deve atuar.

Depois que index.html é carregado no navegador (que sabe que é html por causa da linha DOCTYPE), ele é executado nesta linha:

Essa é uma solicitação para uma folha de estilo css. A localização desta folha é fornecida em href = "…". Então, o que seu navegador faz? Certo, ele lança outra solicitação para o servidor, desta vez para style.css. O servidor captura esta solicitação, porque ela foi registrada:

server.on ("/ style.css", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("css request received"); request-> send (SPIFFS, "/style.css", "text / css ");});

Legal hein? A propósito, poderia ser href = "/ algum / arquivo / no / outro / lado / da / / lua", para todos os problemas do seu navegador. Ele iria buscar aquele arquivo com a mesma felicidade. Não vou explicar sobre a folha de estilo, pois ela apenas controla as aparências, então não é realmente interessante aqui, mas se você quiser aprender mais, verifique este tutorial.

Como o logotipo do DuvelBot aparece? Em index.html temos:

ao qual o ESP32 responde com:

server.on ("/ duvel", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("duvel logo request received!"); request-> send (SPIFFS, "/duvel.png", "image /-p.webp

..outro arquivo SPIFFS, desta vez uma imagem completa, conforme indicado por "image / png" na resposta.

Agora chegamos à parte realmente interessante: o código dos botões. Vamos nos concentrar no botão AVANÇAR:

FRENTE

O nome da classe = "…" é apenas um nome para vinculá-lo à folha de estilo para personalizar o tamanho, cor, etc. As partes importantes são onmousedown = "toggleCheckbox ('forward')" e onmouseup = "toggleCheckbox ('stop') " Estas constituem as ações do botão (o mesmo para ontouchstart / ontouchend, mas para telas sensíveis ao toque / telefones). Aqui, a ação do botão chama uma função toggleCheckbox (x) na seção de javascript:

função toggleCheckbox (x) {var xhr = new XMLHttpRequest (); xhr.open ("GET", "/" + x, verdadeiro); xhr.send (); // também poderia fazer algo com a resposta quando estiver pronto, mas não fazemos}

Assim, pressionar o botão Avançar resulta imediatamente na chamada toggleCheckbox ('encaminhar'). Esta função então lança um XMLHttpRequest "GET", da localização "/ forward" que age como se você tivesse digitado 192.168.0.121/forward na barra de endereços do seu navegador. Assim que esta solicitação chega ao ESP32, ela é tratada por:

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

Agora, o ESP32 simplesmente responde com um texto "OK para a frente". Observe que toggleCheckBox () não faz nada com (ou espera) esta resposta, no entanto, poderia, conforme mostrado mais tarde no código da câmera.

Durante esta resposta, o programa apenas define uma variável actionNow = FORWARD, como resposta ao pressionar o botão. Já no mainloop do programa, essa variável é monitorada com o objetivo de aumentar / diminuir o PWM dos motores. A lógica é: enquanto tivermos uma ação que não seja STOP, acelere os motores nessa direção até que um determinado número (dutyCycleMax) seja alcançado. Em seguida, mantenha essa velocidade, contanto que a ação agora não tenha mudado:

loop vazio () {currentMillis = millis (); if (currentMillis - previousMillis> = dutyCycleStepDelay) {// salvar a última vez que você executou o loop previousMillis = currentMillis; // o mainloop é responsável por acelerar / desacelerar os motores if (actionNow! = previousAction) {// desacelerar, parar, alterar a ação e aumentar dutyCycleNow = dutyCycleNow-dutyCycleStep; if (dutyCycleNow <= 0) {// se após a desaceleração dc for 0, defina para a nova direção, comece em min dutycycle setDir (actionNow); previousAction = actionNow; dutyCycleNow = dutyCycleMin; }} else // actionNow == previousAction ramp up, exceto quando a direção for STOP {if (actionNow! = STOP) {dutyCycleNow = dutyCycleNow + dutyCycleStep; if (dutyCycleNow> dutyCycleMax) dutyCycleNow = dutyCycleMax; } else dutyCycleNow = 0; } ledcWrite (pwmChannel, dutyCycleNow); // ajustar o ciclo de trabalho do motor}}

Isso aumenta lentamente a velocidade dos motores, em vez de apenas lançar em velocidade total e derramar o precioso Duvel. Uma melhoria óbvia seria mover este código para uma rotina de interrupção do cronômetro, mas ele funciona como está.

Agora, se liberarmos o botão Avançar, seu navegador chamará toggleCheckbox ('parar'), resultando em uma solicitação para GET / parar. O ESP32 configura actionNow para STOP (e responde com "OK, pare."), O que faz com que o loop principal diminua a rotação dos motores.

E quanto aos LEDs? Mesmo mecanismo, mas agora temos um controle deslizante:

No javascript, a configuração do controle deslizante é monitorada, de forma que a cada mudança aconteça uma chamada para obter "/ LED / xxx", onde xxx é o valor de brilho que os LEDs devem ser configurados em:

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

Observe que usamos document.getElementByID ('slide') para obter o próprio objeto slider, que foi declarado com e que o valor é enviado para um elemento de texto com a cada alteração.

O manipulador no esboço captura todas as solicitações de brilho usando "/ LED / *" no registro do manipulador. Em seguida, a última parte (um número) é dividida e convertida em um int:

server.on ("/ LED / *", HTTP_GET, (solicitação AsyncWebServerRequest *) {Serial.println ("solicitação led recebida!"); setLedBrightness ((solicitação-> url ()). substring (5).toInt ()); solicitação-> enviar (200, "texto / simples", "OK Leds.");});

Semelhante ao descrito acima, os radiobuttons controlam variáveis que definem os padrões do PWM, de modo que o DuvelBot pode ir devagar até você com a cerveja, com cuidado para não derramar o ouro líquido, e voltar rapidamente para a cozinha para buscar um pouco mais.

… Então, como a imagem da câmera é atualizada sem você ter que atualizar a página? Para isso utilizamos uma técnica chamada AJAX (Asynchronous JavaScript and XML). O problema é que normalmente uma conexão cliente-servidor segue um procedimento fixo: cliente (navegador) faz a solicitação, servidor (ESP32) responde, caso encerrado. Feito. Nada acontece mais. Se ao menos pudéssemos enganar o navegador para solicitar atualizações regularmente do ESP32 … e isso é exatamente o que faremos com este 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) {// veja: 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); // criar um objeto a partir do blob document.querySelector ("# camimage"). src = imageUrl; urlCreator.revokeObjectURL (imageurl)}}; xhttp.send ();}, 250);

setInterval toma como parâmetro uma função e a executa de vez em quando (aqui, uma vez a cada 250ms, resultando em 4 quadros / segundo). A função executada solicita um "blob" binário no endereço / CÂMERA. Isso é tratado pelo ESP32-CAM no esboço como (de Randomnerdtutorials):

server.on ("/ CAMERA", HTTP_GET, (AsyncWebServerRequest * request) {Serial.println ("camera request received!"); camera_fb_t * fb = NULL; // esp_err_t res = ESP_OK; size_t _jpg_buf_len = 0; uint8_t * _jpg_buf = NULL; // captura um quadro fb = esp_camera_fb_get (); if (! fb) {Serial.println ("O buffer de quadro não pôde ser adquirido"); return;} if (fb-> format! = PIXFORMAT_JPEG) / / já neste formato de config {bool jpeg_converted = frame-j.webp

As partes importantes são obter o frame fb = esp_camera_fb_get () convertê-lo em um-j.webp

A função javascript então espera que esta imagem chegue. Em seguida, basta um pouco de trabalho para converter o "blob" recebido em um url que pode ser usado como uma fonte para atualizar a imagem na página html.

ufa, terminamos!

Etapa 4: ideias e sobras

Ideias e sobras
Ideias e sobras

O objetivo deste projeto para mim era aprender programação web o suficiente para fazer a interface do hardware com a web. Várias extensões para este projeto são possíveis. Aqui estão algumas idéias:

  • Implemente o streaming de câmera 'real' conforme explicado aqui e aqui e mova-o para um segundo servidor conforme explicado aqui no mesmo ESP32, mas no outro núcleo da CPU, em seguida, importe o camerastream para o html servido pelo primeiro servidor usando um…. Isso deve resultar em atualizações mais rápidas da câmera.
  • Use o modo de ponto de acesso (AP) para que o robô seja mais autônomo, conforme explicado aqui.
  • Expanda com medição de tensão de bateria, recursos de sono profundo etc. Isso é um pouco difícil no momento porque o AI-Thinker ESP32-CAM não tem muitos GPIOs; precisa de expansão via uart e, por exemplo, um arduino escravo.
  • Converta-se em um robô em busca de gatos que ejeta guloseimas para gatos de vez em quando ao pressionar um grande botão com a pata, transmita toneladas de belas fotos de gatos durante o dia …

Por favor, comente se gostou ou tiver dúvidas e obrigado pela leitura!

Recomendado: