quinta-feira, 12 de julho de 2012

Robô de sumô 500g



O robô mostrado aqui foi construído para participar de campeonato de sumô de robôs na categoria quinhentas gramas. Neste tipo de competição o robô deve mover-se dentro de uma arena preta com bordas brancas procurando seu oponente para empurra-lo para fora da arena. Na categoria do Eniac Jr., como foi batizado, além de não poder pesar mais que quinhentos gramas, o robô não deve ter largura e comprimento superiores a 10 cm. 

A estrutura

 A estrutura é composta basicamente por duas placas de compensado 4 mm e quatro pedaços de barra roscada de 4mm de diâmetro e 9cm de comprimento. Na primeira plataforma (8cm x 6 cm) estão os servo motores, presos por abraçadeiras, e os sensores de linha. Na segunda (10cm x 8 cm), o arduino com uma sensorshield, que é a placa sobre o arduino, usada para facilitar a conexão dos sensores e servos, o UBEC (regulador 5V x 5A), é necessário pro que os servos são forçados e não é conveniente alimenta-los diretamente pelo arduino. O sensor de oponente e demais componentes eletrônicos também estão na segunda plataforma. 
Apenas duas rodas são usadas. Foram adaptadas do rolo de tração de uma velha impressora. Uma pequena chapa de alumínio substitui a roda frontal.

A eletrônica

Sensor de linha




Os motores usados são servomotores modificados para rotação. Usar servos trás a vantagens deles já possuirem circuito de acionamento interno, necessitando apenas do sinal de controle e alimentação que neste caso e de 5 V/ 5A, provida por um UBEC (Universal Battery Eliminator Circuit). A bateria usada é uma LIPO 3 células 1300 mAh.


 Sensores


O Eniac Jr possui quatro sensores. Tanto os dois sensores de linha frontal quanto o sensor de linha traseira, que não está sensdo usado por ainda não ser necessário no programa, foram montados conforme digrama ao lado.

O quarto sensor é usado para detectar o oponente. Trada-se de um sensor infravermelho sharp GP2Y0A21. Um excelente sensor para este tipo de aplicação por sua velocidade e facilidade de uso.

O microcontrolador

Para controlar o robô foi escolhido o arduino, uma plataforma excepcional por sua capacidade, versatilidade e enorme quantidade de material de consulta. Este projeto está usando o arduino Uno, equipado com o atmega 328, o mais comumente usado hoje. Talvez fosse melhor usar o arduino mini 3.0 por seu tamanho reduzido.

O código fonte que embarca o arduino pode ser visto, com comentários, abaixo. É um programa básico pretendo incrementa-lo. A dinâmica de funcionamento é a seguinte:

Depois de ligado o robô aguada cinco segundos e inicia seu funcionamento andando para frete. Caso encontre a linha branca retorna e gira em torno de si mesmo procurando o oponente com auxilio do sensor frontal. Se encontrar o oponente o robô para de girar e volta a andar para frete. Não encontrando o adversário ele anda para frente após o fim do tempo de procura.



  #include <Servo.h>  
  Servo esquerdo;   
  Servo direito;   
  //******************* PINOS **********************//  
  int direito_pin = 10;  
  int esquerdo_pin = 11;  
  int SLF_esq = 8;  // pino do sensor de linha frontal esquerdo  
  int SLF_dir = 9;  // pino do sensor de linha frontal direito  
  int led_pin = 13;  // led no pino 13  
  int sens_front = 5; // pino do sensor oponente frontal (SHARP)( pino analogico 0 )  
 //****************** VARIAVEIS ******************//  
  long cm;    // variaveis para sensor frontal  
  float sharp = 0;  // usada na leitura dos sensores analogicos  
  float distancia = 0; // usada na leitura dos sensores analogicos  
  int tmp_Re = 5;  // tempo de reversão dos motores quando o robo encontra a linha*200 milissegundos  
  int tmp_Busc =3.4; // tempo de procura do adverssario, girando, em segundos  
  long raio_front = 35; // raio de procura frontal em centimetros  
  long tmpRound = 90000;  // tempo do round 90.000 milissegundos. 1 minuto e 30 segundos  
  long prev_tmpRound;  // variavel para contar tempo do round  
  unsigned long current_tmpRound; // variavel para contar tempo do round  
  long previousMillis;  // variavel para contar tempo entre buscas  
  unsigned long currentMillis; // variavel para contar tempo entre buscas  
  int aux_SLF = 0; // auxiliar para leitura do sensor de linha frontal  
  int aux_SLT = LOW; //0; // auxiliar para leitura do sensor de linha traseiro  
  int aux_front = 0;  // auxiliar para leitura do sensor frontal  
 //**************** SETUP *****************************//  
 void setup() {   
  Serial.begin(19200);   
  pinMode(led_pin, OUTPUT);  
  pinMode(SLF_esq, INPUT);  
  pinMode(SLF_dir, INPUT);  
 // conta os cinco segundos piscando o led do pin 13  
  for(int conte = 0; conte < 5; conte++)   
  {  
   digitalWrite(led_pin, HIGH);  
   delay(300);  
    digitalWrite(led_pin, LOW);  
   delay(700);  
  }  
  esquerdo.attach(esquerdo_pin,1000,2000);  //servo1 no pino 2, min, max  
  direito.attach(direito_pin,1000,2000);  //servo1 no pino 3   
  prev_tmpRound = millis();  // prev_tmpRound recebe o tempo atua de execução do programa marcando a contagem do round  
  current_tmpRound = millis();  
  // procurar(); // inicia procurando o oponente  
 }  
 //***************** FIM SETUP ****************************//  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
  ///////////////////////////////////////////////FUNÇÃO PRINCIPAL///////////////////////////////////////////////////////////////////  
 void loop()   
 {  
  int a1 =0;  
  int proc = 0;  
  int cnt =0;  
  int cnt_tmp =0;  
  static int direcao = LOW;  
  frente();  
  aux_SLF = ler_digital(SLF_esq , SLF_dir); // verifica sensor frontal de linha ( HIGH para branco LOW para preto)  
 // aqui o robo comeca efetivamente seu trabalho andar no tatame a procurar o oponente   
 // ele para apos 90 segundos (tempo do round)  
  do    
  {     
   if(aux_SLF == HIGH) // se um dos sensores de linha dianteiros encontrou a linha branca  
    {  
      re();  
      while(cnt_tmp < tmp_Re*4)  
      {  
       delay(50);  
       cnt_tmp++;  
      }  
      cnt_tmp =0;  
      procurar();  
    }  
   else  
    {  
    frente(); //se nenhum dos sensores for acionado continua indo em frente  
    }  
     aux_SLF = ler_digital(SLF_esq , SLF_dir); // verifica sensor frontal de linha ( HIGH para branco LOW para preto)  
  current_tmpRound = millis(); // atualisa current_tmpRound com o tempo atua de execução do programa  
   }while(current_tmpRound - prev_tmpRound <= tmpRound);//O ROBO ANDA ATE SE PASSAR O TEMPO DE UM ROUND  
   parar(999999); // para o robo após fim do round  
 } // fim do void loop()  
 ///////////////////FUNÇÃO PARAR /////////////////////  
 // como a modificação dos servos não ficou 100% é dificil para-los totalmente  
 void parar(int time)  
 {  
   direito.write(92.5);  
   esquerdo.write(89.5);  
   delay(time);  
 }  
 ///////////////////FUNÇÃO FRENTE /////////////////////  
 void frente()  
 {  
   direito.write(0);  
   esquerdo.write(180);  
 }  
 ///////////////////FUNÇÃO RÉ /////////////////////  
 void re()  
 {  
   direito.write(180);  
   esquerdo.write(0);  
 }  
 ///////////////////FUNÇÃO DIREITA /////////////////////  
 void direita()  
 {  
   direito.write(180);  
   esquerdo.write(180);  
 }  
 ///////////////////FUNÇÃO ESQUERDA /////////////////////  
 void esquerda()  
 {  
   direito.write(0);  
   esquerdo.write(0);  
 }  
 ///////////////////FUNÇÃO ler sensores analogicos sharp/////////////////////  
 // adaptada de:  
 /* www.ebay.com/itm/5-x-Arduino-IR-Sensor-GP2Y0A21YK0F-Measuring-Detecting-Distance-  
 10-80cm-/261031972852?_trksid=p4340.m263&_trkparms=algo%3DSIC%26its%3DI%252BC%26itu%3DUCI%  
 252BIA%252BUA%252BFICS%252BUFI%26otn%3D15%26pmod%3D260944545770%26ps%3D63%26clkid%3D56665851  
 1840405440&_qi=RTM1062687 */  
 int ler_analog(int sensor, int raio)  
 {  
  sharp = analogRead(sensor);   
  distancia = (6762/(sharp-9))-4;  
  if(distancia <= raio)  
  {  
  digitalWrite(led_pin, HIGH);   
  return(HIGH); // retorna HIGH caso o opnente esteja dentro do raio de alcance definido  
  }  
  else  
  {  
  digitalWrite(led_pin, LOW);  
  return(LOW); // retorna LOW caso o opnente NÃO esteja dentro do raio de alcance definido  
  }  
 }  
 ///////////////////FUNÇÃO ler sensores digitais /////////////////////  
 int ler_digital(int sens1 , int sens2)  
 {  
  if(digitalRead(sens1) == LOW || digitalRead(sens2) == LOW)  
  return(HIGH);  
  else  
  return(LOW);  
 }  
 ////função procura oponete chamada depois que o robo encontra a linha e da re/////////////////////////////  
  void procurar()  
  {  
   int cnt1 =0;  
   int a =0;  
   static int direcao = LOW;  
   static int aux_sFront_ant = LOW;  
   static int aux_sFront = LOW;  
  previousMillis = millis();  
  currentMillis = millis();  
     aux_front = ler_analog(sens_front, raio_front); // verifica sensor procura frontal  
     aux_SLF = ler_digital(SLF_esq , SLF_dir); // verifica sensor frontal de linha ( HIGH para branco LOW para preto)  
  while(currentMillis - previousMillis <= (tmp_Busc * 1000) && aux_SLF != HIGH && aux_front != HIGH)  
  {  
   direita();  
   delay(30);  
  currentMillis = millis();  
  aux_front = ler_analog(sens_front, raio_front); // verifica sensor procura frontal  
  aux_SLF = ler_digital(SLF_esq , SLF_dir); // verifica sensor frontal de linha ( HIGH para branco LOW para preto)  
  }  
  }