Recents in Beach


Receba o meu conteúdo GRATUITAMENTE


Câmera PANTILT com ESP32


Hoje vou te apresentar o PANTILT, que é um dispositivo que possibilita o movimento de uma câmera para cima, para baixo e para os lados. Eu mesmo produzi esse dispositivo através de peças impressas em 3D, usando dois servos e o ESP32, que possibilita o controle deste mecanismo através do WiFi. Vamos, então, realizar leituras usando os canais AD dos ESP32, bem como uma atuação analógica usando o controlador interno LED_PWM. Ainda, aplicamos o controle através de uma conexão TCP/IP.


No vídeo você confere que eu tenho um ESP32 lendo os valores dos dois potenciômetros, os quais são enviados, via WiFi, a outro ESP32, este ligado aos dois servos motores. Os movimentos da câmera presa ao PANTILT, para cima, para baixo ou para os lados, dependem do controle que você faz através dos potenciômetros.
O link com o desenho do PAN TILT para impressão em 3D:




Recursos usados

·         Vários jumpers para conexão
·         Dois Node MCU ESP32S
·         Dois cabos USB para os ESP32
·         Uma WebCam para controle
·         Dois potenciômetros para controle
·         Um protoboard.
·         Uma fonte para os servos.




NodeMCU ESP32S  - Pinout




Periféricos do ESP32

Periféricos de PWM
O ESP32 possui dois periféricos capazes de gerar sinais PWM. O Motor Control Pulse Width Modulator (MCPWM) desenhado para controle de potência e motores, e o LED_PWM, desenvolvido para controle de intensidade de leds, mas que pode ser usado também de modo genérico.
Utilizaremos o LED_PWM que pode gerar 16 canais independentes de PWM com períodos e ciclos de trabalho configuráveis e até 16bits de resolução.




PWM de controle do servo motor

O controle do servo motor é realizado através do ajuste da modulação da largura de pulso de uma onde quadrada de frequência específica.
Para o servo utilizado (bem como para a maioria), a frequência é de 50Hz, e uma largura de 1 a 2ms de duração do pulso determina a posição angular do servo.
Vamos direcionar o canal 0 do LED_PWM para o GPIO13 e o canal 1 para o GPIO12, usando estas informações para efetuar o controle.




Captura analógica

Periférico de conversão analógica para digital
O ESP32 possui conversores analógico-digitais de aproximação sucessiva que podem ser aplicados em até 18 canais, mas somente nos GPIOs habilitados para analógico.
A tensão aplicada não deve exceder a faixa de 0 a 3V.
A conversão realizada não mantem um erro constante para todas as tensões amostradas dependendo da faixa configurada. Para uma faixa de 150mV a 2,450V é necessária uma verificação do comportamento  em aplicações mais críticas.
Para a captura usaremos um potenciômetro de 10k como divisor de tensão.  A captura será feita no canal ADC0 e ADC3, acessíveis pelo GPIO36 e GPIO39.




Circuito – Servidor e Cliente




Código – Fonte do Ponto de Acesso e Servidor

Declarações

Incluo a biblioteca do WiFi e defino algumas variáveis.

#include <WiFi.h>  // inclusão da biblioteca WiFi

const int freq = 50; //frequência do PWM
const int canal_A = 0; //primeiro canal do controlador LED_PWM
const int canal_B = 1; //segundo canal do controlador LED_PWM
const int resolucao = 12; //Resolução usado no controlador LED_PWM

const int pin_Atuacao_A = 13; //Pino para onde o canal 0 será redirecionado
const int pin_Atuacao_B = 12; //Pino para onde o canal 1 será redirecionado

const  char* ssid =  "ESP32ap" ; //constante com o SSID do WiFi do ponto de acesso ESP32
const  char* password =  "12345678" ; //senha para confirmação de conexão no ponto de acesso
const int port = 2; //porta na qual o servidor receberá as conexões

int ciclo_A = 0; //variável que receberá o ciclo de atuação do canal A
int ciclo_B = 0; //variável que receberá o ciclo de atuação do canal A

WiFiServer server(port); //declaração do objeto servidor
IPAddress myIP; //declaração da variável de IP


Setup()

Definimos, aqui, os pinos de saída. Ajustamos os canais para a frequência desejada e definimos o valor do PWM.

void setup()
{
  pinMode(pin_Atuacao_A, OUTPUT); //definindo o pino de atuação A como saída
  pinMode(pin_Atuacao_B, OUTPUT); //definindo o pino de atuação B como saída

  ledcSetup(canal_A, freq, resolucao); //Ajustando o canal 0 para frequência de 50 Hz e resolução de 12bits
  ledcSetup(canal_B, freq, resolucao); //Ajustando o canal 1 para frequência de 50 Hz e resolução de 12bits
  ledcAttachPin(pin_Atuacao_A, canal_A); //redirecionando o canal 0 para o pino 13
  ledcAttachPin(pin_Atuacao_B, canal_B); //redirecionando o canal 1 para o pino 12
  ledcWrite(canal_A, ciclo_A); //definindo o valor do PWM para 0
  ledcWrite(canal_B, ciclo_B); //definindo o valor do PWM para 0


Iniciamos a serial, o ponto de acesso com SSID ESP32ap e senha. Obtemos, então, o IP do servidor e iniciamos o servidor.

 Serial.begin(115200); //iniciando a Serial
  Serial.println("Iniciando ponto de acesso: " + String(ssid)); //mensagem
  WiFi.softAP (ssid, password); //iniciando o ponto de acesso com SSID ESP32ap e senha 12345678

  Serial.println("Obtendo IP"); //mensagem
  myIP = WiFi.softAPIP (); //obtendo o IP do servidor (como não foi configurado deverá ser o padrão de fábrica)
  Serial.println("IP: " + WiFi.localIP()); //mensagem

  Serial.println("Iniciando servidor em: " + String(port)); //mensagem
  server.begin(); //iniciando o servidor
}


Loop()

No Loop, primeira coisa que vamos fazer é instanciar o client, conectando e associando à variável cliente. Verifico se há cliente conectado. Em caso positivo, iniciamos a variável que receberá os dados. Enquanto a conexão estiver estabelecida, e se houver dados a receber, executamos a leitura dos caracteres para a variável c. Por fim, concatenamos c na variável dados.

void loop() {

  WiFiClient cliente = server.available(); //se um cliente conectar, associe a variável cliente

  if (cliente.connected()) { //se há um cliente conectado
    String dados = ""; //inicia a variável que receberá os dados
    Serial.println("Cliente conectado."); //mensagem
    while (cliente.connected()) { //enquanto a conexão estiver estabelecida
      if (cliente.available()) { //e se houver dados a receber
        char c = cliente.read(); //leia os caracteres para a variável c
        dados = dados + c; //concatene c na variável dados


Se um caracter de nova linha for recebido, procuramos pelo índice do caracter ',' na string em dados. Obtemos as substrings antes e depois da vírgula e convertemos para inteiro. Ajustamos o PWM dos canais A e B. Limpamos a variável.

 if (c == '\n') { //se um caracter de nova linha for recebido

          int virgula = dados.indexOf(','); //procure pelo índice do caracter ',' na string em dados
          ciclo_A = (dados.substring(0, virgula)).toInt(); //obtenha a substring até antes da vírgula e converta para inteiro
          ciclo_B = dados.substring(virgula + 1, dados.length()).toInt();//obtenha a substring após a vírgula e converta para inteiro

          ledcWrite(canal_A, ciclo_A); //Ajusta o PWM do canal A
          ledcWrite(canal_B, ciclo_B); //Ajusta o PWM do canal B
          dados = ""; //Limpa a variável

        }
      }
    }
  }


Caso o cliente se desconecte, confirmamos o fim da conexão. Aguardamos um instante e imprimimos "Nenhum cliente conectado". Aguardamos mais um segundo antes de reiniciar.

// caso o cliente se desconecte, confirma o fim da conexão
  delay(50); //aguarda um momento
  cliente.stop();
  Serial.println("Nenhum cliente conectado."); //mensagem
  delay(1000); //aguarda um segundo antes de reiniciar
}


Código – Fonte do Cliente

Declarações

Incluímos novamente a biblioteca WiFi, desta vez no cliente, além de definirmos as variáveis.

#include <WiFi.h>

const char* ssid     = "ESP32ap"; //SSID do ponto de acesso ESP32
const char* password = "12345678"; //Senha para acessar o ponto de acesso

const uint16_t port = 2; //Porta de escuta do servidor
const char * host = "192.168.4.1"; //endereço IP do servidor

const int pin_Leitura_A = 36; //GPIO de leitura do ADC0
const int pin_Leitura_B = 39; //GPIO de leitura do ADC3

int ciclo_A = 0; //variável que receberá o valor do ciclo do PWM A
int ciclo_B = 0; //Variável que receberá o valor do ciclo do PWM B

WiFiClient cliente; //declaração do objeto cliente


Setup()

Definimos os GPIOs como entrada, iniciamos a serial e conectamos ao ponto de acesso.

void setup()
{
  pinMode(pin_Leitura_A, INPUT); //define o GPIO como entrada
  pinMode(pin_Leitura_B, INPUT); //define o GPIO como entrada

  Serial.begin(115200); //inicia a comunicação serial
  WiFi.begin(ssid, password); //conecta ao ponto de acesso
}


Loop()

Neste Loop, vamos nos conectar ao server, ou seja, ao outro ESP.

void loop()
{
  //se não conectado ao ponto de acesso, tenta se conectar
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(String(millis()) + " - Conectando no WiFi " + ssid + "..."); //mensagem
    WiFi.begin(ssid, password);
    delay(2000);
  }
  Serial.println(String(millis()) + " - Conectado..."); //mensagem
  //se não conectado ao servidor, tenta se conectar
  while (!cliente.connect(host, port)) {
    Serial.println(String(millis())  + " - Conectando no Servidor " + host + ":" + port + "..."); //mensagem
    delay(1000);
  }


Nesta etapa, enquanto estiver conectado ao servidor, executamos a leitura do ADC0 e do ADC3 e armazenamos nas respectivas variáveis. No total, capturamos 500 amostras de cada e delas tiramos a média.

//enquanto estiver conectado ao servidor
  while (cliente.connected()) {
    int leitura_A = 0; //variável para armazenar a leitura do ADC0
    int leitura_B = 0; //variável para armazenar a leitura do ADC3
    int amostras = 500; //número de amostras
    int contador = 0; //contador de amostras

    while (contador < amostras) { //acumua várias leituras
      leitura_A = leitura_A + analogRead(pin_Leitura_A);
      leitura_B = leitura_B + analogRead(pin_Leitura_B);
      contador++;
    }
    leitura_A = leitura_A / amostras; //média das leituras
    leitura_B = leitura_B / amostras;

    ciclo_A = map(leitura_A, 0, 4095, 140, 490); //mapeia a leitura para criar a duração correta para controle do servo
    ciclo_B = map(leitura_B, 0, 4095, 140, 490); //mapeia a leitura para criar a duração correta para controle do servo
    //concatena e envia para o servidor
    cliente.println(String(ciclo_A) + "," + String(ciclo_B));

  }


Por fim, se não conectado, garantimos que a conexão foi finalizada expondo a mensagem equivalente.

//se não coonectado, garante que a conexão foi finalizada
  cliente.stop();
  Serial.println(String(millis()) + " - cliente desconectado..."); //mensagem
}





Faça o download dos arquivos:







Postar um comentário

3 Comentários

  1. Muto bom, este projeto! Vou testa-lo com do Esp32 que tenho aqui. Gostaria que Senhor pudesse colocar projetos usando o protocolo mqtt com os esp32, para que possamos controlar motores, ventiladores e lâmpada a distância usando o app mqtt dash.

    ResponderExcluir
  2. Olá. boa noite! Excelente tutorial! Teria como fazer os movimentos especificando em graus ao invés de utilizar potenciômetros? Obrigado.

    ResponderExcluir
  3. Fernando, teria como fazer só com 1 ESP32 com reconhecimento de Face/objeto/Pessoa?
    Exemplo simples seria por uma câmera ligada a um ESP32 que siga a pessoa automaticamente!
    já consegui fazer isso a um tempo com raspberry, mas descontinuei o projeto por limitação do Raspberry, Já com o ESP32 vejo o Potencial para isso funcionar sem problemas. mas meus Dias estão literalmente um Caos e sem tempo para realizar os projetos de automação. mas isso eu gostaria de fazer e ou ver funcionando.. seria uma realização..

    ResponderExcluir