Tp3-Robotica móvel navegação e controle:

OBJETIVOS

Este trabalho prático nos traz como novidade a ideia de navegação e localização de um robô de forma autônoma através de sensores LDR ligados a um micro controlador arduino. O robô deverá navegar por um campo se orientando por linhas pretas no chão, usando no máximo dois sensores LDR. Para a parte de localização, o robô deverá identificar por meio de uma lâmpada com lentes polarizadas em que lado do campo ele está e seguir em direção a luz mais próxima. Alem destas novidades também tivemos que aprimorar a parte de odometria feita no trabalho prático anterior, utilizando sensores break-beam como um tipo de shaft-encoders, de forma que teremos o controle da quantidade de rotações de cada uma das rodas do robô, podendo assim fazer o controle de velocidade de cada uma e distância percorrida.

ESTRUTURA

Com relação ao trabalho prático anterior, diminuímos a quantidade de reduções, de maneira que nosso robô não precise de um nível de energia tão alto para seu funcionamento. A redução foi alterada de 162:1 para 54:1, sendo o necessário para movimenta-lo com velocidade aceitável sem um consumo elevado de bateria.

Vídeo de teste da nova redução.

Imagem da estrutura de redução.

A imagem mostra a caixa de redução e o novo motor.

Utilizamos o próprio eixo de rotação das rodas para colocar uma engrenagem pequena de 14 dentes, de forma que possamos através de um sensor break-beam contar quantas vezes um feixe de luz foi interrompido por estes dentes e assim definir aproximadamente quantos graus cada roda girou. O sensor foi montado embaixo de nossa estrutura que foi elevada em um nível para não termos problema de travamento. Desenho esquemático chave óptica. Desenho esquemático Shaft-encolder. Imagem do sensor break-beam sendo utilizado como Shaft-encoder. Imagem da parte traseira do Robô, mostrando os sensores nas rodas.

Para a parte de navegação, os dois sensores foram colocados na parte da frente do robô, virados para baixo, embaixo da base principal da estrutura, de forma que tenham uma distância entre eles um pouco maior que a largura da linha preta a ser seguida.

Montagem dos sensores a serem acoplados ao Robô

LDR's na parte da frente para o motor seguir linha

LOCALIZAÇÃO

Para a parte de localização, foram colocados dois sensores do tipo LDR na parte de cima traseira do robô, de forma que estes sensores fiquem numa altura suficiente para receber diretamente a luz vinda das lâmpadas nas extremidades do campo. Para que a distância entre as lâmpadas fosse comparada, os sensores foram colocados um ao lado do outro, cada um com uma lente polarizada de uma forma (uma na vertical e outra na horizontal), lembrando que as lâmpadas nas extremidades do campo também tem na frente, lentes polarizadas da mesma forma (uma na vertical e outra na horizontal). Foram feitos testes e a iluminação exterior não interfere na leitura dos sensores.

Esquema do circuito do LDR diferencial

imagem do LDR acoplado ao robô

O arduino foi fixado na estrutura com o auxílio e de lacres, de forma que ficou bem firme e numa posição possibilitando o fácil acesso a suas entradas e saídas.

Arduino MEGA, acoplado ao robô

PROGRAMAÇÃO

Inicialmente, foi feito um menu de seleção com as opções relativas a odometria, navegação e localização. Para o comando odometria existem subdivisões no menu para a seleção da forma geométrica desejada (triangulo, quadrado e reta) e para cada forma geométrica podemos escolher as proporções relativas, indo de 10cm a 50cm com intervalos de 5cm.

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Robolfo V,3.0");
  lcd.setCursor(0, 1);
  lcd.print("func:Localizacao");
}


void loop() {
  int botao = analogRead (0);
  lcd.setCursor(6, 1);
  if (w == 0) {
    if (botao < 100) {
      lcd.print ("Start rigth     ");

    }
    else if (botao < 200) {
      x = x + 1;
      if (x > 3) {
        x = 1;
      }
      menu(x, 0); //botao up define qual funcao usar
    }
    else if (botao < 400) {
      x = x - 1;
      if (x < 1) {
        x = 3;
      }
      menu(x, 0); //botao down define qual funcao usar
    }
    else if (botao < 600) {
      lcd.print ("botao left");

    }
    else if (botao < 800) {
      lcd.print ("botao select      ");
      menu(x, 1);

    }
  }
  else if (w == 1) {
    if (botao < 100) {
      lcd.print ("Start rigth     ");
    }
    else if (botao < 200) {
      z = z + 1;
      if (z > 3) {
        z = 1;
      }
      menu2(z, 0); //botao up define qual funcao usar
    }
    else if (botao < 400) {
      z = z - 1;
      if (z < 1) {
        z = 3;
      }
      menu2(z, 0); //botao down define qual funcao usar
    }
    else if (botao < 600) {
      lcd.print ("botao left");
      menu2(4, 1);

    }
    else if (botao < 800) {
      lcd.print ("botao select      ");
      menu2(z, 1);
    }
  }
  else if (w == 2) {
    if (botao < 200) {
      tamanho = tamanho + 5;
      if (tamanho > 50) {
        tamanho = 10;
      }
      lcd.setCursor(5, 1);
      lcd.print(tamanho);
      lcd.print("           ");
      delay (500);
    }
    else if (botao < 400) {
      tamanho = tamanho - 5;
      if (tamanho < 10) {
        tamanho = 50;
      }
      lcd.setCursor(5, 1);
      lcd.print(tamanho);
      lcd.print("           ");
      delay (500);
    }
    else if (botao < 600) {
      lcd.print ("botao left");


    }
    else if (botao < 800) {
      lcd.setCursor(5, 1);
      lcd.print ("voltar      ");
      w = 1;
    }

  }

}

int menu2 (int x, int y) {
  lcd.setCursor(5, 1);

  switch (x) {
    case 1:
      lcd.print("Reta");
      lcd.print("           ");
      delay(500);
      if (y == 1) { //select acionado
        w = 2;
      }
      break;
    case 2:
      lcd.print("Quadrado");
      lcd.print("           ");
      delay(500);
      if (y == 1) { //select acionado
        w = 2;
      }
      break;
    case 3:
      lcd.print("Triangulo");
      lcd.print("           ");
      delay(500);
      if (y == 1) { //select acionado
        w = 2;
      }
      break;

    case 4:
      w = 0;
      break;
  }
}
int menu(int x, int y) {
  //switch q define as opcoes do menu
  lcd.setCursor(5, 1);
  switch (x) {
    case 1://caso 1 quadrado
      lcd.print ("Localizacao");
      lcd.print ("          ");
      delay(500);
      if (y == 1) { //select acionado

      }
      break;
    case 2: //para selecinar um triangulo
      lcd.print ("Odometria");
      lcd.print ("          ");
      delay(500);
      if (y == 1) {
        menu2(z, 0);
        w = 1;
      }

      break;
    case 3:  // para selecionar uma reta
      lcd.print ("Segue linha");
      lcd.print ("          ");
      delay(500);
      if (y == 1) { //select acionado

      }
  }
}

Para que a distância percorrida seja precisa, fizemos a proporção entre a quantidade de interrupções no feixe de luz do brake-beam e a distancia percorrida pela roda, neste caso, para cada 14 interrupções temos uma distância de 28cm percorridos, assim implementamos uma função de proporcionalidade.

Como exemplo de implementação da função de shaft-enconder

void loop(){
  // definição de varial para temporização
  // myDelay é o tempo que queremos comparar
  unsigned long endTime = millis() + myDelay;
  // faz a leitura do sensor e guarda como estado prévio
  byte previousState = digitalRead(opticalPin);
  int counter = 0; // inicializa contador
  // enquanto for menor que "endTime" executa
  while(endTime > millis()){
    // coloca estado do pino como estado corrente
    byte currentState = digitalRead(opticalPin);
    // se o estado conrrente não for igual ao estado prévio
    if(currentState != previousState){
      counter++; // acrescenta 1 ao contador
      // faz estado prévio igual ao estado corrente
      previousState = currentState;
    }// continua executando
  }
  // imprime contador no monitor serial
  // facilmente modificado se precisar imprimir em LCD
  // ou display 7 segmentos
  Serial.println(counter);
}

Código de implementação do sensor Shaft-encoder

Para a parte de navegação, foi implementado um algoritmo que utiliza informações de um sensor LDR para se localizar. Os sensores são colocados sobre a linha preta para que sejam calibrados, o número obtido é uma espécie de referência, em nosso algoritmo, um valor equivalente a 130% deste valor já é tomado como a cor preta. Quando o sensor direito ou esquerdo encontra a cor preta, apenas o respectivo motor é paralisado, de forma que automatica-mente o robô acerta sua posição, isso é feito para ambos os lados, de forma que o robô se move oscilando para direita e esquerda. Uma situação especial é quando ambos sensores encontram a cor preta, quando isso ocorre é chamada uma função randômica que decide se o robô irá virar para esquerda ou direita.

void calibra_line_follow(){
  //Calibra os LDRs de Line Follow

    //LDR L
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Calibrando");
  lcd.setCursor(0,1);
  lcd.print("LDR L");
  delay(2000);
  calib_line_follow[0] = mediaLeituras(num_medias, LDR_L);
  calib_line_follow[0] *= (1.0 + (tolerancia_ldr/100.0));
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Calib LDR L:");
  lcd.setCursor(0,1);
  lcd.print(calib_line_follow[0]);
  delay(5000);

  //LDR L
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Calibrando");
  lcd.setCursor(0,1);
  lcd.print("LDR R");
  delay(2000);
  calib_line_follow[1] = mediaLeituras(num_medias, LDR_R);
  calib_line_follow[1] *= (1.0 + (tolerancia_ldr/100.0));
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Calib LDR R:");
  lcd.setCursor(0,1);
  lcd.print(calib_line_follow[1]);
  delay(5000);
}

Código para calibração do Line-Follow

Vídeo do line-follow

Para a parte de localização, a lógica implementada consiste em uma espécie de mapeamento do local em que ele está presente, a princípio é executado um giro de 360 graus, obtendo informações em cada um dos sensores localizados na parte de trás do robô. O maior e menor valor de luminosidade são armazenados juntamente com o ângulo em que este nível de luz foi recebido. Após o fim do giro, o robô deverá girar o ângulo correspondente ao maior nível de luminosidade. do para a localização

MODIFICAÇÕES E PROBLEMAS DURANTE A MONTAGEM

Uma dúvida que existia era sobre a posição em que o break-beam seria colocado, inicialmente foi criado um eixo extra movido por uma correia que era ligada no eixo da roda. Este eixo era utilizado para girar a pequena engrenagem e fazer a contagem de quantas vezes o feixe de luz do break-beam era cortado. Este método gerou problemas pois existia uma perda de energia pela transmissão entre os eixos, além da utilização da corrente que dobrava a haste utilizada como eixo para a roda. A fixação do motor também gerou problemas, devidos ao desgaste da fixação feita com cola quente. A fixação foi refeita e funcionou perfeitamente.

1º Dia (25/05)

No trabalho anterior nossos motores não acionaram as rodas de maneira satisfatória, portanto resolvemos diminuir a redução e trocarmos os m}}otores.

Trocamos os motores antigos que não ofereciam uma potencia satisfatória por novos que seriam mais confiáveis;

2º Dia (27/05)

-montamos os circuitos elétricos que integram o novas funções, que são dois sensores LDR's que seriam usados para navegação nas linhas e um sensor para o robô conseguir se orientar em direção a luz;

-terminamos a montagem da estrutura básica do robô.

-

3º Dia (05/06)

-Começamos o dia com a montagem do break beam na parte superior do robô; -vimos que com o uso da corrente a montagem tinha seus defeitos com a corrente pegando na roda causando atrito resolvemos então alterar a construção; -Nos então remontamos ligando o break beam ligado direto na roda testando apenas com um pneu;

4º Dia (06/06)

-Nos começamos alterando o break beam para a parte interna da armação dos eixos da roda; -Na parte da programação terminamos o controlador PD e a navegação na linha;