Tabela de conteúdos

Trabalho Final - Robôs Brigadistas

Introdução

O quarto trabalho prático, final, consistiu na integração das soluções já implementadas nos outros TPS. Foram utilizados:

Materiais

Robô

LDR de start

Sensor de cores

LDR Diferencial

Ópticos reflexivos

Procedimentos

Para esse TP, precisavamos consertar e/ou otimizar problemas anteriores, implementar novas soluções e integrar as já existentes, para isso, fizemos as seguintes tarefas:

- Um dos problemas do TP3 era o LDR Diferencial, que não funcionou como previsto. A fim de ter uma boa implementação, foi corrigido o problema. - Notamos que o robô estava demasiadamente grande, e pesado. Para otimizar a performance do robô, reduzimos as dimensões e peso do robô, sem prejudicar o seu bom funcionamento, e compactamos alguns componentes, como foi o caso do sensor de cores, que teve seu tamanho reduzido. - Notamos que também poderia ser vantajoso alterar a posição de alguns sensores, e assim fizemos com o optico-reflexivo e o sensor de cores, e foi bastante significativo as mudanças.

- A fim de poder iniciar o circuito como pedido, implementamos um sensor para a luz de start. Esse sensor é bem simples, no qual é constituido de LDR e uma resistencia, no qual, quando a luz de start incide sobre ele, um sinal é enviado ao arduino, demonstrando que iniciou a prova, e partir daí ele toma as devidas decisões.

  1. Foi necessário a criação de acrescer ao robô essa nova função, devido a demanda do trabalho, e sendo assim acrescemos um novo braço a ele, para manusear as peças no campo.
  1. Fazer a junção das soluções já implementadas anteriormente e necessárias para o atual desafio, e unir os códigos dessas implementações em um código de uma única tarefa, e definir as melhores estratégias para a melhor performance do robô.
  2. Uma das decisões tomadas, era que não seria necessário o uso de um encoder, pois seriamos orientados pela linhas que estão no chão.

Documentação do código

Foi utilizado várias funções já citadas anteriormente nos outros trabalhos, que são:

Seguidor de linha

O código do Seguidor de Linha é representado abaixo:

void pretobranco(){
  Serial.print("Leitura2");
  lcd.print("ESQUERDA");
  Serial.println();
  //MoverControladoAngulo(90);
  motor1->run(FORWARD);
  motor2->run(FORWARD); 
  motor1->setSpeed(35);
  motor2->setSpeed(60);   
 }
 void brancopreto(){
  Serial.print("Leitura3");
  lcd.print("Direita");
  Serial.println();
  //MoverControladoAngulo(-90);
  motor1->run(FORWARD);
  motor2->run(FORWARD); 
  motor1->setSpeed(60);
  motor2->setSpeed(35); 
 }
 void brancobranco(){
  Serial.print("Leitura1");
  lcd.print("RETO");
  Serial.println();
  motor1->run(FORWARD);
  motor2->run(FORWARD); 
  motor1->setSpeed(60);
  motor2->setSpeed(60); 
 }
 void leitura(){
  while(1){
  Serial.print(digitalRead(S2));
  Serial.print(digitalRead(S1));
  if(digitalRead(S1) == 0 && digitalRead(S2) == 0){   //VIRA PRA ESQUERDA 90º
  int i=0;
  Serial.print("Leitura0");
  lcd.print("Direita");
  Serial.println();
  motor1->run(RELEASE);
  motor2->run(RELEASE);  
  delay(800);
   Serial.print("Andou pra frente");
  while(i != 200){
  motor1->run(FORWARD); //Vai um pouco pra frente (vai estar lendo só branco)
  motor2->run(FORWARD); 
  motor1->setSpeed(56.4);
  motor2->setSpeed(60);  
    if(digitalRead(S1) == 1 && digitalRead(S2) == 1){
      i++;
    }
  }
  i=0;
  motor1->run(RELEASE);
  motor2->run(RELEASE);
  delay(800);
   Serial.print("fez angulo");
   MoverControladoAngulo(90);
   Serial.print("andou pra tras");
  motor1->run(BACKWARD);  //Volta um pouco pra trás;
  motor2->run(BACKWARD); 
  motor1->setSpeed(60);
  motor2->setSpeed(60);
  delay(1300);
  Serial.print("proximo");
  motor1->run(RELEASE);
  motor2->run(RELEASE);
  delay(800);
  ResetarPID(); 
  }
   //vai linha reta
   if(digitalRead(S1) == 1 && digitalRead(S2) == 1){ // SEGUE RETO
    brancobranco();    
   }
   //vai para esquerda
   if(digitalRead(S1) == 1 && digitalRead(S2) == 0){ //VIRA PRA ESQUERDA
  pretobranco();  
   }
   //vai para direita
   if(digitalRead(S1) == 0 && digitalRead(S2) == 1){ //VIRA PRA DIREITA
    brancopreto();
   }
   }
 }

Sensor de cores

O código do sensor era composto por 4 funções básicas, nas quais eram: Calibragem(), Reconhecimento_Blocos(), Leitura() e ConvertRGB(int atual, char palavra[4]).

A função Calibragem() é chamada apenas no setup, onde ela calibra o sensor para os valores mínimos e máximos de cada cor que serão lidos pelo arduino, no qual se pede uma superficie branca e outra preta para se ter os valores.

A função Leitura() é a que fica por conta de fazer verificar de fato a leitura da cor, onde, primeiro liga o LED vermelho por 0,1s e lê o valor que está no pino 8 do Arduino, e registra esse valor em uma variável e repete o procedimento para os leds verde e azul. e no fim da leitura dos 3 LEDS, ele espera por 0,3s.

A função ConvertRGB tem como função converter o valor do LDR, que pode variar de 0 a 1023 para cada uma das 3 cores, para valores do padrão da representação numérica RGB, que varia de 0 a 255. A função recebe dois parametros, onde um é a leitura no formato analógico, e uma string com 4 caracteres que se refere a qual cor aquela leitura, na qual pode ser “verm”, “verd”, e “azul” (Que são os valores de cada um dos 3 leds). Após isso, a função retorna o valor da superficie lida no padrão numérico RGB.

A função Reconhecimento_Blocos() tem como função aprender os valores RGB de cada um dos blocos da apresentação, e salva os valores nos vetores blocoVermelho[3], blocoVerde[3], blocoAzul[3] e blocoAmarelo[3], onde a posição [0] dos vetores corresponde a cor vermelha, a [1] corresponde a verde, e a [2] corresponde a azul. Com isso, ele aprende qual é a cor do bloco para posteriormente poder ler e comparar com esses valores.

Abaixo estão os códigos de cada uma das funções:

FUNÇÃO CALIBRAGEM

 void Calibragem(){
//CALIBRAGEM BRANCO
int botao; 
botao = analogRead (0);
do{
  botao = analogRead (0);
  lcd.setCursor(0,0);  
  lcd.print("PAPEL BRANCO:");
  lcd.setCursor(0,1);  
  lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800));
lcd.clear();
lcd.setCursor(0,0);  
lcd.print("PAPEL BRANCO:");
lcd.setCursor(0,1);  
lcd.print("Calibrando.");
digitalWrite(PinVerm, 1);
delay(100);
VermMax = analogRead(sensorPin);
digitalWrite(PinVerm, 0);
lcd.print(".");
digitalWrite(PinVerd, 1);
delay(100);
VerdMax = analogRead(sensorPin);
digitalWrite(PinVerd, 0);
lcd.print(".");
digitalWrite(PinAzul, 1);
delay(100);
AzulMax = analogRead(sensorPin);
digitalWrite(PinAzul, 0); 
lcd.clear(); // CALIBRAGEM DE PRETO
do{
  botao = analogRead (0);
  lcd.setCursor(0,0);  
  lcd.print("PAPEL PRETO:");
  lcd.setCursor(0,1);  
  lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800));
lcd.clear();
lcd.setCursor(0,0);  
lcd.print("PAPEL PRETO:");
lcd.setCursor(0,1);  
lcd.print("Calibrando.");
digitalWrite(PinVerm, 1);
delay(100);
VermMin = analogRead(sensorPin);
digitalWrite(PinVerm, 0);
lcd.print(".");
digitalWrite(PinVerd, 1);
delay(100);
VerdMin = analogRead(sensorPin);
digitalWrite(PinVerd, 0);
lcd.print(".");
digitalWrite(PinAzul, 1);
delay(100);
AzulMin = analogRead(sensorPin);
digitalWrite(PinAzul, 0);
lcd.clear();
}

FUNÇÃO LEITURA

  void Leitura(){  
digitalWrite(PinVerm, 1); // Leitura Pino Vermelho
delay(100);
int sensor_val = analogRead(sensorPin);
Red = ConvertRGB(sensor_val,"verm");
digitalWrite(PinVerm, 0);
digitalWrite(PinVerd, 1); // Leitura Pino Verde
delay(100);
sensor_val = analogRead(sensorPin);
Green = ConvertRGB(sensor_val,"verd");
digitalWrite(PinVerd, 0);
digitalWrite(PinAzul, 1); // Leitura Pino Azul
delay(100);
sensor_val = analogRead(sensorPin);
Blue = ConvertRGB(sensor_val,"azul");
digitalWrite(PinAzul, 0);
delay (300);
}

FUNÇÃO DE RECONHECIMENTO DOS BLOCOS

 
void Reconhecimento_Blocos(){
int botao; 
botao = analogRead (0);
lcd.clear(); // Reconhecimento Bloco Vermelho 
do{
botao = analogRead (0);
lcd.setCursor(0,0);  
lcd.print("BLOCO VERMELHO:");
lcd.setCursor(0,1);  
lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800));
Leitura();
blocoVermelho[0] = Red;
blocoVermelho[1] = Green;
blocoVermelho[2] = Blue;
lcd.clear(); // Reconhecimento Bloco Verde
do{
botao = analogRead (0);
botao = analogRead (0);
lcd.setCursor(0,0);  
lcd.print("BLOCO VERDE:");
lcd.setCursor(0,1);  
lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800));
Leitura();
blocoVerde[0] = Red;
blocoVerde[1] = Green;
blocoVerde[2] = Blue;
lcd.clear(); // Reconhecimento Bloco Azul
do{
botao = analogRead (0);
lcd.setCursor(0,0);  
lcd.print("BLOCO AZUL:");
lcd.setCursor(0,1);  
lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800));
Leitura();
blocoAzul[0] = Red;
blocoAzul[1] = Green;
blocoAzul[2] = Blue; 
lcd.clear(); // Reconhecimento Bloco Amarelo
do{
botao = analogRead (0);
lcd.setCursor(0,0);  
lcd.print("BLOCO AMARELO:");
lcd.setCursor(0,1);  
lcd.print("Aperte Select");
}while(not(botao >= 600 & botao < 800)); 
Leitura();
blocoAmarelo[0] = Red;
blocoAmarelo[1] = Green;
blocoAmarelo[2] = Blue;
lcd.clear(); 
}

FUNÇÃO DE CONVERSÃO PARA O PADRÃO RGB

int ConvertRGB(int atual, char palavra[4]) // Convertendo para o formato de cores RGB{
if (palavra == "verm")
{
  float aux = (float(atual) - float(VermMin)) / (float(VermMax) - float(VermMin));
  aux = aux*255;
  if (aux > 255)
  return (255);
  else if (aux <0)
  return (0);
  else
  return (aux);
}  
else if (palavra == "verd")
{
  float aux = (float(atual) - float(VerdMin)) / (float(VerdMax) - float(VerdMin));
  aux = aux*255;
  if (aux > 255)
  return (255);
  else if (aux <0)
  return (0);
  else
  return (aux);
}  
else if (palavra == "azul")
{
  float aux = (float(atual) - float(AzulMin)) / (float(AzulMax) - float(AzulMin));
  aux = aux*255;
  if (aux > 255)
  return (255);
  else if (aux <0)
  return (0);
  else
  return (aux);
}
}

A função Loop usa as funções pré-estabelecidas chamando a função Leitura, e verificando as variáveis Red, Green e Blue, que são os valores já convertidos para o padrão RGB, e compara se os valores são próximos (com um grau de sensibilidade) aos registrados nos vetores dos blocos, como descritos acima. Após os testes lógicos, ele imprime na tela a cor do bloco e altera o valor da variável global Cor_Bloco para o valor respectivo de cada bloco, e caso se a cor não for a de nenhum bloco, ele imprime “Sem Bloco”, e variável Cor_Bloco continua 0. Essa variável serve para que no modo Multitarefas, ele chame a função e só teste o valor da variável global, para saber qual será a ação a ser realizada.

LDR Diferencial

Como o LDR diferencial foi construído em paralelo, nosso código consiste em executar uma volta e pegando os valores de máximo e minimo. Uma vez coletados estes e sabendo que o robô pode estar ou no lado cujo filtro é horizontal ou vertical temos as seguinte situação:

a) O robô está no lado com o filtro horizontal. Quando o robô está nesse lado as leituras captadas pelo LDR se encontram na faixa de 200, com exceção de quando esse se encontra alinhado ou quase alinhado quando as leituras atingem seu mínimo próximo de 100.

b) O robô está no lado com o filtro vertical. Quando o robô está nesse lado as leituras do LDR mais uma vez encontram-se em valores próximos de 200 alterando, novamente, quando o robô está quase alinhado que tais valores atingem seu máximo cima de 400.

A partir desses conhecimentos sabemos que se a leitura de máximo for superior a 400 ele se encontra do lado com o filtro vertical, nesse caso devendo permanecer girando até encontrar um valor próximo do máximo. Caso contrário o valor procurado é o de mínimo e o robô deverá permanecer em movimento até um valor da janela de máximo ser atingido.

O código encontra-se abaixo:

void orienta(){///Colocar e o cabeçalho da função também

int ldrDifValor = 0; 
int Max = 0 ;
int Min = 1023;
long previousMillis = millis();
long interval = 2500;

motor1->setSpeed(50);
motor1->run(FORWARD);
motor2->setSpeed(50);
motor2->run(BACKWARD);
ldrDifValor = analogRead(ldrDif);
//delay(300);
while(millis() - previousMillis < interval){
  ldrDifValor = analogRead(ldrDif);
  Max = max(ldrDifValor,Max);
  Min = min(ldrDifValor,Min);
  }//Peimeira volta
if(Max > 400){
    while((analogRead(ldrDif) > Max + 10)||(analogRead(ldrDif) < Max - 10)){
      }
      motor1->run(RELEASE);
      motor2->run(RELEASE);
    }
else{
     while((analogRead(ldrDif) > Min + 10)||(analogRead(ldrDif) < Min - 10)){
      }
      motor1->run(RELEASE);
      motor2->run(RELEASE);
      }
}

Tal código foi construído da seguinte maneira:

  1. Fazer as leituras com o sensor e garantir seu funcionamento adequado, ou seja, não realizando medidas incoerentes.
  2. O robô faz as leituras imprimindo-as no LCD enquanto ele dá uma volta
  3. Girar o robô fazendo as leituras de máximo e mínimo. Ao término da volta imprime os valores de máximo e mínimo
  4. Função de localizar completa

E os novos códigos que foram implementados para o atual trabalho, que são o da estratégia a ser feita e o do LDR de start:

Sensor de Start

O sensor de Start foi de simples implementação já que seu valor fica próximo de zero na ausência de luz e ultrapassa 400 quando com luz. Seu código consiste em apenas em fazer leituras até que um valor maior que o estipulado seja captado.

void loop() {
ldrValor = analogRead(ldr);
if(ldrValor > 500){
  motor1->setSpeed(50);
  motor1->run(FORWARD);
  motor2->setSpeed(50);
  motor2->run(FORWARD);
 }
}

Algoritmo da estratégia

A estratégia consistia em fazer um percurso com o seguidor de linha e com isso coletando os blocos e leva-los até a base. Inicialmente pretendia-se fazer com que os blocos pretos fossem evitados

Resultados

Colocação na competição: 7ºLugar (Penúltimo)

Apresentação do grupo:

trabalho_final_1.2_sem_fotos.pptx

Problemas encontrados

Durante a execução das tarefas grande parte das tarefas exigiu que melhorássemos as coisas anteriormente produzidas. Tentamos suavizar os movimentos do seguidor de linha e na hora de unirmos as partes de código dos respectivos sensores tivemos dificuldade em fazer com que o robô simultaneamente seguisse linha e rejeitasse blocos pretos.

Pontos a melhorar

Uma possível melhora de se fazer seria na garra do robô, uma vez que ela não mantem os bloquinhos presos ao robô sob nenhuma circunstância. Fazer uma integração entre o seguidor de linha e a função de localização de modo que uma vez que o robô pegasse a linha central e chegasse próximo a linha da base ele parasse de seguir linha e passasse a utilizar das leituras do LDR diferencial para nela adentrar. A garra do robô também ficou bem simples não sendo capaz de carregar o bloco ou esfera até a base ou mante-lo preso.

Portifolio