Seguidor de Linha · 4 sensores TCRT5000
Seguidor de Linha · 4 sensores TCRT5000
- Construir e programar um robô que segue uma linha usando 4 sensores TCRT5000 e um driver TB6612, corrigindo a rota em tempo real com um PID proporcional-derivativo — calibração, ajuste de ganhos e depuração.
1× Arduino Uno 1× Driver de motor TB6612FNG 4× Sensor de linha TCRT5000 2× Motor DC com caixa de redução 1× Roda + roda boba (esfera) 1× Bateria 9V (ou pack de pilhas) 1× Chassi (impressão 3D) 1× Pista: fita isolante preta sobre fundo branco 1× Jumpers, parafusos e interruptor
Introdução / Contextualização
Apresente o desafio: um robô que segue uma linha sozinho usando só 4 sensores. Pergunta: como ele decide para que lado corrigir, com tão poucos sensores?
Montagem do Circuito / Hardware
1) Montar o chassi, fixar os 2 motores e as rodas. 2) Ligar o driver TB6612 (motor A: D9/D7/D8 · motor B: D3/D5/D4 · STBY no D6, que precisa ficar em nível alto). 3) Ligar os 4 sensores TCRT5000 (sinais em A1–A4, emissor no D13) e a alimentação: bateria na entrada VM, o 5V e o GND comuns com o Arduino.
Programação / Codificação
Carregar o código. Explicar a lógica: ler a POSIÇÃO da linha, calcular o ERRO e corrigir com um PID simples (proporcional + derivativo), sempre avançando. CALIBRAR passando os sensores sobre a linha e o fundo. Ajustar os ganhos KP/KD e a velocidade base.
Teste, Depuração e Ajustes
Testar na pista. Depurar em equipe: se oscila, baixe a velocidade base ou o ganho proporcional; se corta as curvas, aumente o ganho derivativo.
Encerramento / Socialização
Roda de conversa: o que é controle em malha fechada (medir → corrigir → repetir)? Por que calibrar é tão importante? Como o número de sensores muda a precisão?
/*
* Seguidor de Linha · 4 sensores TCRT5000 — Arduino UNO
* Driver: TB6612FNG | Sensores: 4x TCRT5000 (lidos como régua QTR)
* PID proporcional-derivativo simples, sempre avançando.
* (código original adaptado; comentários traduzidos para o português)
*/
// ===== Pinos do driver TB6612FNG =====
#define PWMA 9 // velocidade do motor A
#define AIN2 8 // direção do motor A
#define AIN1 7 // direção do motor A
#define BIN1 5 // direção do motor B
#define BIN2 4 // direção do motor B
#define PWMB 3 // velocidade do motor B
#define STBY 6 // standby: precisa ficar em HIGH para o driver funcionar
int velocidadeBase = 250; // velocidade de cruzeiro (0 a 255)
// ===== Ganhos do PID =====
float KP = 0.2;
float KD = 5;
int erro = 0;
int derivada = 0;
int erroAnterior = 0;
float correcao;
#include <QTRSensors.h>
#define NUM_SENSORES 4
#define TIMEOUT 2500
#define PINO_EMISSOR 13 // liga os LEDs infravermelhos dos sensores
QTRSensorsRC qtr(
(unsigned char[]){18, 17, 16, 15}, // A4, A3, A2, A1
NUM_SENSORES,
TIMEOUT,
PINO_EMISSOR
);
unsigned int leiturasSensores[NUM_SENSORES];
unsigned int posicao = 0;
void setup() {
Serial.begin(115200);
pinMode(PWMA, OUTPUT);
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
pinMode(PWMB, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(STBY, OUTPUT);
digitalWrite(STBY, HIGH); // habilita o TB6612
// Calibração: passe os 4 sensores sobre a linha e o fundo por alguns segundos
Serial.println("== CALIBRANDO ==");
digitalWrite(PINO_EMISSOR, HIGH);
for (int i = 0; i < 400; i++) {
qtr.calibrate();
delay(5);
}
digitalWrite(PINO_EMISSOR, LOW);
Serial.println("== PRONTO ==");
}
void loop() {
posicao = qtr.readLine(leiturasSensores, QTR_EMITTERS_ON, 0);
// Centro para 4 sensores: faixa 0..3000, centro = 1500
erro = posicao - 1500;
// ===== PID =====
derivada = erro - erroAnterior;
correcao = (erro * KP) + (derivada * KD);
correcao = constrain(correcao, -velocidadeBase, velocidadeBase);
int motorA = velocidadeBase - correcao;
int motorB = velocidadeBase + correcao;
motorA = constrain(motorA, 0, 255);
motorB = constrain(motorB, 0, 255);
// ===== Sempre para frente, ajustando só a velocidade de cada lado =====
digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); analogWrite(PWMA, motorA);
digitalWrite(BIN1, HIGH); digitalWrite(BIN2, LOW); analogWrite(PWMB, motorB);
erroAnterior = erro;
delay(5);
}
when green flag clicked forever set [posicao v] to (qtr.readLine(leiturasSensores, QTR_EMITTERS_ON, 0)) set [erro v] to (posicao - 1500) set [derivada v] to (erro - erroAnterior) set [correcao v] to ((erro * KP) + (derivada * KD)) set [correcao v] to (constrain(correcao, -velocidadeBase, velocidadeBase)) set [motorA v] to (velocidadeBase - correcao) set [motorB v] to (velocidadeBase + correcao) set [motorA v] to (constrain(motorA, 0, 255)) set [motorB v] to (constrain(motorB, 0, 255)) digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); analogWrite(PWMA, motorA) :: custom digitalWrite(BIN1, HIGH); digitalWrite(BIN2, LOW); analogWrite(PWMB, motorB) :: custom set [erroAnterior v] to (erro) wait (0.005) secs end
Toque para ver em 3D · gire com o dedo.
Você chegou ao fim! 🎉
O que foi mais difícil? O que você faria diferente? Conte pra turma!