🤖 RoboFeed
Explorar aulas Entrar Comece grátis
🤖 Robótica

Seguidor de Linha ESP32 (MicroPython + PID)

👤 Weslley Barros 🏫 E.M. Abdalla 9º ano1º ano (EM)2º ano (EM)3º ano (EM) ⚡ Plugada
🔧 Modo Bancada · passo a passo, pro aluno no tablet

🎯 Objetivos de aprendizagem

  • Montar e programar (em MicroPython) um seguidor de linha de alto desempenho com ESP32: ler 8 sensores QTR-8RC, calcular a posição da linha e usar um controle PID para seguir curvas suavemente, com recuperação quando a linha é perdida.
🧭 Habilidades BNCC Computação (6)
🧠 Pensamento Computacional
EF89CO01 Desenvolver projetos computacionais que integrem decomposição, abstração, generalização e avaliação crítica da solução proposta.
EF89CO02 Implementar algoritmos com funções/sub-rotinas, listas/arrays e leitura de sensores, em linguagens de blocos ou textuais (C++, Python).
💻 Mundo Digital
EF89CO03 Projetar e construir sistemas integrados que combinem hardware (placa, sensores, atuadores) e software (algoritmo) para resolver problemas reais.
EF89CO04 Avaliar arquiteturas de hardware (processador, memória, periféricos) e modelos de comunicação (cliente-servidor, IoT) em soluções tecnológicas.
🌐 Cultura Digital
EF89CO05 Discutir aspectos éticos do uso de inteligência artificial (viés algorítmico, automação, direitos autorais, deepfakes) e propor princípios de uso responsável.
EF89CO06 Compreender legislações de proteção de dados (LGPD) e aplicar boas práticas de segurança digital, autoria e propriedade intelectual em produções escolares.

Habilidades dos anos selecionados (9º ano, 1º ano (EM), 2º ano (EM), 3º ano (EM)) — Resolução CNE/CP nº 1/2022. Em turmas de Ensino Médio, mapear para EM13CO.

🧰 Materiais e componentes

🧰
ESP32 (placa WROOM-32 DevKit)
🧰
Driver de motor TB6612FNG
Régua de sensores QTR-8RC (8 canais)
Régua de sensores QTR-8RC (8 canais)
Motor DC com caixa de redução
Motor DC com caixa de redução
Roda + roda boba (esfera)
Roda + roda boba (esfera)
Bateria Li-Po + interruptor (e regulador)
Bateria Li-Po + interruptor (e regulador)
🧰
PCB do projeto (ESP32 seguidor) ou protoboard
Chassi (impressão 3D)
Chassi (impressão 3D)
🧰
Pista: fita isolante preta sobre fundo branco
Jumpers, parafusos e cabos
Jumpers, parafusos e cabos
🪜 Desenvolvimento da aula
Introdução / Contextualização

Apresente o seguidor de linha avançado: ESP32 em MicroPython, 8 sensores (QTR-8RC) e controle PID. Pergunta: por que um robô simples ziguezagueia e este segue a curva suave? Resposta: o PID corrige proporcional ao tamanho do erro.

Montagem do Circuito / Hardware

1) Montar chassi, motores e a régua de sensores na frente. 2) Ligar o TB6612 ao ESP32 (motor A: AIN1 G18, AIN2 G19, PWMA G4 · motor B: BIN1 G21, BIN2 G22, PWMB G5; STBY/VCC no 3V3; VM na bateria). 3) Ligar a régua QTR-8RC nos GPIO 13,12,14,27,26,25,33,32. Energia: bateria → regulador → ESP32; GND comum.

Programação / Codificação

Instalar o MicroPython no ESP32 e enviar o código com a IDE Thonny. Explicar o PID: P corrige proporcional ao erro, D antecipa pela velocidade do erro, I corrige desvios acumulados. A posição da linha vira um número (0–7000, centro 3500). Ajustar Kp, Kd, Ki e a velocidade base.

Teste, Depuração e Ajustes

Calibrar na pista: se ziguezagueia, baixar Kp ou subir Kd; se corrige devagar, subir Kp; se sai nas curvas, reduzir a velocidade base. Testar a recuperação quando a linha some.

Encerramento / Socialização

Roda de conversa: o que é uma malha de controle (PID)? Onde mais existe (chuveiro, drone, carro)? Encerrar com uma corrida cronometrada e comparação de ajustes entre as equipes.

🔌 Montagem do robô

Placa: ESP32 (WROOM-32)

⬇ baixar SVG
🧰 Montagem do robôPlaca: ESP32 (WROOM-32) · 4 componentes · 20 ligações detectadas do códigoESP32 (WROOM-32)⚡ Barramento de alimentação · 5V (+) / GND (–)GPIO13 · sensor 1GPIO12 · sensor 2GPIO14 · sensor 3GPIO27 · sensor 4GPIO26 · sensor 5GPIO25 · sensor 6GPIO33 · sensor 7GPIO32 · sensor 8Régua QTR-8RCGPIO18 · direção AGPIO19 · direção AGPIO4 · PWM velocidade AGPIO21 · direção BGPIO22 · direção BGPIO5 · PWM velocidade BDriver de motor(TB6612)AO1·AO2Motor DC esquerdoBO1·BO2Motor DC direitoLEGENDA DOS FIOSAlimentação (+5V)PWM (velocidade)Saída de motorOutro / dados
🧰 Montagem do robôESP32 (WROOM-32)placa controladoraDriver de motor (TB6612)GPIO18GPIO19GPIO4GPIO21GPIO22GPIO53V3bateria +Régua QTR-8RCGPIO13GPIO12GPIO14GPIO27GPIO26GPIO25GPIO33GPIO32Motor DC esquerdoAO1AO2Motor DC direitoBO1BO2
Energia: a bateria Li-Po alimenta a entrada VM do driver TB6612 (motores) e, por um regulador, fornece 5V ao ESP32. O VCC e o STBY do TB6612 vão no 3V3 do ESP32; a régua QTR também é alimentada (VCC/GND). GND comum entre tudo. Use um interruptor geral.
📋 Tabela de ligações (fio a fio)
Sensores
Régua QTR-8RC
S1 GPIO13 sensor 1
S2 GPIO12 sensor 2
S3 GPIO14 sensor 3
S4 GPIO27 sensor 4
S5 GPIO26 sensor 5
S6 GPIO25 sensor 6
S7 GPIO33 sensor 7
S8 GPIO32 sensor 8
Sistema motor
Driver de motor (TB6612)
AIN1 GPIO18 direção A
AIN2 GPIO19 direção A
PWMA GPIO4 PWM velocidade A
BIN1 GPIO21 direção B
BIN2 GPIO22 direção B
PWMB GPIO5 PWM velocidade B
STBY/VCC 3V3 habilita (nível alto) + lógica
VM bateria + alimentação dos motores
Motor DC esquerdo
terminal + AO1 (Ponte H) tração esq
terminal − AO2 (Ponte H) tração esq
Motor DC direito
terminal + BO1 (Ponte H) tração dir
terminal − BO2 (Ponte H) tração dir
🔧 Passo a passo de ligação
  1. Cérebro: ESP32 WROOM-32 rodando MicroPython.
  2. Motores: AIN1→G18, AIN2→G19, PWMA→G4 (motor A); BIN1→G21, BIN2→G22, PWMB→G5 (motor B). STBY/VCC no 3V3, VM na bateria.
  3. Sensores: régua QTR-8RC nos GPIO 13, 12, 14, 27, 26, 25, 33, 32 (8 canais) + VCC/GND.
  4. Energia: bateria Li-Po → VM (motores) e → regulador → 5V do ESP32; GND comum.
  5. Calibração: a posição vai de 0 a 7000 (centro = 3500). Ajuste Kp/Kd/Ki e a velocidade base (cruzero) na pista.
  6. Motores: esquerdo nas saídas AO1/AO2; direito nas BO1/BO2. Se um girar ao contrário, inverta os 2 fios dele.

💻 Código

aula.py
# Seguidor de Linha — ESP32 (MicroPython) + driver TB6612 + régua QTR-8RC
# Controle PID com filtro de média móvel e recuperação de linha perdida.
# (código original; comentários traduzidos para o português)
from machine import Pin, PWM
import time

# ------------------ Pinos dos Motores (TB6612) ------------------
PWMA = PWM(Pin(4), freq=5000, duty=0)   # PWM do motor A
PWMB = PWM(Pin(5), freq=5000, duty=0)   # PWM do motor B

AIN1 = Pin(18, Pin.OUT)
AIN2 = Pin(19, Pin.OUT)
BIN1 = Pin(21, Pin.OUT)
BIN2 = Pin(22, Pin.OUT)

# ------------------ Pinos dos Sensores QTR-8RC ------------------
sensors = [
    Pin(13, Pin.IN), Pin(12, Pin.IN), Pin(14, Pin.IN), Pin(27, Pin.IN),
    Pin(26, Pin.IN), Pin(25, Pin.IN), Pin(33, Pin.IN), Pin(32, Pin.IN)
]
NUM_SENSORS = len(sensors)

# ------------------ Parâmetros do PID ------------------
cruzero = 300  # velocidade base (0–1023)
Kp = 0.2
Kd = 10.0
Ki = 0.005

PRO = 0
DER = 0
INT = 0
LAST = 0

# ------------------ Filtro dos sensores ------------------
history = [3500] * 5  # histórico inicial para a média móvel

def read_qtr_digital():
    """Devolve a posição com base nos sensores digitais (0 ou 1)."""
    values = [s.value() for s in sensors]
    weighted_sum = 0
    total = 0
    for i, v in enumerate(values):
        weighted_sum += v * i * 1000
        total += v
    if total == 0:
        return 3500  # centro por padrão
    return int(weighted_sum / total)

def read_qtr_filtered():
    """Filtra a leitura dos sensores usando média móvel."""
    pos = read_qtr_digital()
    history.pop(0)
    history.append(pos)
    return sum(history) // len(history)

# ------------------ Controle dos motores ------------------
def set_motor(left, right):
    """Controla os motores esquerdo e direito com valores de -1023 a 1023."""
    # Motor A (esquerdo)
    if left >= 0:
        AIN1.value(1); AIN2.value(0); PWMA.duty(min(left, 1023))
    else:
        AIN1.value(0); AIN2.value(1); PWMA.duty(min(-left, 1023))
    # Motor B (direito)
    if right >= 0:
        BIN1.value(1); BIN2.value(0); PWMB.duty(min(right, 1023))
    else:
        BIN1.value(0); BIN2.value(1); PWMB.duty(min(-right, 1023))

# ------------------ Programa principal ------------------
print("Iniciando o seguimento de linha...")
time.sleep(2)

last_time = time.ticks_ms()

while True:
    now = time.ticks_ms()
    dt = max((now - last_time) / 1000, 0.001)  # evita divisão por zero
    last_time = now

    # Leitura de posição filtrada
    pos = read_qtr_filtered()
    PRO = pos - 3500

    # Linha perdida -> giros suaves para reencontrar
    if PRO < -3500:
        vel_loss = int(cruzero * 0.8)
        set_motor(-vel_loss, vel_loss)
        INT = 0  # zera o integral
    elif PRO > 3500:
        vel_loss = int(cruzero * 0.8)
        set_motor(vel_loss, -vel_loss)
        INT = 0
    else:
        # PID
        DER = (PRO - LAST) / dt
        INT += PRO * dt
        INT = max(min(INT, 3000), -3000)  # anti-windup

        vel = (PRO * Kp) + (DER * Kd) + (INT * Ki)
        vel = max(min(vel, cruzero), -cruzero)

        # Ajuste dinâmico da velocidade base nas curvas
        baseSpeed = cruzero
        if abs(PRO) > 1500:
            baseSpeed = int(cruzero * 0.7)

        left = baseSpeed - vel
        right = baseSpeed + vel
        set_motor(int(left), int(right))

        LAST = PRO

    time.sleep_ms(5)

🔀 Fluxograma do algoritmo

flowchart TD A(["Início"]) --> CFG["Configurar TB6612, PWM e 8 sensores QTR"] CFG --> L["Ler posição da linha (filtro de média móvel)"] L --> E["erro = posição - 3500"] E --> Q{"Linha perdida?"} Q -->|Sim| R["Girar suave para reencontrar"] Q -->|Não| PID["PID: Kp·erro + Kd·derivada + Ki·integral"] PID --> M["Motores: esq = base - correção · dir = base + correção"] R --> L M --> L

🧱 Algoritmo em blocos

quando @greenFlag for clicado
configurar TB6612, PWM e os 8 sensores QTR
sempre
  ler a posição da linha (8 sensores, com filtro de média móvel)
  somar (erro) a (posição) - (3500)
  se <linha perdida para um lado?> então
    girar suave para reencontrar a linha
  senão
    somar (derivada) a (erro - erro anterior) / (dt)
    somar (integral) a (integral) + (erro × dt)
    somar (correção) a (Kp×erro) + (Kd×derivada) + (Ki×integral)
    acionar motor esquerdo com (base - correção)
    acionar motor direito com (base + correção)
  end
end

🖨️ Modelos 3D para impressão

Toque para ver em 3D · gire com o dedo.

Corpo/chassi 📥 Baixar
Suporte 📥 Baixar

🤖 Quer essa aula do SEU jeito?

O Co-professor adapta esta aula pro seu ano e contexto — ou a estica numa sequência didática de 2 a 4 encontros — e gera um PDF pronto pra você. A estrutura da aula é preservada. Cadastre-se grátis pra usar.

✨ Adaptar e gerar PDF

💬 Comentários

Entre na sua conta ou crie uma grátis pra comentar.

Seja o primeiro a comentar.

Gostou desta aula?

Monte aulas como esta em minutos, com ajuda da IA — e compartilhe com professores do Brasil todo. É grátis.

Criar minha conta grátis
📲 Compartilhar no WhatsApp

Explorar mais aulas · RoboFeed — robótica e computação na escola, alinhado à BNCC.