Tutorial · Iniciante · 20 min

Matriz de sensores infravermelhos para robô seguidor de linha

Transforme uma fileira de sensores de reflectância infravermelha em um único erro de posição, com calibração, leitura analógica e média ponderada.

O desempenho de um robô seguidor de linha depende do erro usado para comandar sua direção. Esse valor vem de uma fileira de sensores de reflectância infravermelha apontados para o piso: a linha tem uma cor, o fundo tem outra, e os sensores informam quanto da luz infravermelha é refletida. Este guia transforma essa fileira bruta de leituras em uma única posição da linha contínua e suave — o erro sobre o qual o controlador atua.

Como um sensor de reflectância vê a linha

Cada sensor combina um LED infravermelho com um fototransistor. O LED projeta luz para baixo; o fototransistor mede a reflexão. Uma linha preta fosca reflete pouca luz infravermelha (leitura baixa); o fundo mais claro reflete mais (leitura alta). Passe a matriz por uma pista preta sobre fundo branco e cada sensor oscilará entre um valor “sobre a linha” e um valor “fora da linha”.

Dois fatores fazem esses valores brutos variarem de uma execução para outra: a altura do sensor acima da superfície e a luz ambiente. Por isso nunca fixe limiares no código — calibre. Os mesmos sensores apontados para a borda de um anel, em vez de uma linha, tornam-se um detector de borda, em que uma leitura perdida custa a partida ao robô.

Sensores analógicos ou digitais

  • Sensores analógicos fornecem um valor contínuo (por exemplo, 0–1023 em um ADC do Arduino). Você sabe a que distância a linha está de cada sensor, o que permite calcular uma posição suave e comandar a direção proporcionalmente.
  • Sensores digitais informam apenas ligado/desligado depois de um limiar interno. São mais simples de conectar, mas perdem a informação intermediária, então o controle fica mais grosseiro.

Para o seguimento proporcional de linha — o tipo que se ajusta com um controlador PID — use leituras analógicas. É essa a abordagem que o simulador de robô seguidor de linha modela.

Calibre primeiro

Antes de uma execução, passe cada sensor sobre a linha e sobre o fundo e registre o valor mínimo e o valor máximo de cada sensor. Depois normalize cada leitura obtida em tempo real para 0–1000 em relação à sua própria faixa:

// Per-sensor calibration captured during a sweep.
int minv[N], maxv[N];

int normalized(int raw, int i) {
  long span = maxv[i] - minv[i];
  if (span <= 0) return 0;                       // sensor never saw contrast
  long v = (long)(raw - minv[i]) * 1000 / span;  // 0 (background) … 1000 (line)
  return constrain(v, 0, 1000);
}

Calibrar cada sensor cancela o brilho desigual dos LEDs e pequenas diferenças de altura ao longo da barra. Assim, a resposta de um único sensor não desloca silenciosamente toda a estimativa.

Das leituras a uma única posição da linha

Agora reduza a matriz a uma única posição com uma média ponderada pela reflectância. Dê a cada sensor uma posição fixa (…−2, −1, 0, +1, +2… ao longo da barra) e pondera esse valor pela leitura normalizada. O resultado é a posição da linha em relação ao centro da barra — positiva de um lado, negativa do outro e zero quando a linha está exatamente no centro.

Gráfico de barras de cinco sensores de reflectância na barra do robô. A linha fica à direita do centro, portanto os sensores desse lado fazem as leituras mais fortes. Uma linha tracejada marca o centro da barra (erro zero), e uma linha sólida marca a posição ponderada pela reflectância em +0,69, o erro de direção calculado.
A média ponderada das leituras dos sensores fornece uma posição suave da linha: aqui a linha fica à direita do centro, portanto o erro é positivo e o controlador comanda o robô para que ele retorne a zero. Baixar SVG
// Sensor positions across the bar, e.g. { -2000,-1000,0,1000,2000 }.
long readLinePosition() {
  long weighted = 0, total = 0;
  for (int i = 0; i < N; i++) {
    int v = normalized(analogRead(pins[i]), i);
    weighted += (long)v * position[i];
    total    += v;
  }
  if (total == 0) return lastPosition;  // line lost — reuse last direction
  lastPosition = weighted / total;
  return lastPosition;                  // 0 = centered, sign = which side
}

Dois detalhes tornam isso robusto:

  • Divida pela soma das leituras, não pela quantidade de sensores, para que uma linha fraca e uma linha forte sejam mapeadas para a mesma escala de posição.
  • Quando todos os sensores perderem a linha (total == 0), reutilize a última posição conhecida em vez de retornar zero. Isso mantém a última direção de correção do robô, em vez de fazê-lo sair em linha reta de uma curva fechada.

Quantos sensores?

Cinco é um bom ponto de partida — suficiente para perceber direção e magnitude, mantendo a matemática fácil de verificar. Três funcionam em baixa velocidade; robôs de competição usam oito ou mais para obter maior resolução em alta velocidade. O principal ganho de mais sensores é uma estimativa de posição mais suave em curvas fechadas.

A rotina completa de calibração

“Calibre primeiro” é fácil de dizer e fácil de executar de forma inadequada. Esta é a rotina inteira, incluindo a proteção que impede que um canal inativo estrague a estimativa:

const int N = 8;
const int PIN[N] = {A0, A1, A2, A3, A4, A5, A6, A7};
int minv[N], maxv[N];

void calibrate(unsigned long durationMs) {
  for (int i = 0; i < N; i++) { minv[i] = 1023; maxv[i] = 0; }

  const unsigned long start = millis();
  while (millis() - start < durationMs) {
    for (int i = 0; i < N; i++) {
      const int v = analogRead(PIN[i]);
      if (v < minv[i]) minv[i] = v;
      if (v > maxv[i]) maxv[i] = v;
    }
  }

  // A channel that never saw contrast would turn noise into huge normalised
  // values and drag the whole estimate toward itself.
  for (int i = 0; i < N; i++) {
    if (maxv[i] - minv[i] < 50) {
      Serial.print(F("channel dead or never crossed the line: "));
      Serial.println(i);
    }
  }
}

Passe a matriz pela linha durante toda a janela de calibração. Um robô parado registra a mesma leitura como mínimo e máximo, produzindo uma amplitude zero e fazendo com que o sensor não contribua para nada. Girar o robô no lugar sobre a linha por três segundos é o movimento padrão, e funciona porque cada canal cruza a fita.

Recalibre no início de cada execução, não uma única vez durante a montagem. A luz ambiente muda, a distância do sensor ao piso muda conforme o pacote de baterias se desloca e a fita acumula poeira. Esse é o motivo mais comum para um robô seguidor de linha funcionar em uma mesa e falhar em outra.

Eliminando a luz ambiente

A luz do sol contém muito infravermelho de 940 nm, e o fototransistor não consegue distingui-lo da reflexão do seu próprio emissor. Um robô que funciona em ambientes internos e falha perto de uma janela está exatamente nessa situação.

Se os emissores da sua matriz puderem ser desligados — a maioria tem um pino LEDON ou CTRL — a solução é completa e custa uma leitura adicional por canal:

int ambientSubtracted(int i) {
  digitalWrite(LEDON, LOW);
  delayMicroseconds(200);              // let the phototransistor settle
  const int dark = analogRead(PIN[i]); // ambient only

  digitalWrite(LEDON, HIGH);
  delayMicroseconds(200);
  const int lit = analogRead(PIN[i]);  // ambient + our emitter

  return lit - dark;                   // just our emitter
}

Tudo o que for constante no ambiente é cancelado exatamente. O custo é o dobro do tempo de amostragem, o que pesa em um robô seguidor de linha rápido — mas converte um sensor pouco confiável em confiável, e é a técnica usada por matrizes comerciais.

Isso também traz um segundo benefício importante: com os emissores desligados entre leituras, a corrente média deles cai bastante. Os emissores de uma matriz de 8 canais podem consumir 100–200 mA continuamente, o que em um pacote pequeno representa uma parte significativa do orçamento.

Perdendo a linha e reencontrando-a

O caso total == 0 merece mais atenção do que costuma receber, porque é nele que um robô seguidor de linha falha visivelmente com mais frequência.

Retornar zero é a implementação óbvia e errada: zero significa “perfeitamente centralizado”, então o robô segue em frente à velocidade máxima — para longe da linha que acabou de perder, que quase certamente estava curvando.

Retornar a última posição faz o robô continuar girando na direção para onde a linha foi. Essa única mudança é a diferença entre um robô que se recupera de uma curva fechada e outro que sai da pista.

Uma versão mais completa adiciona um tempo limite, para que um robô realmente perdido pare em vez de ficar em espiral:

long lastPosition = 0;
unsigned long lostSince = 0;

long readLinePosition() {
  long weighted = 0, total = 0;
  for (int i = 0; i < N; i++) {
    const int v = normalized(analogRead(PIN[i]), i);
    if (v > 100) {                    // ignore channels clearly on the floor
      weighted += (long)v * POSITION[i];
      total    += v;
    }
  }

  if (total == 0) {
    if (lostSince == 0) lostSince = millis();
    if (millis() - lostSince > 1500) stopMotors();   // genuinely lost
    return lastPosition;              // keep turning the way we were
  }

  lostSince = 0;
  lastPosition = weighted / total;
  return lastPosition;
}

O limiar v > 100 também importa. Sem ele, oito canais que registram um pequeno valor de fundo diferente de zero arrastam a média ponderada para o centro da matriz, independentemente de onde a linha esteja — o resultado é um robô que acompanha bem uma linha forte e mal uma linha apagada.

A distância ao piso determina o contraste

Sensores de reflectância têm uma faixa ideal estreita, e essa é a variável mecânica que mais frequentemente se disfarça de problema de software.

Distância do sensor ao piso O que aparece na amplitude da calibração
1–3 mm Maior amplitude, mas a matriz raspa em qualquer irregularidade do piso
3–8 mm A faixa utilizável. A maioria das matrizes especifica cerca de 3 mm
8–15 mm A amplitude diminui visivelmente; a normalização começa a amplificar o ruído
> 15 mm Praticamente sem leitura na maioria das superfícies

Duas consequências decorrem disso. Monte a matriz rigidamente — uma matriz em um suporte flexível muda de altura quando o robô acelera, o que altera as leituras, e o laço de controle interpreta essa alteração como se a linha tivesse se movido. E monte a matriz nivelada, porque uma matriz inclinada dá a cada canal uma altura efetiva diferente e, portanto, uma calibração diferente; isso aparece como um robô que acompanha bem em uma direção e mal na outra.

Quantos sensores, de forma quantificada

Canais Resolução de posição em uma linha de 19 mm Adequado para
3 Essencialmente esquerda / centro / direita Entender a ideia
5 ~4 regiões discretas, suaves entre elas Um primeiro robô seguidor de linha em uma pista suave
8 ~7 regiões Pistas rápidas, curvas fechadas, detecção de junções
12–16 Fina Robôs de competição em alta velocidade

O número que importa mais do que a contagem é a largura da matriz em relação à linha. Para o seguimento comum de uma linha, a matriz precisa ser larga o suficiente para que pelo menos um sensor fique sobre o piso, junto a cada borda da linha — aproximadamente o dobro da largura da fita.

Para detecção de junções em labirintos de linhas, o requisito é mais estrito: o robô reconhece um ramo quando vê os sensores mais externos escurecerem enquanto o centro ainda está sobre a linha, portanto a matriz deve ter pelo menos três vezes a largura da fita. Uma matriz de 8 canais com espaçamento de 8 mm mede cerca de 60 mm, valor adequado para fita de 19 mm.

Solução de problemas

Sintoma Causa provável Correção
Funciona em uma superfície e falha em outra Calibração desatualizada ou ausente Recalibre no início de cada execução
Um canal desloca a estimativa Emissor inativo — a amplitude dele é mínima Verifique o valor maxv − minv de cada canal e aplique a proteção
O robô segue em linha reta ao perder a linha Retorna 0 ao perder a linha Retorne a última posição
Acompanha fita forte e vagueia sobre fita apagada Ruído de fundo entra na média Adicione o limiar v > 100
Falha perto de uma janela Infravermelho ambiente Faça a subtração com o emissor desligado ou proteja a matriz
A posição salta quando a linha cruza os sensores Leituras não normalizadas por canal Calibre cada canal em relação ao próprio valor mínimo e máximo
As leituras variam ao longo de uma execução longa Queda de tensão da bateria, que faz a intensidade dos emissores diminuir Verifique a tensão no trilho sob carga
Todos os canais fazem a mesma leitura A matriz está longe demais do piso Use 3–8 mm e depois recalibre
Acompanha bem em uma direção e mal na outra Matriz não está nivelada Cada canal tem uma altura efetiva diferente

Para onde isso leva

Esse único valor de posição é o termo de erro. Alimente-o a um laço de controle que acelera uma roda e desacelera a outra, e você terá um robô seguidor de linha. Aprenda esse laço em ajustar um controlador PID e depois tente o conjunto completo no simulador de robô seguidor de linha.

Explore o grafo

Faz parte destas montagens

Projetos e caminhos de aprendizagem que incluem este tutorial.

Leitura complementar

Referências