IoT, Conectividade e Controle Inteligente
Conclusão do Nível 1 ou conhecimento equivalente
Você deve estar confortável com:
10 horas • 4 aulas
_# Módulo 2.1: Aprofundando no ESP32
No Nível 1, você construiu um robô funcional e aprendeu os fundamentos da programação e eletrônica. Agora, no Nível 2, vamos mergulhar em conceitos mais avançados para tornar nossos robôs mais inteligentes e autônomos. Começaremos explorando todo o potencial do ESP32, o cérebro poderoso que já estamos usando.
Enquanto o Arduino UNO é fantástico para começar, o ESP32 é uma plataforma muito mais robusta, projetada para a era da Internet das Coisas (IoT). Suas principais vantagens são o processamento dual-core e, mais importante, a conectividade sem fio integrada.
Figura 1: Diagrama de pinagem detalhado de um ESP32 DevKit, mostrando a vasta quantidade de periféricos disponíveis.
---
| Característica | Arduino UNO (ATmega328P) | ESP32 (Xtensa LX6) |
|---|---|---|
| Processador | Single-Core 8-bit @ 16 MHz | Dual-Core 32-bit @ 240 MHz |
| Memória RAM | 2 KB | 520 KB |
| Memória Flash | 32 KB | 4 MB (ou mais) |
| Conectividade | Nenhuma (requer shields) | Wi-Fi 802.11 b/g/n e Bluetooth 4.2/BLE |
| Pinos GPIO | 14 Digitais, 6 Analógicos | Até 34, com múltiplas funções (ADC, DAC, Touch, etc.) |
| Tensão de Operação | 5V | 3.3V |
Essa superioridade em hardware permite que o ESP32 execute tarefas muito mais complexas, como:
O ESP32 possui dois núcleos de processamento que podem executar tarefas de forma independente. Isso é extremamente útil em robótica. Podemos, por exemplo, dedicar um núcleo para tarefas críticas de tempo real (como o controle dos motores e a leitura de sensores), enquanto o outro núcleo cuida da comunicação Wi-Fi e da interface do usuário. Essa divisão evita que a conexão de rede interfira na estabilidade do robô.
---
Além dos pinos digitais e analógicos, o ESP32 oferece uma gama de periféricos avançados:
UART), o ESP32 suporta I2C e SPI, protocolos para se comunicar com centenas de sensores e outros chips usando poucos fios.---
Vamos criar um projeto que demonstra o poder do ESP32. Construiremos um servidor web que não apenas controla um LED, mas também exibe o status de um pino (como um botão) e o tempo que o ESP32 está ligado (uptime).
GND.GND. Conecte o outro terminal do botão ao 3.3V do ESP32.#include <WiFi.h>
// Configurações de Rede
const char* ssid = "SEU_WIFI"; // <<< COLOQUE O NOME DA SUA REDE
const char* password = "SUA_SENHA"; // <<< COLOQUE A SENHA DA SUA REDE
WiFiServer server(80);
// Pinos dos componentes
const int pinoLed = 26;
const int pinoBotao = 25;
void setup() {
Serial.begin(115200);
pinMode(pinoLed, OUTPUT);
pinMode(pinoBotao, INPUT);
// Conecta ao Wi-Fi
Serial.print("Conectando a ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado!");
Serial.print("Endereço IP: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
String req = client.readStringUntil('\r');
// Controle do LED
if (req.indexOf("/led/on") != -1) {
digitalWrite(pinoLed, HIGH);
} else if (req.indexOf("/led/off") != -1) {
digitalWrite(pinoLed, LOW);
}
// Monta a página HTML
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html><html><head><title>ESP32 Web Server</title>");
client.println("<meta http-equiv=\"refresh\" content=\"5\">"); // Atualiza a página a cada 5s
client.println("</head><body><h1>Status do ESP32</h1>");
client.print("<p>Uptime: ");
client.print(millis() / 1000);
client.println(" segundos</p>");
client.print("<p>Status do Botão: ");
client.print(digitalRead(pinoBotao) == HIGH ? "Pressionado" : "Solto");
client.println("</p>");
client.println("<p>Controle do LED:</p>");
client.println("<a href=\"/led/on\"><button>Ligar</button></a>");
client.println("<a href=\"/led/off\"><button>Desligar</button></a>");
client.println("</body></html>");
}
}
Resultado Esperado:
"SEU_WIFI" e "SUA_SENHA" para os dados da sua rede Wi-Fi.Você verá uma página que mostra há quanto tempo o ESP32 está ligado e o estado do botão. A página se atualizará automaticamente a cada 5 segundos. Os botões na página permitirão que você ligue e desligue o LED remotamente.
Este projeto demonstra como o ESP32 pode atuar como um dispositivo de IoT completo, servindo uma interface de usuário e interagindo com o hardware simultaneamente. No próximo módulo, vamos aprofundar na criação de interfaces web mais ricas e na comunicação sem fio.
10 horas • 5 aulas
_# Módulo 2.2: Comunicação Sem Fio e Interfaces Web
No projeto anterior, usamos o ESP32 no modo Station (STA), onde ele se conecta a uma rede Wi-Fi existente, como um celular ou computador. No projeto do Nível 1 (Rover de Papel), usamos o modo Access Point (AP), onde o ESP32 cria sua própria rede Wi-Fi.
Compreender a diferença é fundamental para a robótica conectada:
| Modo | Descrição | Vantagens | Desvantagens |
|---|---|---|---|
| Station (STA) | O ESP32 é um cliente em uma rede maior (seu roteador de casa). | Acesso à internet, comunicação com outros dispositivos na rede. | Depende de uma rede Wi-Fi existente. |
| Access Point (AP) | O ESP32 é o roteador, criando sua própria rede. | Autocontido, funciona em qualquer lugar sem infraestrutura externa. | Sem acesso à internet, apenas dispositivos conectados diretamente a ele podem se comunicar. |
| AP + STA | Modo híbrido onde o ESP32 cria sua rede e simultaneamente se conecta a outra. | O melhor dos dois mundos: oferece um ponto de acesso para configuração e ainda se conecta à internet. | Mais complexo de gerenciar. |
Para robôs móveis, o modo AP é excelente para controle direto em campo, enquanto o modo STA é ideal para robôs que precisam buscar informações da internet ou serem controlados de qualquer lugar do mundo.
---
Quando você acessa uma página no seu navegador, seu dispositivo está fazendo uma requisição HTTP para um servidor. O servidor então envia de volta uma resposta HTTP, que contém o conteúdo da página (geralmente HTML, CSS e JavaScript).
GET /led/on.HTTP/1.1 200 OK seguido do código HTML.Nosso ESP32 atua como um mini servidor web. Ele escuta por requisições e responde de acordo com a lógica que programamos.
No código anterior, o HTML e o CSS estavam misturados em uma única String no código C++, o que é difícil de manter. Uma abordagem muito mais limpa é armazenar o HTML em uma variável separada usando a notação R"rawliteral(...)rawliteral" do C++. Isso permite escrever HTML de forma muito mais natural.
Figura 1: Um robô com ESP32-CAM sendo controlado por uma interface web sofisticada em um smartphone.
---
Vamos evoluir nosso web server para um dashboard mais completo. Ele terá botões que mudam de cor para refletir o estado do LED e usará um pouco de JavaScript para enviar comandos sem recarregar a página (uma técnica conhecida como AJAX), tornando a experiência muito mais fluida.
Materiais:Este código é mais longo, mas a maior parte é a página HTML e o JavaScript. A lógica no ESP32 continua simples.
#include <WiFi.h>
// ===== Configurações de Rede =====
const char* ssid = "SEU_WIFI";
const char* password = "SUA_SENHA";
WiFiServer server(80);
// ===== Pinos e Estado =====
const int pinoLed = 26;
bool estadoLed = false;
// ===== Página HTML com CSS e JavaScript =====
const char* HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>ESP32 Dashboard</title>
<style>
body { font-family: system-ui, sans-serif; text-align:center; margin: 24px; background-color: #f0f0f0; }
h1 { color: #333; }
.card { background-color: white; padding: 20px; border-radius: 12px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); max-width: 400px; margin: 20px auto; }
button { font-size: 18px; padding: 12px 24px; border: none; border-radius: 8px; cursor: pointer; transition: background-color 0.3s; }
.on { background-color: #2ecc71; color: white; }
.off { background-color: #e74c3c; color: white; }
</style>
</head>
<body>
<h1>Dashboard do Robô</h1>
<div class="card">
<h2>Controle do LED</h2>
<p>O LED está atualmente: <b id="status">DESLIGADO</b></p>
<button id="btnLigar" class="on" onclick="sendCommand('on')">LIGAR</button>
<button id="btnDesligar" class="off" onclick="sendCommand('off')">DESLIGAR</button>
</div>
<script>
function sendCommand(cmd) {
fetch('/led/' + cmd)
.then(response => response.text())
.then(data => {
document.getElementById('status').innerText = data;
});
}
</script>
</body>
</html>
)rawliteral";
void setup() {
pinMode(pinoLed, OUTPUT);
digitalWrite(pinoLed, LOW);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
server.begin();
}
void handleRequest(WiFiClient& client, String req) {
String response_content_type = "text/html";
String response_body = "";
if (req.startsWith("GET /led/on")) {
estadoLed = true;
digitalWrite(pinoLed, HIGH);
response_content_type = "text/plain";
response_body = "LIGADO";
} else if (req.startsWith("GET /led/off")) {
estadoLed = false;
digitalWrite(pinoLed, LOW);
response_content_type = "text/plain";
response_body = "DESLIGADO";
} else {
response_body = HTML_PAGE;
}
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: " + response_content_type + "; charset=utf-8");
client.println("Connection: close\r\n");
client.print(response_body);
}
void loop() {
WiFiClient client = server.available();
if (!client) return;
String req = client.readStringUntil('\r');
while (client.available()) client.read();
handleRequest(client, req);
delay(1);
}
Como o Código Funciona:
sendCommand(cmd) usa a API fetch() do navegador. Quando um botão é clicado, o JavaScript envia a requisição (ex: /led/on) para o ESP32 em segundo plano. Ele não recarrega a página inteira./led/on ou /led/off, ele muda o estado do LED e responde apenas com o novo status em texto puro (ex: "LIGADO"). Se ele recebe qualquer outra requisição, ele responde com a página HTML completa. com o ID "status", mudando o texto na tela sem piscar.Ao acessar o IP do seu ESP32, você verá um dashboard mais profissional. Clicar nos botões "LIGAR" e "DESLIGAR" mudará o estado do LED instantaneamente, e o texto de status na página será atualizado sem que a página inteira precise ser recarregada. Esta é a base para criar interfaces de controle de robôs muito mais responsivas e agradáveis de usar.
No próximo módulo, vamos adicionar mais "sentidos" ao nosso robô com sensores avançados.
8 horas • 3 aulas
_# Módulo 2.3: Sensores Avançados
No Nível 1, usamos o sensor ultrassônico para dar ao nosso robô uma percepção básica de distância. Agora, vamos equipá-lo com sentidos mais aguçados que permitem tarefas de navegação complexas, como seguir uma linha ou saber sua própria orientação no espaço.
O TCRT5000 é um sensor de refletância. Ele consiste em um LED infravermelho (emissor) e um fototransistor (receptor). O LED emite luz IR, que é refletida pela superfície abaixo do sensor e captada pelo fototransistor.
Ao ler a intensidade do sinal refletido, o robô pode distinguir entre uma linha preta e um fundo branco, tornando-se a base para um robô seguidor de linha.
Figura 1: Um módulo com o sensor TCRT5000. Ele já inclui o circuito necessário e um pino de saída digital e/ou analógico.
A IMU é um dos sensores mais poderosos para robótica. O MPU-6050 é um chip que combina dois sensores em um:
Combinando os dados desses dois sensores (um processo chamado de fusão de sensores), podemos obter uma estimativa muito precisa da orientação do robô no espaço (seu roll, pitch e yaw). Isso é crucial para realizar curvas precisas (ex: virar exatamente 90 graus) ou para manter o robô equilibrado.
Figura 2: Um módulo MPU-6050 conectado a um Arduino via protocolo I2C, que usa apenas dois fios de dados (SDA e SCL).
---
Vamos construir um programa que lê os dados do MPU-6050 e os exibe no Monitor Serial. Este é o primeiro passo para usar a IMU em um sistema de navegação.
Materiais Necessários:O MPU-6050 se comunica usando o protocolo I2C, que é muito conveniente pois usa apenas dois pinos de dados.
VCC do MPU-6050 ao pino 3.3V do ESP32. Conecte o GND do MPU-6050 ao GND do ESP32. - Conecte o pino SCL (Serial Clock) do MPU-6050 ao pino GPIO 22 do ESP32 (pino SCL padrão).
- Conecte o pino SDA (Serial Data) do MPU-6050 ao pino GPIO 21 do ESP32 (pino SDA padrão).
Primeiro, instale a biblioteca para o MPU-6050. Vá em Ferramentas > Gerenciar Bibliotecas e instale a biblioteca "Adafruit MPU6050" e suas dependências (como a "Adafruit BusIO" e a "Adafruit Unified Sensor").
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
// Cria um objeto para o sensor MPU6050
Adafruit_MPU6050 mpu;
void setup() {
Serial.begin(115200);
// Tenta inicializar o sensor
if (!mpu.begin()) {
Serial.println(\"Falha ao encontrar o chip MPU6050. Verifique as conexões!\");
while (1) {
delay(10);
}
}
Serial.println(\"MPU6050 Encontrado!\");
// Configura as faixas de medição (opcional)
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DPS);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
}
void loop() {
// Cria variáveis para armazenar os eventos (leituras) dos sensores
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
// Imprime os dados do Acelerômetro (em m/s^2)
Serial.print(\"Aceleração X: \");
Serial.print(a.acceleration.x);
Serial.print(\", Y: \");
Serial.print(a.acceleration.y);
Serial.print(\", Z: \");
Serial.print(a.acceleration.z);
Serial.println(\" m/s^2\");
// Imprime os dados do Giroscópio (em rad/s)
Serial.print(\"Rotação X: \");
Serial.print(g.gyro.x);
Serial.print(\", Y: \");
Serial.print(g.gyro.y);
Serial.print(\", Z: \");
Serial.print(g.gyro.z);
Serial.println(\" rad/s\");
Serial.println(\"---\" );
delay(500); // Pausa de meio segundo entre as leituras
}
Resultado Esperado:
Abra o Monitor Serial. Você verá um fluxo contínuo de dados do acelerômetro e do giroscópio. Tente mover e girar o sensor MPU-6050. Observe como os valores nos eixos X, Y e Z mudam de acordo com o movimento.
Entender e interpretar esses dados é o primeiro passo para criar algoritmos de controle sofisticados, que é exatamente o que faremos no próximo módulo.
10 horas • 4 aulas
_# Módulo 2.4: Algoritmos de Controle
Até agora, nossos robôs ou eram controlados diretamente por nós (teleoperados) ou tinham uma lógica de decisão muito simples (se a distância for menor que X, faça Y). Para criar robôs verdadeiramente autônomos, precisamos de algoritmos de controle: um conjunto de regras e cálculos que permitem ao robô tomar decisões inteligentes com base nos dados dos sensores para atingir um objetivo.
Neste módulo, vamos explorar dois algoritmos fundamentais: a lógica para seguir uma linha e o famoso controle PID.
---
Um dos desafios clássicos da robótica é construir um robô que possa seguir uma linha preta em um fundo branco. A lógica por trás disso é um excelente exercício de controle.
Imagine que nosso robô tem três sensores de linha (TCRT5000) na frente: um à esquerda, um no centro e um à direita.
Figura 1: Um robô autônomo precisa de algoritmos para interpretar os dados dos seus sensores e decidir como se mover.
A lógica de decisão pode ser descrita como uma série de regras "SE-ENTÃO":
| Leitura dos Sensores (Esquerda, Centro, Direita) | Situação | Ação do Robô |
|---|---|---|
| Branco, Preto, Branco | O robô está perfeitamente sobre a linha. | Mover para frente em velocidade normal. |
| Branco, Branco, Preto | O robô está desviando para a esquerda. | Virar para a direita para corrigir. |
| Preto, Branco, Branco | O robô está desviando para a direita. | Virar para a esquerda para corrigir. |
| Branco, Branco, Branco | O robô perdeu a linha (ou chegou a uma interrupção). | Parar ou iniciar uma rotina de busca. |
| Preto, Preto, Preto | O robô encontrou uma intersecção ou a linha de chegada. | Parar ou tomar uma decisão mais complexa. |
Este é um exemplo de uma máquina de estados finitos, onde o robô está sempre em um de vários estados possíveis e transita entre eles com base nas leituras dos sensores.
---
A lógica "SE-ENTÃO" funciona, mas muitas vezes resulta em um movimento oscilante, onde o robô ziguezagueia sobre a linha. Para um movimento suave e preciso, usamos um Controlador Proporcional-Integral-Derivativo (PID).
O PID é um algoritmo de controle de malha fechada amplamente utilizado na indústria e na robótica. Seu objetivo é minimizar o erro entre o estado atual de um sistema e o estado desejado (o setpoint).
No nosso robô seguidor de linha, o erro pode ser definido como a distância do sensor central até o centro da linha. O PID calcula uma saída de correção para os motores com base em três termos:
Figura 2: Um fluxograma de programa de robô. O controle PID se encaixa no passo de "Processar Dados" e "Tomar Decisão".
O termo Proporcional é a parte mais intuitiva. A correção é proporcional ao erro atual.
O Kp é uma constante de ganho que ajustamos. Um Kp muito alto causa oscilações; um Kp muito baixo torna o robô lento para reagir.
O termo Integral lida com o erro acumulado ao longo do tempo. Ele serve para corrigir pequenos erros persistentes que o termo P sozinho não consegue eliminar (erro de estado estacionário).
O Ki é a constante integral. Um Ki muito alto pode levar a uma correção exagerada e instabilidade.
O termo Derivativo olha para a taxa de variação do erro (a "velocidade" com que o erro está mudando). Ele tem um efeito de amortecimento, prevendo o erro futuro e agindo para evitar que a correção seja excessiva (overshoot).
O Kd é a constante derivativa. Ele ajuda a estabilizar o sistema e reduzir as oscilações.
A correção total aplicada aos motores é a soma dos três termos:
Correção_Final = (Kp erro) + (Ki soma_dos_erros) + (Kd * (erro_atual - erro_anterior))Esta Correção_Final é então usada para ajustar a velocidade dos motores esquerdo e direito, fazendo o robô seguir a linha de forma suave e eficiente.
---
Implementar um PID completo em hardware requer um ajuste cuidadoso (chamado de tuning) das constantes Kp, Ki e Kd. Antes de colocar no robô, vamos fazer um programa simples que simula a lógica do PID no Monitor Serial.
Materiais:Este código simula um sistema (como nosso robô) que tenta alcançar um setpoint (ponto desejado) de 100.
// Variáveis do sistema simulado
double setpoint = 100.0; // O valor que queremos alcançar
double valorAtual = 0.0; // O valor atual do sistema
double saidaMotor = 0.0; // A "força" aplicada ao sistema
// Constantes do PID (Tuning)
double Kp = 0.5;
double Ki = 0.2;
double Kd = 0.1;
// Variáveis do PID
double erro;
double erroAnterior = 0;
double integral = 0;
double derivativo;
unsigned long tempoAnterior;
void setup() {
Serial.begin(115200);
tempoAnterior = millis();
}
void loop() {
unsigned long tempoAtual = millis();
double dt = (double)(tempoAtual - tempoAnterior) / 1000.0; // Delta T em segundos
tempoAnterior = tempoAtual;
// ===== Lógica do PID =====
erro = setpoint - valorAtual;
integral += erro * dt;
derivativo = (erro - erroAnterior) / dt;
erroAnterior = erro;
// Calcula a saída do PID
double saidaPID = (Kp erro) + (Ki integral) + (Kd * derivativo);
// ===== Simulação do Sistema =====
// A saída do PID afeta o valor atual do sistema (simulando o motor empurrando o robô)
valorAtual += saidaPID * dt;
// Imprime os resultados
Serial.print("Setpoint: "); Serial.print(setpoint);
Serial.print(" | Valor Atual: "); Serial.print(valorAtual);
Serial.print(" | Erro: "); Serial.print(erro);
Serial.print(" | Saída PID: "); Serial.println(saidaPID);
// Para a simulação quando chegar perto do setpoint
if (abs(erro) < 0.1) {
Serial.println("\nSetpoint alcançado! Fim da simulação.");
while(true) delay(1000);
}
delay(100);
}
Resultado Esperado:
Abra o Monitor Serial. Você verá o Valor Atual começar em 0 e gradualmente se aproximar do Setpoint de 100. Observe como a Saída PID é alta no início (quando o erro é grande) e diminui à medida que o Valor Atual se aproxima do Setpoint.
Experimente mudar os valores de Kp, Ki e Kd:
Kp: o sistema responderá mais rápido, mas pode passar do setpoint e oscilar.Ki: o sistema eliminará erros pequenos mais rápido, mas pode se tornar instável.Kd: o sistema ficará mais estável e com menos oscilações.Entender essa dinâmica é a chave para aplicar o PID em projetos reais. No projeto final deste nível, usaremos essa lógica para criar um robô autônomo que navega com precisão.
8 horas • 3 aulas
_# Módulo 2.5: Alimentação e Gestão de Energia
Um robô autônomo só é verdadeiramente autônomo se puder carregar sua própria fonte de energia. No Nível 1, usamos um power bank, que é uma solução simples e eficaz. No entanto, para robôs mais compactos e integrados, precisamos de um sistema de alimentação dedicado. Este módulo aborda os fundamentos da gestão de energia para robôs móveis.
A escolha da bateria é uma das decisões mais críticas no design de um robô. Ela afeta o peso, a autonomia e a segurança do projeto.
| Tipo de Bateria | Vantagens | Desvantagens |
|---|---|---|
| Alcalinas (AA, AAA) | Baratas, fáceis de encontrar. | Não recarregáveis, baixa capacidade de corrente. |
| NiMH (Níquel-Hidreto Metálico) | Recarregáveis, mais seguras que Li-Ion. | Menor densidade de energia, efeito memória (em modelos antigos). |
| Li-Ion (Íon de Lítio) / Li-Po (Polímero de Lítio) | Alta densidade de energia (muita capacidade em pouco peso), alta capacidade de corrente. | Requerem circuitos de proteção (contra sobrecarga, descarga excessiva e curto-circuito), mais caras, sensíveis a danos físicos. |
Para robótica, as baterias de Li-Ion (como as células 18650) e Li-Po são as mais populares devido à sua excelente relação energia/peso. No entanto, elas exigem um cuidado extremo no manuseio e carregamento.
AVISO DE SEGURANÇA: Nunca use baterias de Lítio sem um BMS (Battery Management System) ou um circuito de proteção adequado. Uma sobrecarga ou um curto-circuito pode causar incêndios ou explosões.Os componentes de um robô geralmente operam em tensões diferentes. Por exemplo:
Uma bateria de Li-Ion fornece uma tensão que varia (ex: de 4.2V quando cheia a 3.0V quando vazia). Para fornecer as tensões estáveis que nossos componentes precisam, usamos reguladores de tensão.
Um conversor step-down reduz a tensão. Por exemplo, ele pode pegar os 7.4V de duas células de Li-Ion em série e convertê-los em 5V estáveis para alimentar o ESP32 e os servos.
Um conversor step-up aumenta a tensão. Por exemplo, ele pode pegar os 3.7V de uma única célula de Li-Ion e elevá-los para 5V.
O uso de conversores DC-DC (como os Buck e Boost) é muito mais eficiente do que usar reguladores lineares (como o LM7805), pois eles desperdiçam muito menos energia na forma de calor, o que é crucial para maximizar a autonomia da bateria.
Vamos projetar um sistema de alimentação básico para nosso robô usando uma célula de Li-Ion 18650 e um módulo que já inclui o carregador e o conversor step-up.
Materiais Necessários:- Este tipo de módulo é muito popular. Ele possui uma entrada micro-USB para carregar a bateria, um circuito de proteção e uma saída de 5V estabilizada.
B+ e B- do módulo TP4056.OUT+ e OUT-. Esta será a sua fonte de 5V estabilizada para alimentar o robô (ESP32 e motores).graph TD
subgraph "Fonte de Energia"
Bateria[Célula Li-Ion 18650]
Modulo[Módulo TP4056 com Step-Up]
end
subgraph "Carga do Robô"
ESP32[ESP32]
Motores[Motores / Servos]
Sensores[Sensores]
end
Bateria -- 3.7V --> Modulo
Modulo -- 5V Estabilizado --> ESP32
Modulo -- 5V Estabilizado --> Motores
ESP32 -- 3.3V --> Sensores
style Bateria fill:#f39c12,stroke:#d68910,color:#fff
style Modulo fill:#3498db,stroke:#2980b9,color:#fff
Resultado:
Você agora tem um sistema de alimentação compacto e recarregável. A saída de 5V do módulo pode ser conectada diretamente à protoboard do seu robô, substituindo o power bank. Isso torna o robô totalmente independente e muito mais profissional.
No próximo módulo, vamos juntar todos os conceitos do Nível 2 para construir um robô autônomo completo, capaz de navegar em um ambiente usando sensores avançados e algoritmos de controle.
6 horas • 3 aulas
Bem-vindo ao projeto final do Nível Intermediário! É hora de combinar o poder do ESP32, a precisão dos sensores avançados, a inteligência dos algoritmos de controle e um sistema de energia dedicado para construir um robô autônomo multi-sensor.
Nosso objetivo é construir um robô que possa navegar em um ambiente simples, realizando duas tarefas principais:
Este projeto representa um salto significativo em complexidade e capacidade em relação ao robô do Nível 1, transformando-o de um veículo teleoperado para um agente autônomo.
Figura 1: Nosso objetivo é um robô que integra múltiplos sensores para navegar de forma inteligente.
---
Vamos partir do nosso Rover de Papel e adicionar os novos componentes.
Materiais Adicionais:- Sensores de Linha: Monte o módulo de sensores de linha na frente do robô, o mais próximo possível do chão (cerca de 3-5 mm de altura é o ideal).
- Sensor Ultrassônico: Monte o HC-SR04 na frente do robô, apontado para frente, a uma altura que possa detectar obstáculos comuns.
Trig no GPIO 12, Echo no GPIO 13 (com divisor de tensão).- Sensor Esquerdo: GPIO 32
- Sensor Central: GPIO 33
- Sensor Direito: GPIO 34
---
Nosso programa será estruturado como uma máquina de estados. O robô estará sempre em um de dois estados principais: SEGUINDO_LINHA ou EVITANDO_OBSTACULO.
stateDiagram-v2
[*] --> SEGUINDO_LINHA
SEGUINDO_LINHA --> EVITANDO_OBSTACULO: Obstáculo detectado
EVITANDO_OBSTACULO --> SEGUINDO_LINHA: Obstáculo removido
EVITANDO_OBSTACULO: Parar e esperar
SEGUINDO_LINHA.loop(), o robô primeiro verifica a distância com o sensor ultrassônico.EVITANDO_OBSTACULO, onde a ação principal é parar.SEGUINDO_LINHA, usando os sensores de linha para ajustar a direção.---
Este código integra a leitura de todos os sensores e implementa a máquina de estados descrita.
#include <ESP32Servo.h>
// --- Configuração dos Pinos
const int pinoServoEsquerdo = 18;
const int pinoServoDireito = 19;
const int pinoTrig = 12;
const int pinoEcho = 13;
const int pinoSensorLinhaEsq = 32;
const int pinoSensorLinhaCen = 33;
const int pinoSensorLinhaDir = 34;
// --- Servos e Movimento
Servo servoEsquerdo;
Servo servoDireito;
int velocidadeBase = 150; // Velocidade de cruzeiro
// --- Sensores e Lógica
#define DISTANCIA_OBSTACULO 15 // cm
enum EstadoRobo { SEGUINDO_LINHA, EVITANDO_OBSTACULO };
EstadoRobo estadoAtual = SEGUINDO_LINHA;
void setup() {
Serial.begin(115200);
// Inicializa os motores
servoEsquerdo.attach(pinoServoEsquerdo);
servoDireito.attach(pinoServoDireito);
// Inicializa os pinos dos sensores
pinMode(pinoTrig, OUTPUT);
pinMode(pinoEcho, INPUT);
pinMode(pinoSensorLinhaEsq, INPUT);
pinMode(pinoSensorLinhaCen, INPUT);
pinMode(pinoSensorLinhaDir, INPUT);
}
// --- Funções de Movimento
void parar() { servoEsquerdo.writeMicroseconds(1500); servoDireito.writeMicroseconds(1500); }
void frente() { servoEsquerdo.writeMicroseconds(1500 + velocidadeBase); servoDireito.writeMicroseconds(1500 - velocidadeBase); }
void esquerda() { servoEsquerdo.writeMicroseconds(1500 - velocidadeBase); servoDireito.writeMicroseconds(1500 - velocidadeBase); }
void direita() { servoEsquerdo.writeMicroseconds(1500 + velocidadeBase); servoDireito.writeMicroseconds(1500 + velocidadeBase); }
// --- Funções de Leitura de Sensores
int lerDistancia() {
digitalWrite(pinoTrig, LOW);
delayMicroseconds(2);
digitalWrite(pinoTrig, HIGH);
delayMicroseconds(10);
digitalWrite(pinoTrig, LOW);
long duracao = pulseIn(pinoEcho, HIGH);
return duracao * 0.0343 / 2;
}
void loop() {
// 1. Verificação de Obstáculos (maior prioridade)
int distancia = lerDistancia();
if (distancia < DISTANCIA_OBSTACulo && distancia > 0) {
estadoAtual = EVITANDO_OBSTACULO;
} else {
estadoAtual = SEGUINDO_LINHA;
}
// 2. Executa a lógica baseada no estado atual
switch (estadoAtual) {
case SEGUINDO_LINHA:
// Lê os sensores de linha (LOW = viu linha preta)
bool esq = digitalRead(pinoSensorLinhaEsq) == LOW;
bool cen = digitalRead(pinoSensorLinhaCen) == LOW;
bool dir = digitalRead(pinoSensorLinhaDir) == LOW;
if (cen) {
frente(); // Em cima da linha, vai para frente
} else if (esq) {
esquerda(); // Desviou para a direita, corrige para a esquerda
} else if (dir) {
direita(); // Desviou para a esquerda, corrige para a direita
} else {
// Perdeu a linha, para (ou pode girar para procurar)
parar();
}
break;
case EVITANDO_OBSTACULO:
Serial.println("Obstáculo detectado! Parando.");
parar();
break;
}
delay(20); // Pequeno delay para estabilidade
}
---
1500 em parar() realmente param seus motores. Ajuste se necessário.8 horas • Projeto Integrado
Construa um robô móvel autônomo com as seguintes características:
ESP32, motores com encoder, IMU, ultrassom, display OLED
Manual (WiFi/BLE), seguidor de linha PID, desviador de obstáculos
Dashboard responsivo com telemetria em tempo real via WebSocket
Envio de dados para MQTT broker, histórico em SD card
PID para motores, fusão de sensores IMU, odometria com encoders
Crie uma missão autônoma: navegar por labirinto, retornar ao ponto de partida e enviar mapa via WiFi!
Conecte dispositivos à internet, crie dashboards e integre com serviços cloud
Implemente controle PID, sistemas realimentados e navegação autônoma
Domine ESP32, FreeRTOS, multitasking e otimização de recursos
Ao concluir o Nível 2, você terá habilidades profissionais em IoT, controle e sistemas embarcados!