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:
3 Comentários
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.
ResponderExcluirOlá. boa noite! Excelente tutorial! Teria como fazer os movimentos especificando em graus ao invés de utilizar potenciômetros? Obrigado.
ResponderExcluirFernando, teria como fazer só com 1 ESP32 com reconhecimento de Face/objeto/Pessoa?
ResponderExcluirExemplo 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..