Ferramentas do usuário

Ferramentas do site


cursos:introrobotica:2017-1:grupo05:competicao

Competição - Robôs Antibombas

1. Objetivo:

A competição de robótica de 2017-1 teve como objetivo a construção e programação de um robô autônomo capaz de localizar, detectar e remover minas terrestres, conforme regras descritas em:

http://homepages.dcc.ufmg.br/~doug/cursos/doku.php?id=cursos:introrobotica:2017-1:competicao.

2. Tática:

A tática inicial divulgada era a de: “navegar pelo campo e capturar o bloco de maior pontuação (bloco azul) e retornar para a base, depois capturar o maior número de blocos possível”. Cada bloco corresponde a um tipo de mina terrestre, relacionada a uma pontuação específica ao ser capturada ou capturada e levada para uma área específica do campo.

Entretanto, a tática descrita anteriormente teve como objetivo a divulgação de uma contra-informação, uma vez que internamente a tática adotada foi a de: “navegar pelo campo e capturar o bloco azul, retornando para a base. Segue abaixo o vídeo representando a tática final:”

3. O robô Mandela:

O robô Mandela, utilizado na comperição é fruto da composição dos dois últimos trabalhos práticos desenvolvidos: TP2 – Robótica móvel (locomoção) e TP3 – Robótica móvel (navegação e controle) cujos respectivos links são:

A partir desses dois trabalhos anteriores foi desenvolvido o robô para a competição final, introduzindo alterações e implementações de forma atender as especificações da competição.

O robô Mandela teve a composição desmembrada em três partes: mecânica, eletrônica embarcada e software embarcado. As seções seguintes descrevem cada uma das partes.

2. Mecânica:

Grande parte da composição mecânica do robô foi herdada dos trabalhos anteriores: TP2 – Robótica móvel (locomoção) e TP3 – Robótica móvel (navegação e controle):

No robô projetado para a competição, as alterações mecânicas consistiram na montagem da base do robô de forma que a mesma ficasse “mais alta”, assim, ao detectar um bloco e esse bloco for um bloco válido, o robô sobrepõem o bloco, arrastando-o em direção à base. Durante a etapa de montagem e testes, verificou-se que o compartimento interno do robô tinha espaço suficiente para armazenar quatro (4) blocos.

As figuras abaixo exibem a disposição dos motores elétricos utilizados para a locomoção, a transmissão mecânica da caixa de engrenagens para as rodas e a montagem mecânica final do robô Mandela.

Motores elétricos Transmissão Montagem mecânica final

3. Eletrônica embarcada

Assim como na seção mecânica, foi usada na seção de eletrônica embarcada vários dos elementos usados nos dois últimos TP's (TP2 e TP3). A base central da eletrônica embarcada consiste na placa Arduino mega2560, associada a uma montagem do tipo pilha em que são encaixadas as placas de driver para acionamento e controle dos motores elétricos e por último a placa contendo o teclado e o LCD alfanumérico 16×2 (16 colunas e 2 linhas). As interconexões com os demais periféricos são dadas através de uma placa auxiliar fornecida pelo Prof. da disciplina de Introdução à Robótica.

As figuras abaixo exibem as três primeiras placas anteriomente citadas:

arduino-mega-2560.jpg adafruit-motor-shield-v2.jpg shielddisp.jpg
Arduino mega2560 Shield: Display e Teclado Shield: Driver do Motor

Abaixo, são exibidos os sensores montados no robô Mandela:

LDR Diferencial Break-beam Óptico-Reflexivo
LDR/LED p/ detecção de objetos Bumper

3.1. Orientação:

Para resolver a tarefa de alinhar o robô com a fonte de luz polarizada, foi feita uma montagem utilizando dois sensores LDR e filtros polarizadores. Sua configuração final segue abaixo:

Divisor de tensão O sensor LDR é um resistor cuja resistência varia de acordo com a intensidade da luz que incide sobre ele. Seu funcionamento típico é: à medida que a intensidade da luz aumenta, a sua resistência diminui. Dessa forma, na escuridão, o LDR possui uma resistência máxima, e na luz muito brilhante, sua resistência é mínima. Já um LDR diferencial nada mais é do que dois sensores LDR ligados em série, com um ponto de medição inserido entre estes sensores.

Para a montagem física dos sensores, os LDRs foram posicionados separados por uma parede de lego. Em frente a cada sensor LDR havia um filtro polarizador.

//LDR// Diferencial

Ambas as resistências (R1 e R2) do circuito são variáveis, uma vez que o valor de suas resistências variam de acordo com a intensidade luminosa incidente. Ao montar um divisor de tensão, obtém-se a equação correspondente exibida acima:

Através da equação, observa-se que a tensão de saída (V_LDR) é diretamente proporcional à resistência (R2) do sensor LDR. Ou seja, a tensão de saída será maior com um índice de luminosidade incidente menor. O circuito do divisor de corrente segue ao lado:

O filtro polarizador funciona como uma fenda para uma direção certa. Ou seja, o filtro polarizador deixa passar a parte da onda que oscila em um determinado plano. A figura abaixo demonstra o que foi citado anteriormente:

Filtro Polarizador A luminária utilizada no projeto emite uma luz polarizada. Dessa forma, só passa luz pelo filtro caso as ondas provenientes da luz estejam alinhadas a um ângulo de 0, 180 ou 360 graus. Caso a diferença de fase seja de 90 ou 270 graus a passagem de luz é nula. Dessa forma, o filtro tinha a função de controlar a intensidade de luz recebida pelos sensores LDR.

O sensor do tipo bumper foi instalado na frente do robô de forma a indicar possíveis colisões com as paredes delimitadoras do campo, com as paredes laterais da rampa onde se encontra o bloco azul ou ainda com o robô do grupo oponente. Inicialmente foi estabelecido um uso simples para o sensor, onde ao ser acionado, os motores do robô são desenergizados e dependendo da orientação prévia do robô uma nova estratégia de navegação pode ser tentada.

3.2. Navegação:

Os sensores utilizados para a navegação do robô foram dois (2) sensores opto-reflexivos para detecção da faixa no campo e dois (2) sensores do tipo break-beam cada um posicionados em um dos eixos da caixa de transmissão.

Os sensores opto-reflexivos utilizados para a detecção de faixa são do tipo infra-red, em que para cada par de sensores, tem-se um deles cumprindo a função de emissor de infra-red e o outro receptor de infra-red. Os emissores são conectados nas saídas digitais da placa Arduino mega2560, enquanto os receptores são conectados nas entradas analógicas da mesma placa. Assim, durante à navegação do robô, ao detectar uma faixa, devido a mesma ser enegrecida, haverá uma discrepância de reflexão muito grande, ocasionando uma tensão analógica diferente dos casos onde o campo tem cor branca (reflexão máxima).

Os dois (2) sensores do tipo break-beam instalados em cada eixo da caixa de transmissão, foram utilizados para transduzirem a rotação (em rad/s) de cada uma das rodas do robô. Portanto, esses sensores auxiliam na navegação do robô de forma indireta, fornecendo a rotação/tempo de cada roda para a implementação do algoritmo de controle dos motores do tipo PID (no robô Mandela, somente o controle do tipo Proporcional e Integral foram utilizados). O princípio de funcionamento do sensor break-beam é similar ao do sensor de faixa, com a diferença de que os pares de emissor e receptor são instalados um de frente para o outro, de forma a ter o feixe de infra-red interrompido na passagem de uma roda com furo, onde o deslocamento dessa roda transduz o deslocamento da roda do robô em rad/s. Assim, informações sobre a quantidade de movimento de cada roda bem como a distância percorrida por cada roda podem ser obtidas.

3.3. Odometria:

Os sensores de odometria utilizados foram os sensores do tipo break-beam

3.4. Odometria:

4. Software Embarcado

Assim como nos trabalhos anteriores, todo o software embarcado foi composto em C/C++ utilizando o framework Arduino para uma placa microcontrolada base do tipo Arduino Mega2560. As subseções abaixo descrevem a implementação de cada tarefa sob a perspectiva do software.

4.1 Localização – Identificação da fonte de luz polarizada:

Para identificar a fonte de luz mais pŕoxima, o robô faz um giro de 360^o (em torno de seu eixo Normal) armazenando os valores de entrada dado pelos LDRs. O menor valor lido após esse movimento de rotação é onde a fonte de luz mais próxima está. A localização (ângulo correspondente medido pelos encoders) foi sendo armazenada à medida que uma entrada menor era recebida. Feito isso, o robô voltava para a posição armazenada (posição da luz mais pŕoxima). O algoritmo correspondente segue abaixo:

// Condicao de parada
// Verifica se os motores atingiram o num de voltas 
// necessaria para o ang requisitado (360)
if((leftEncCount>=ligthLeftEncoder)&&(rightEncCount>=ligthRightEncoder)){
  getOutLp = 1; // Sai do loop
}
 
// Gira o robo 360 graus para a direita
leftMotor->run(FORWARD);
leftMotor->setSpeed(leftMotorSpeed);
rigthMotor->run(BACKWARD);
rigthMotor->setSpeed(rigthMotorSpeed);
 
// Faz a leitura dos encoderes
leftEncState = digitalRead(leftEncoder);
rightEncState = digitalRead(rigthEncoder);
 
// Verifica borda de descida do encoder esquerdo
if(leftEncState == HIGH) {
  if(oldLeftEncState == LOW) {
    leftEncCount++;
  }
}else { //Verifica borda de subida
  if(oldLeftEncState == HIGH) {
    leftEncCount++;
  }
}
 
// Verifica borda de descida do encoder direito
if(rightEncState == HIGH) {
  if(oldRightEncState == LOW) {
    rightEncCount++;
  }
}else { //Verifica borda de subida
  if(oldRightEncState == HIGH) {
    rightEncCount++;
  }
}
 
// Faz a leitura do sensor ldr
ldrInputValue = analogRead(ldr);
 
// Verifica se o ponto luminoso eh maior
// O ponto luminoso ocorre qnd o ldr faz uma leitura pequena
if(ldrInputValue < minLdrValue) {
  minLdrValue = ldrInputValue;
  ligthLeftEncoder = leftEncCount;
  ligthRightEncoder = rightEncCount;
}
 
oldRightEncState = rightEncState;
oldLeftEncState = leftEncState;

Segue abaixo o vídeo da versão final da localização da luz polarizada:

4.2. Odometria e Controle

Foram utilizados sensores break-beam para construir shaft-encoders. Foi implementado um controlador do tipo PD para controlar a velocidade do robô. Além disso, o robô é capaz de realizar um determinado caminho com uma distância selecionada através do menu (Reta, Quadrado, Triângulo).

Os Sensores break-beam foram usados para medir a variação (rotação) do eixo da roda. Dessa forma era possível obter: quão rápido as rodas estão girando e o número total de rotações. Um disco perfurado foi colocado sobre o eixo, entre o par de emissor-detector. À medida que o eixo girava, os furos no disco cortam o feixe de luz na velocidade do giro. As rotações foram contadas a partir do número de bordas de subida e descida. A montagem do encoder segue abaixo:

Montagem do encoder

A distância agora é controlada pelo valor retornado pelos encoders do motor direito e esquerdo. Primeiramente foi necessário medir quantas bordas de subida e descida os encoderes retornavam para uma volta de 360 graus das rodas. O valor final retornado pelo encoder foi obtido de forma empírica (foram feitas várias medidas para obter o melhor valor correspondente).

Considerando que a roda tem 8cm de diâmetro, a distância translacional do robô correspondia a 25,13cm (d = 2*pi*R = 25,13cm). O valor de bordas retornado pelos encoderes foi 22. Através de uma regra de três simples, foi obtido o ganho (= 0.48) que deveria ser multiplicado pelas distâncias requisitadas (dadas em centímetro).

O mesmo foi feito para descobrir o valor correspondente do número de rotação do encoder para o ângulo em graus. Nesse caso, foi medido quantas bordas os encoders retornavam para um giro de 360 graus do robô (em torno de seu eixo Normal). O algoritmo utilizado para resolver o problema segue abaixo:

// Quantas voltas o encoder deve dar para atingir a distancia necessaria
distRightMotor = 0.48*dist;
distLeftMotor = 0.48*dist;
 
while (getOut != 1) {
  // Verifica se os motores atingiram o num de voltas necessaria para a dist requisitada
  if((leftEncCount>=distLeftMotor)&&(rightEncCount>=distRightMotor)) {
    getOut = 1;
  }
 
  // Caso seja terminado
  if(getOut == 1) {
    leftMotor->run(RELEASE);
    rigthMotor->run(RELEASE);
    Serial.println("esq");
    Serial.println(leftEncCount);
    Serial.println("dir");
    Serial.println(rightEncCount);
    break;
  }
 
  // Gira as rodas 360 graus, ou seja, 25,13cm de translacao
  leftMotor->run(FORWARD);
  leftMotor->setSpeed(leftMotorSpeed);
  rigthMotor->run(FORWARD);
  rigthMotor->setSpeed(rightMotorSpeed);
 
  // Faz a leitura dos encoderes
  leftEncState = digitalRead(leftEncoder);
  rightEncState = digitalRead(rigthEncoder);
 
  // Verifica borda de descida do encoder esquerdo
  if(leftEncState == HIGH) {
    if(oldLeftEncState == LOW) {
      leftEncCount++;
    }
  }else { //Verifica borda de subida
    if(oldLeftEncState == HIGH) {
      leftEncCount++;
    }
  }
 
  // Verifica borda de descida do encoder direito
  if(rightEncState == HIGH) {
    if(oldRightEncState == LOW) {
      rightEncCount++;
    }
  }else { //Verifica borda de subida
    if(oldRightEncState == HIGH){
      rightEncCount++;
    }
  }
 
  oldRightEncState = rightEncState;
  oldLeftEncState = leftEncState;
}

Por fim, o controle da velocidade foi obtido de forma empírica. Através de vaŕios testes, foi atribuído um ganho Kp que era multiplicado pelo erro (diferença entre o setpoint e a saída). O ganho ke também foi obtido de forma empírica e multiplicado pela variação do erro (diferença entre o erro anterior e o erro atual). O proporcional e o derivativo são somados e atribuídos à saída.

4.4. Navegação (line-following):

O algoritmo de navegação implementado foi o de seguidor de linha simples, utilizando dois sensores óptico-reflexivos como fonte de sinal de detecção da linha. Para o controle da velocidade dos motores foi utilizado um controlador do tipo PD (Proporcional e Derivativo). O controlador do tipo PD obtém dos sensores break-beam a velocidade a qual o robô desloca-se e a partir desse valor, juntamente com os valores das constantes proporcional e derivativa, efetua o ajuste na alimentação dos motores através do valor da largura de pulso (PWM) aplicada a cada um deles. Desta forma, é possível o robô realizar trajetória em linha reta mesmo tendo motores com taxas de rotação de eixo diferentes – caso comum encontrado na prática. A correção da trajetória para seguir a linha traçada é dada pelos sensores ópticos, quando um dos sensores detecta o traçado, implica que é necessário o aumento da velocidade do motor contrário para a correção da trajetória (correção esta efetuada através do ajuste da alimentação do motor, via alimentação por modulação do tipo larguar de pulso (PWM)). Abaixo, segue trecho do código fonte que implementa o algoritmo de navegação:

//Navegação (line-following)
// ...
 
//Atribui ao Setpoint de cada sensor um valor médio
setPointR = (blackSurfaceR - whiteSurfaceR)/2 + whiteSurfaceR;
setPointL = (blackSurfaceL - whiteSurfaceL)/2 + whiteSurfaceL;
 
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Kp = ");
 
Kp = 1;
 
leftMotor->run(FORWARD);
leftMotor->setSpeed(60);
rigthMotor->run(FORWARD);
rigthMotor->setSpeed(72);
 
while(1){
  //Leitura dos sensores					
  rightValue = analogRead(rightSensor);
  leftValue = analogRead(leftSensor);
 
  //Erro = Setpoint - leitura
  correctionR = Kp * (setPointR - rightValue);
  correctionL = Kp * (setPointL - leftValue);
 
  //Move para frente
  if(rightValue < setPointR && leftValue < setPointL){
    leftMotor->run(FORWARD);
    leftMotor->setSpeed(60);
    rigthMotor->run(FORWARD);
    rigthMotor->setSpeed(72);
  }
  //Move para direita
  else if(rightValue > setPointR && leftValue < setPointL){
    leftMotor->run(FORWARD);
    if(60 + correctionR <= 255){
      leftMotor->setSpeed(60 + correctionR);
    }
    else{
      leftMotor->setSpeed(255);
    }
    rigthMotor->run(BACKWARD);
    rigthMotor->setSpeed(72);
  }
  //Move para esquerda
  else if(rightValue < setPointR && leftValue > setPointL){
    rigthMotor->run(FORWARD);
    if(72 + correctionL <= 255){
      rigthMotor->setSpeed(72 + correctionL);
    }
    else{
      rigthMotor->setSpeed(255);
    }
    leftMotor->run(BACKWARD);
    leftMotor->setSpeed(60);
  }
  //Move também para esquerda, caso ambos sobre a linha preta
  else if(rightValue > setPointR && leftValue > setPointL){
    rigthMotor->run(FORWARD);
    if(72 + correctionL <= 255){
      rigthMotor->setSpeed(72 + correctionL);
    }
    else{
      rigthMotor->setSpeed(255);
    }
    leftMotor->run(BACKWARD);
    leftMotor->setSpeed(60);
    }
  }

Resultados:

Apesar extensivos testes no laboratório, durante a competição, a iluminação do ambiente estava bem diferente da encontrada no laboratório, segundo um dos componentes do grupo isso pode ter contribuído

O robô Mandela teve seus conceitos colocados em prova durante a competição de robôs autônomos, tendo resultado final muito abaixo da expectativa inicial. A primeira etapa da competição: etapa eliminatória, o robô Mandela foi classificado em 5^o lugar, passando para a próxima etapa, a etapa classificatória, terminando a competição em 3^o lugar, empatado com mais dois grupos.

As deficiências observadas durante a competição foram: orientação inicial, navegação, detecção de blocos e por fim a ausência de uma segunda implementação estratégica. A orientação inicial não posicionava o robô precisamente no meio do campo para que, posteriormente, o mesmo pudesse seguir à linha central que levaria à rampa onde estava o bloco azul. Como a implementação do algoritmo seguidor de linha não corrigia a trajetória à tempo, o robô terminava por subir a rampa mal posicionado, não ficando com as duas rodas na rampa, mas sim com uma das rodas no campo e a outra roda na rampa ou em alguns casos a roda ficava “livre”; dispendendo todo o tempo da competição tentando reencontrar a linha que demarcava a trajetória pretendida até o bloco azul. Em outros casos, ao inicial a subida na rampa, o sensor LDR/LED de detecção e indicação fornecia a informação errônea de que ali havia um bloco. Então, o robô terminava por rotacionar 180^o e retornava para a base. Foi precisamente em um desses casos que o robô pontuou na primeira etapa da competição, por conseguir arrastar um dos blocos até à base de maneira aleatória.

Durante a competição dos outros grupos, tentou-se corrigir alguns trechos do código, mas sem sucesso. Durante à etapa classificatória, o robô permaneceu com o mesmo comportamento relatado anteriormente, terminando em terceiro lugar juntamente com dois grupos adversários. Justamente na segunda e última etapa da competição, caso houvesse uma segunda implementação, a mesma poderia ser posta em prática e talvez o resultado pudesse ter sido diferente (uma melhor classificação final poderia ter sido obtida).

Observamos que o grupo vencedor teve a mesma estratégia adotada pelo nosso grupo (orientar inicialmente no campo, posicioando o robô no centro de forma que o mesmo pudesse navegar sobre à linha que levava ao bloco azul sobre a rampa, capturar o bloco azul e retornar para a base e esperar o término do tempo da partida), porém, a implementação e a forma com a qual usaram os sensores, levaram a melhores resultados.

Percebemos então que houve ingenuidade ao não implementar uma segunda estratégia de jogo, bem como a de não testar previamente o robô no local da competição, submetido a diferentes intensidades de luz. O uso de um LED RGB no sensor de detecção e identificação de blocos poderia contribuir para o sucesso em alguns casos verificados de detecção falsa de blocos. A implementação de algoritmos melhores de odometria e navegação poderiam de certa forma ter evitado o comportamento de mal posicionamento do robô para a subida na rampa onde encontrava o bloco azul.

Conclusão:

O trabalho prático proporcionou melhor entendimento dos conceitos apresentados na disciplina de Introdução à Robótica, através da implementação de um robô móvel inicialmente capaz de cumprir uma missão de forma autônoma.

Apesar do resultado aquém do esperado na competição, a experiência proporcionada durante a execução dos trabalhos práticos

O ramo da robótica móvel é sem dúvida um dos mais interessantes que tivemos contato. Permeado de problemas multidisciplinares, o trabalho em grupo é essencial para atingir os objetivos propostos.

Referências:

cursos/introrobotica/2017-1/grupo05/competicao.txt · Última modificação: por 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki