Artrobots Inteli na Campus Party 2024 - Como montar um robô segue faixa

No tutorial de hoje, temos o prazer de apresentar a nossa nova parceria com a equipe de robótica da Artrobots Inteli. Desta parceria, nasce o robô segue faixa. A equipe da Artrobots Inteli participou da competição que ocorreu na Campus Party 2024. Hoje nossa parceria nos permite acompanhar e explicar todo o processo de desenvolvimento realizado pela equipe para a definição dos componentes, planejamento e design, além de claro, a montagem do circuito elétrico, estrutura mecânica e também programação e testes. Vamos lá !! 

Introdução

Aqui vamos mostrar todos os aspectos da construção de um robô seguidor de linha para uma competição nacional, desde a montagem mecânica até a programação e testes. Todo o desenvolvimento desse robô foi iniciado do zero para a participação da competição e aqui vamos mostrar como foi todo esse desenvolvimento. Este projeto é ideal para quem está começando em robótica ou mesmo para entusiastas que desejam aprimorar suas habilidades.

 

Lista de Componentes*
●     Arduino Nano 3.0: Cérebro do robô, controla sensores e motores. Este microcontrolador foi escolhido devido sua facilidade de uso, por ser leve, pequeno e ter um processamento relativamente rápido.

●     Módulo Sensor Fototransistor QRE1113 (8 Canais): Detecta a linha na frente.

●     Motores DC (N20 6V 3000RPM): Proporcionam a mobilidade do robô. Essa configuração de motores foi escolhida para atender a tensão da bateria que temos e também por ser um motor rápido devido ao seu rpm.

●     Ponte H (tb6612fng): Controla os motores DC.

●     Rodas de 44mm: Proporcionam movimento físico ao robô.

●     Bateria Lipo 7.4V 1100mAh: Alimenta todas as partes elétricas do robô. Essa tensão e corrente foi escolhida por conseguir alimentar todos os componentes do robô.

●     Placa de Circuito Impresso (PCB): Serve como base física para montagem dos componentes.

●     Resistores, Protoboard e Jumpers: Utilizados para as conexões elétricas e testes.

●     Regulador de Tensão LM7805: Converter tensão para 5V estável.

●     Sensor Reflexivo Infravermelho TCRT5000: Detectar marcações laterais para controle do robô.

●     Módulo Bluetooth HC-05: Comunicar com o robô via bluetooth, o que vai ser útil para ligar/desligar o robô e controlar variáveis internas via celular.

* Praticamente todos esses componentes são o mínimo para construir um robô seguidor de linha porém existem componentes mais avançados como como encoders e ventoinhas.

 

Planejamento e Design

Antes de fazer o robô em si, precisamos planejar como vai ser a estrutura do robô e suas conexões elétricas.

 

Circuito Elétrico e Conexões


Antes de fazer qualquer coisa física, precisamos entender como cada componente do robô vai se conectar e se comunicar entre si.

 

Conexões do robô:

 Aqui vamos descrever em uma visão macro como cada parte está comunicando com a outra:

●     Arduino Nano: Como isso é cérebro do robô gerencia todos os inputs e outputs do robô. Estamos utilizando todas as portas analógicas para receber os inputs dos sensores QRE1113. O resto das portas estão sendo utilizadas para o controle dos outros componentes.

●     Ponte H (tb6612fng): Permite o controle de direção e a variação de velocidade dos motores. Está conectado em algumas portas digitais do Arduino. Recebe tanto 5V do Arduino quanto 7.4 V da bateria que é direcionado automaticamente para os motores, não afetando nenhum outro componente.

●     Sensores QRE1113: Alinhados na frente do robô para detectar a linha com precisão.

●     Bateria Lipo: Conectada para fornecer energia ao sistema.

●     Módulo Bluetooth HC-05: O módulo se comunica com o Arduino através de comunicação serial.

●     Sensor Reflexivo Infravermelho TCRT5000: A comunicação é feita digitalmente pela falta de GPIOs analógicos. A regulagem desses sensores é feita manualmente no próprio sensor.

Tendo esse entendimento inicial, montamos todo desenho esquemático no software KiCad:

 

Design do Chassi

Tendo o desenho esquemático em mãos, podemos partir para criação da placa de circuito impresso (PCB) que vai ser o corpo e chassi do nosso robô. Isso vai fazer com que o robô seja compacto e leve. Também vai facilitar a integração e manutenção dos componentes, permitindo uma montagem mais estável.

No software KiCad conseguimos passar todos os componentes do desenho esquemático para a prototipação de PCBs. Nesta etapa, precisamos delimitar o tamanho do robô, as trilhas de conexões de cada componente e onde vai ficar cada componente em si.

TrilhasPCB- Artrobots inteli

A seguir vamos detalhar um pouco mais das escolhas feitas para a montagem do robô:

1. Forma e Dimensões da Placa
●     A PCB tem um formato octogonal, projetado para maximizar o espaço para os componentes enquanto mantém o robô compacto e manobrável.

●     As dimensões e o formato ajudam na distribuição equilibrada do peso, para manter a estabilidade.

 

2. Conector do Arduino Nano
●     No centro da PCB, há um soquete para o Arduino Nano. Isso coloca o microcontrolador no coração do robô, facilitando conexões diretas aos sensores e motores.

●     O Arduino é montado de forma que todos os seus pinos sejam acessíveis, permitindo fácil programação e depuração.

 

3. Tracks e Conexões
●     As trilhas vermelhas indicam os caminhos dos sinais elétricos e de energia, projetadas para minimizar interferências e perda de sinal.

●     As conexões são estrategicamente planejadas para reduzir a complexidade do fio e melhorar a eficiência elétrica.

●     Vale mencionar  que nenhuma conexão pode cruzar com outra, já que estamos utilizando uma placa de apenas de uma camada.

 

4. Conectores de Motores
●     Há dois conectores (J3 e J2) localizados nas bordas da placa para conectar os motores. Estes conectores garantem que os motores possam ser facilmente conectados e desconectados sem soldagem direta, facilitando manutenções e substituições.

 

5. Conectores para Sensores
●     Conectores adicionais (J1 e J4) são alocados para sensores de linha e laterais. Esses conectores permitem modularidade, significando que sensores podem ser trocados ou atualizados com facilidade.

 

6. Área de Alimentação e Regulação
●     A parte superior esquerda da PCB inclui espaços para componentes de regulagem de tensão e distribuição de energia.

●     Isso inclui o circuito para a bateria e um regulador de tensão para estabilizar a entrada de energia para os componentes sensíveis.

 

7. Design para Montagem e Estabilidade
●     Os pontos de montagem, indicados pelos círculos brancos nos cantos, são para fixar os motores, suporte dos sensores frontais e sensores laterais.

 Após a montagem disso, fizemos a prototipação na máquina PCB-PROTO 1S R2, que está disponível no laboratório da nossa faculdade. Resultando na placa da imagem abaixo:

 

Montagem Mecânica

Após termos impresso a placa de circuito impresso, soldamos todos os pinos fêmeas para encaixe dos componentes.

 

Programação 

Tendo desenho esquemático, desenho do circuito impresso e placa PCB feitas, agora podemos passar para a criação do código que estará rodando no nosso robô.

Antes de partir para o código em si, precisamos entender a lógica básica de uma seguidor de linha:

Logica Robo segue faixa - Artrobots Inteli

Sensores centrais detectam a linha:

  • Ação: Mantém as rodas girando na mesma velocidade.
  • Resultado: O robô move-se para frente em linha reta.

Sensores a esquerda detectam a linha:

  • Ação: Aumenta a velocidade da roda direita.
  • Resultado: O robô vira para a direita para corrigir seu curso e voltar para a linha central.

Sensor a direita detectam a linha:

  • Ação: Aumenta a velocidade da roda esquerda.
  • Resultado: O robô vira para a esquerda para corrigir seu curso e realinhar-se com a linha.

Para um controle mais preciso e maior velocidade do robô utilizamos um algoritmo de controle chamado PID. O controlador PID é uma estratégia de controle utilizada para manter o robô alinhado com a linha. O nome "PID" vem das três correções que o algoritmo usa para calcular a saída:

  • P - Proporcional: Depende da distância atual do robô em relação à linha. Se o robô está muito longe da linha, a correção aplicada é maior.
  • I - Integral: Acumula os erros passados, ou seja, se o robô tem estado consistentemente fora da linha, a correção torna-se mais forte. Isso é útil para eliminar o erro residual que o componente proporcional sozinho não pode corrigir.
  • D - Derivativo: Considera a taxa de mudança do erro, ajudando a suavizar a aproximação do robô à linha. Isso previne que o robô oscile muito ao redor da linha.

Aplicação no Seguidor de Linha
No contexto de um seguidor de linha, o controlador PID pode ser explicado como:

  • Leitura dos Sensores: Captura os valores de cada sensor disposto ao longo da frente do robô.
  • Cálculo do Erro: Determina quão longe e em qual direção o robô está desviado da linha. Por exemplo, se o sensor mais à direita tem a leitura mais alta, o erro é positivo, indicando um desvio à esquerda.
  • Aplicação do PID: Calcula a saída usando as componentes PID com base no erro:
    • Proporcional: Ajusta a velocidade das rodas proporcionalmente ao erro.
    • Integral: Compensa erros contínuos, como uma linha consistentemente curvada.
  • Derivativo: Reage às mudanças rápidas no erro, como curvas fechadas.

4 - Ajuste das Velocidades dos Motores: Conforme a saída do PID, a velocidade de cada motor é ajustada para realinhar o robô com a linha.
Agora podemos passar de fato para a construção do código do robô em si:

 

1. Inclusão de Bibliotecas e Configuração Inicial

#include <SoftwareSerial.h>

// Pinos para o módulo Bluetooth
SoftwareSerial BTSerial(6, 7); // RX, TX

●     SoftwareSerial.h: Biblioteca utilizada para criar portas seriais adicionais em pinos digitais do Arduino, permitindo a comunicação com o módulo Bluetooth.

●     BTSerial: Objeto SoftwareSerial configurado nos pinos 6 (RX) e 7 (TX) para comunicação com o módulo Bluetooth.

 

2. Definição dos Pinos

// Pinos para os sensores
#define S1 A0
#define S2 A1
#define S3 A2
...
#define S8 A7

// Pinos para os motores
#define AIN1 4
#define AIN2 3
#define PWMA 2
#define STBY 5
#define BIN1 8
#define BIN2 9
#define PWMB 11

●     Sensores (S1 a S8): Pinos analógicos configurados para receber os dados dos sensores de linha.

●     Motores e Ponte H: Pinos digitais configurados para controlar dois motores DC através de uma ponte H. STBY é usado para ativar/desativar os motores.

 

3. Variáveis Globais e Calibração

int sensores[8];
int limiar[8]; // utilizado para calibração
...
void setup() {
  ...
  for (int i = 0; i < 150; i++) {
    calibraFundo();
    calibraLinha();
  }
  ...
}

●     Arrays de calibração: Armazenam valores de calibração dos sensores para distinguir entre a linha e o fundo.

●     Calibração no setup(): Realiza múltiplas leituras para estabelecer um limiar de detecção antes do início das operações normais.

 

4. Loop Principal e Controle via Bluetooth

void loop() {
  if (BTSerial.available()) {
    String bluetoothData = BTSerial.readString();
    ...
  }

  if (isRunning) {
    ...
    runMotor(0, motorEsq, motorEsq > 0 ? 0 : 1);
    runMotor(1, motorDir, motorDir > 0 ? 0 : 1);
  } else {
    stop();
  }
}

●     Leitura Bluetooth: Verifica se há dados disponíveis vindo do módulo Bluetooth e executa comandos como iniciar ou parar o robô. Baseado no estado da variável isRunning

●     Controle de Motores: Calcula a correção necessária com base na posição da linha detectada e ajusta a velocidade dos motores para manter o robô alinhado.

 

5. Funções Auxiliares de Movimentação e Calibração

void calibraFundo() {...}
void calibraLinha() {...}
void runMotor(int motor, int spd, int dir) {...}
void stop() {...}

●     Calibração: Funções calibraFundo() e calibraLinha() leem os valores dos sensores para estabelecer um baseline e um limiar para a detecção de linha.

●     Movimentação: runMotor() controla individualmente os motores. stop() desativa os motores, colocando o robô em estado de espera.

 

O código completo do robô pode ser encontrado aqui: 

#include <QTRSensors.h>
#include <SoftwareSerial.h>

// Pinos para o módulo Bluetooth
SoftwareSerial BTSerial(6, 7); // RX, TX

// Pinos para os motores
#define AIN1 4
#define AIN2 3
#define PWMA 2

#define STBY 5

#define BIN1 8
#define BIN2 9
#define PWMB 11

QTRSensors qtr;
const uint8_t SensorCount = 8;
uint16_t sensorValues[SensorCount];

int lastError = 0;
boolean onoff = 0;
int val, cnt = 0, v[3];

const uint16_t threshold = 500;
const int maxspeeda = 255;
const int maxspeedb = 255;
const int basespeeda = 165;
const int basespeedb = 165;
const int minspeeda = 150;
const int minspeedb = 150;

float Kp = 0.3; // Ganho proporcional
float Ki = 0.0; // Ganho integral
float Kd = 0.6; // Ganho derivativo
uint8_t multiP = 1;
uint8_t multiI = 1;
uint8_t multiD = 1;

int P;
int I;
int D;
float Pvalue;
float Ivalue;
float Dvalue;

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  BTSerial.begin(9600);

  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]){A0, A1, A2, A3, A4, A5, A6, A7}, SensorCount);
  qtr.setEmitterPin(7);

  pinMode(STBY, OUTPUT);
  pinMode(AIN1, OUTPUT);
  pinMode(AIN2, OUTPUT);
  pinMode(PWMA, OUTPUT);
  pinMode(BIN1, OUTPUT);
  pinMode(BIN2, OUTPUT);
  pinMode(PWMB, OUTPUT);
  
  digitalWrite(STBY, HIGH);
  calibration();

  forward_brake(0, 0);
}

void calibration() {
  digitalWrite(13, HIGH);
  for (uint16_t i = 0; i < 400; i++) {
    qtr.calibrate();
  }
  digitalWrite(13, LOW);
}

void loop() {
  if (BTSerial.available()) {
    String bluetoothData = BTSerial.readString();
    Serial.println(bluetoothData);

    if (bluetoothData.indexOf("On") >= 0) {
      onoff = 1;
      digitalWrite(13, HIGH);
    } else if (bluetoothData.indexOf("Off") >= 0) {
      onoff = 0;
      digitalWrite(13, LOW);
      stop();
    }
  }

  if (onoff == 1) {
    robot_control();
  } else {
    stop();
  }

  delay(50); // Pequeno atraso para estabilidade
}

void robot_control() {
  uint16_t position = qtr.readLineBlack(sensorValues);
  int error = 3500 - position;

  PID(error);
}

void PID(int error) {
  int P = error;
  int I = I + error;
  int D = error - lastError;
  lastError = error;

  Pvalue = Kp * P;
  Ivalue = Ki * I;
  Dvalue = Kd * D;

  float motorspeed = Pvalue + Ivalue + Dvalue;

  int motorspeeda = basespeeda + motorspeed;
  int motorspeedb = basespeedb - motorspeed;

  motorspeeda = constrain(motorspeeda, minspeeda, maxspeeda);
  motorspeedb = constrain(motorspeedb, minspeedb, maxspeedb);

  speedcontrol(motorspeeda, motorspeedb);
}

void speedcontrol(int mota, int motb) {
  if (mota >= 0 && motb >= 0) {
    forward_brake(mota, motb);
  } else if (mota < 0 && motb >= 0) {
    mota = -mota;
    right_brake(mota, motb);
  } else if (mota >= 0 && motb < 0) {
    motb = -motb;
    left_brake(mota, motb);
  }
}

void forward_brake(int posa, int posb) {
  digitalWrite(AIN1, HIGH);
  digitalWrite(AIN2, LOW);
  analogWrite(PWMA, posa);

  digitalWrite(BIN1, HIGH);
  digitalWrite(BIN2, LOW);
  analogWrite(PWMB, posb);
}

void left_brake(int posa, int posb) {
  digitalWrite(AIN1, LOW);
  digitalWrite(AIN2, HIGH);
  analogWrite(PWMA, posa);

  digitalWrite(BIN1, LOW);
  digitalWrite(BIN2, HIGH);
  analogWrite(PWMB, posb);
}

void right_brake(int posa, int posb) {
  digitalWrite(AIN1, HIGH);
  digitalWrite(AIN2, LOW);
  analogWrite(PWMA, posa);

  digitalWrite(BIN1, HIGH);
  digitalWrite(BIN2, LOW);
  analogWrite(PWMB, posb);
}

void stop() {
  forward_brake(0, 0);
}

Video de funcionamento do Robô segue faixa

Conclusão

O desenvolvimento desse robô seguidor de linha proporcionou uma excelente oportunidade para aprender sobre planejamento, design e programação em robótica.

Utilizando os componentes descritos e as técnicas apresentadas, é possível construir um robô eficiente e pronto para competições. A implementação de melhorias como encoders e otimizações de código pode ainda elevar o desempenho do robô.