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.
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:
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ô.