Ferramentas do usuário

Ferramentas do site


cursos:introrobotica:2016-1:grupo06:quarto_trabalho_pratico


Quarto Trabalho Prático

Execução das tarefas

  1. Reconhecimento de Cores
  2. Realização de Percursos
  3. Alinhamento com a Luz Polarizada

Figura - Estrutura Final

Eletrônica

LDR Diferencial

Sabe-se que um sensor LDR é um resistor variável que muda sua resistência de acordo com a luminosidade a qual está exposto. A medida que a luminosidade aumenta a resistência também aumenta. Sendo assim, dependendo do circuito projetado pode-se observar uma elevação de tensão a medida que a luminosidade aumenta (caso um resistor de pull-down seja utilizado), ou a tensão medida na porta analógica do microcontrolador pode diminuir com o aumento da luminosidade (caso seja usado um resistor de pull-up).

Figura - Resistor Pull-up e Pull-down

É importante notar que os valores de saída destes dois sensores estão relacionados com a resolução do conversor analógico digital do microcontrolador utilizado, sendo que o sinal de um sensor é o complementar do sinal do outro. Isso significa que se o conversor analógico digital do microcontrolador utilizado é de 10 bits (range de 0 - 1023), então se o sensor ligado da segunda maneira tiver como saída um valor X então o mesmo sensor ligado da primeira maneira descrita, terá como saída 1023 - X.

Já um LDR diferencial nada mais é do que sensores LDR ligados em série, com um ponto de medição inserido entre estes sensores. Seu princípio de funcionamento é mesmo de um divisor de tensão. Dependendo da resistência equivalente do circuito, passará uma corrente que é proporcional a relação da tensão de alimentação pela resistência equivalente. Sendo assim, a queda de tensão no primeiro resistor (primeiro sensor LDR) será basicamente a corrente calculada vezes a resistência do LDR.

Montando o circuito de LDR diferencial obtém-se a saída já proporcional a diferença de resitência entre os dois sensores. Porém, pode-se obter um resultado semelhante com o circuito dos LDR montado separadamente e com um processamento interno ao microcontrolador. Com esta montagem apesar de serem usadas mais portas analógicas, pode-se observar separadamente o efeito de cada sensor, e uma maior mobilidade ao circuito é obtida, podendo posicionar os sensores em lugares arbitrários.

Figura - Variação da resistência de acordo com a luminosidade

Figura - Sensor LDR com filtro polarizador

Filtro Polarizador

Os filtros polarizadores são filtros que funcionam como fendas em uma direção, isso é, só deixam passar a parte da onda que oscila num determinado plano. Como mostra a figura abaixo:

Figura - Filtro polarizador na luz

Entretanto, a luminária utilizada no projeto ao redor do campo já possui uma luz polarizada. Dessa forma, só passa luz pelo filtro caso as ondas proveniente da luz estejam alinhadas a um ângulo de 0, 180 ou 360 graus. Caso essa diferença de fase seja de 90 ou 270 graus a passagem de luz é nula.

Figura - Filtro com luz polarizada

Assim, este foi colocado na frente do LDR de forma a controlar a intensidade de luz que este recebia. E ajudar na localização, uma vez que era possível se alinhar com as ondas de luz.d

Sensores Break-Beam e Shaft Encoding

Com o intuito de medir a velocidade de rotação de uma roda, foi construído o circuito de sensores do tipo break-beam. Estes consistem no conjunto de LED emissor de infravermelho e um receptor (fototransistor) posicionados um em frente ao outro de modo que o feixe de luz IR seja interrompido caso algum objeto passe na frente do feixe, impedindo a detecção.

Os sensores foram posicionados em frente às engrenagens que moviam cada roda. Foi observado que o espaçamento das engrenagens era diferente e por isso optou-se por tampar alguns dos furos de modo que apenas furos igualmente espaçados continuassem expostos. Sendo assim os LEDs foram ligados permanentemente à alimentação e os fototransistors conectados às portas digitais do Arduino. Quando havia detecção do feixe de luz (o feixe passava pelo furo da engrenagem) a entrada do microcontrolador era 1 (verdadeiro), caso contrário a entrada era 0. Com isso, pudemos fazer a contagem de furos em determinado intervalo de tempo e inferir a velocidade que o robô se movia.

Figura - Break-Beam

Reconhecimento de Cores

Uma das tarefas propostas neste trabalho prático foi seguir em linha reta até que um bloco fosse detectado em frente ao robô. De acordo com a cor desse bloco diferentes decisões seriam tomadas. Sendo assim foi fez-se necessária a criação de um código confiável para detecção de cores. Em hardware não houveram muitas modificações no circuito detector de cores. O circuito continuou consistindo em um LDR, resistor pull-up de 10KOhm, um LED rgb, e o resistor apropriado para o LED (neste TP usamos um resistor de 180 Ohm). Já no software, a estratégia de detecção mudou.

  • Calibração do Branco

Posiciona-se uma superfície branca em frente ao LDR e LED RGB, faz-se 5 leituras de tensão proporcional às cores incididas (vermelho, verde, azul) e a média desses valores é salva em um vetor.

  • Calibração do Preto

Faz-se o mesmo, porém agora com uma superfície preta. A média dos valores lidos é salva em outro vetor, e assim a calibração está concluída.

  • Checa os valores do LDR

A checagem de cor é feita constantemente e consiste em realizar 5 leituras do sensor e fazer a média delas. O valor da cor após a calibragem será então a diferença da média calculada para os valores salvos como sendo branco e preto. Faz-se isso para cada uma das três cores.

  • Checa cor

Feita a relação dos valores de tensão proporcionais a leitura do LDR, relacionou-se esses valores a uma cor. Nesse passo foi utilizada a distância entre pontos para calcular para qual cor salva a leitura realizada era mais próxima. Estes valores para a cor foram inseridos tomando como base a quantidade de R,G e B presente em cada cor e ajustados empiricamente. Sendo assim, a menor distância medida era a cor do bloco que estava posicionado na frente do LDR e imprimiu-se no display LCD o nome dessa cor.

Buzzer

O buzzer é do que um componente eletrônico que faz o papel de um pequeno alto-falante capaz de emitir som. Esse é normalmente usado em projetos que necessitam de avisos sonoros. Neste caso, foi utilizado para avisar quando o robô detectasse um bloco verde em sua frente.

Figura - Ligação no Arduíno

Mecânica

A montagem anterior do carro, principalmente pelas dimensões, altura e caixa de marchas fez com que os ajustes para essa atividade fossem mínimos. As principais mudanças foram a instalação de um assoalho, uma forma provisória de fixação dos motores e sensores e uma maior preocupação do ponto de vista estético e limpeza do robô.

A mudança no assoalho se deu a necessidade de uma boa fixação e maior segurança dos componentes eletrônicos para essa etapa. Além de estar mais pesados, eles também aumentaram em número e volume e começaram a exigir um espaço para serem instalados que permitia uma certa flexibilidade. A mudança foi parcialmente satisfatória, uma vez que as engrenagens ainda se encontravam muito próximas dos componentes e isso cria um certo risco de acidentes com os fios.

Uma boa fixação dos motores e engrenagens é uma exigência inerente as estratégias de controle. A informação do sensor define o posicionamento do robô que ganha com isso muito mais autonomia, no entanto, pára de funcionar corretamente se receber o sinal errado dos sensores. Portanto, essa é uma preocupação que é de extrema importância e ainda precisa ter mais atenção. Os sensores foram fixados em peças de LEGO com cola quente e então grudados no assoalho pelo próprio encaixe das peças. Isso flexibilizou a escolha do posicionamento dos sensores e garantiu uma repetibilidade em suas medições. No entanto, os sensores que estavam próximos ao motor eram eventualmente deslocados da sua posição e geravam erros no funcionamento do robô. Essa fixação ainda precisa ser mais robusta e confiável.

Uma terceira preocupação para essa etapa foram os fios. A quantidade de sensores se tornou muito superior as das tarefas anteriores e quantidade e tamanho dos fios também aumentou. Portanto, foi montada uma estrutura no centro do carro para encobrir esses fios e fixar melhor os motores. A estrutura não encobria as placa ou o arduino e, consequentemente, o encaixe dos fios também estava exposto. O encaixe por sí só já mostrava e expunha muito os fios e é algo que pode ser melhorado.

Sugestões para a próxima etapa:

  • Fixar melhor os motores e sensores: imobilizá-los seria uma ação quase desejável. Qualquer movimento de um deles pode colocar em risco toda a movimentação do robô a partir dessa etapa.
  • Aumentar a estrutura de lego para esconder tanto as placas quanto os fios que são ligados nela. A próxima etapa permite que possíveis colisões entre os carros aconteçam e isso não deve afetar a integridade do robô. O que significa que não deve quebrar ou desconectar nenhum fio.

Programação

Estrutura do código Nesta etapa, reestruturamos as bibliotecas internas do código para utilizar os conceitos de orientação objeto. Sendo assim cada biblioteca criada foi abstraída em uma classe, aumentando a legibilidade e manutenibilidade do código. Nesta etapas nos implementamos quatro bibliotecas:

  • ColorDetect ⇒ Responsável por calibrar e detectar cores
  • Menu ⇒ Responsável por gerenciar as opções do menu e navegação
  • MotorController ⇒ Responsável por controlar o motor
  • ShaftEncoder ⇒ Responsável por medir a velocidade da roda.

A biblioteca de menu continua com o funcionamento similar ao do TP anterior e portanto não será detalhada nesta documentação.

Shaft Encoder A biblioteca de ShaftEncoder possui rotinas para medir o giro e velocidade do motor associado. Possui basicamente dois tipos de métodos: O read() que é executado no loop do Arduino, que realiza a leitura do break-beam e atualiza o contador e timer interno, e o getSpeed() que calcula a velocidade angular do motor com base nos valores internos.

Quando o método read() detecta uma borda de subida no sensor break-beam isso indica que um quarto da engrenagem (a engrenagem possui 4 orificios que ativam o break-beam) foi girada. Quando isso acontece, nos salvamos o tempo que o motor levou para girar esse ¼ de roda e adicionamos 1 ao contador de giro. Quando o método getSpeed() é chamado, ele calcula a velocidade angular do motor com base no ultimo tempo salvo. Como a velocidade é atualizada apenas quando o engrenagem completa ¼ de giro, se a engrenagem parar de girar a velocidade permanecerá a mesma, causando problemas no módulo de controle. Desta forma nós adicionamos um limite de tempo, de modo que se o break-beam não for acionado dentro de 800ms, assumimos que ele está parado e retornamos a velocidade 0.

Motor Controller A biblioteca de Motor Controller é responsavel por controlar o motor de modo que ele se mantenha a uma velocidade objetivo desejada. Para isso ele utiliza o módulo de Shaft Encoder para medir a velocidade de giro e uma biblioteca externa de controle PID. Nós inicialmente haviamos implementado nossa propria biblioteca de PID, porém optamos por usar uma implementação externa pois ela era mais robusta e confiável (disponível em: https://github.com/br3ttb/Arduino-PID-Library/).

Os dois principais métodos do módulo são o setGoal() e o control(). O setGoal() é utilizado para definir a velocidade objetivo do robô. O control() é executado dentro do loop principal e é responsável por atualizar a tensão aplicada ao motor com base no controlador PID. O algorítimo da função control() funciona da seguinte forma:

  1. Lê a velocidade do motor usando o Shaft Encoder.
  2. Calcula a variação da tensão no motor com base na velocidade atual e a desejada, usando o controlador PID.
  3. Aplica a nova tensão no motor.

Como o Shaft Encoder precisa esperar o giro de ¼ da engrenagem para atualizar sua leitura de velocidade, o metodo control() apenas atualiza a tensão aplicada no motor a cada 150ms. Desta forma, a tensão não é atualizada com base em uma leitura antiga de velocidade. Outra medida necessária para controlar corretamente o motor foi assumir que a leitura de velocidade do motor é de mesmo sinal que a tensão aplicada no motor, já que nosso Shaft Encoder não é capaz de detectar mudança na direção de giro.

Um caso especial da função control() é quando a velocidade objetivo é de 0. Como o não é necessário controlar nesse caso, quando a velocidade objetivo é 0, a tensão aplicada śerá 0 automaticamente.

Color Detect O modo de deteção de cores foi alterado do ultimo trabalho prático para realizar um detecção mais confiavel.

Adicionamos uma função de calibração. Ela funciona lendo uma amostra de branco e outra de preto de modo a ajustar as leituras subsequentes, onde o branco seria a maior leitura do LDR e preto a menor. Desta forma a influencia da luz ambiente é minimizada.

Outra mudança é no algoritmo de interpretação dos valores lidos. Para detectar a cor, nós interpretamos o três valores lidos como um ponto em um espaço de cores 3D, onde os eixos sistema de coordenadas deste espaço é dado pelos valores de vermelho, verde e azul. Nos utilizamos então pontos determinados empiricamente como os pontos ideias de cores no espaço para as cores a serem detectadas (Vermelho, Azul, Verde e Amarelo). Assim calculamos a distancia ente o ponto de cada cor ideal no espaço e a cor lida, e assumimos que a menor distancia é a da cor lida.

Tarefas Como nos outros trabalhos, utilizamos a função runTask() para programar a logica de cada tarefa a ser executada pelo robô. Para auxiliar a programação das tarefas, foram criadas duas funções auxiliares que calculam o tempo necessário para realizar um movimento dado uma velocidade de giro: distanceToDelay() e angleToDelay().

Medimos que para um uma velocidade angular de uma rotação por segundo da engrenagem o robô se movia aproximadamente a 2.75 cm/s. Usamos essa mediada para calcular então o tempo necessário para o robô uma distancia desejada a uma determinada velocidade.

Para o cálculo do tempo para girar um angulo, a distancia entre as rodas do robô e utilizamos esse valor como o diâmetro do circulo descrito. Usando o diâmetro medido podemos calcular o perímetro do circulo, de modo que para um giro de 360 graus seria necessário percorrer uma distancia igual ao perímetro do circulo, logo, dado um angulo qualquer, calculamos a distancia proporcional a ser percorrida para girar o robô. Com a distancia a ser percorrida podemos usar a função distanceToDelay() para determinar o tempo de giro.

Com essas duas funções, programar os caminhos e a tarefa de tomada de decisão trivial.

Alinhamento Para o alinhar o carrinho em direção a luz polarizada utilizamos a seguinte estratégia:

  • Giramos 360 graus a uma velocidade constante.
  • A cada 10 graus, lemos o valor medido por ambos os LDR’s com lente polarizadas e armazenamos em um vetor
  • Ao fim do giro, achamos a menor soma de valores lidos pelos dois LDRs (valores menores indicam maior luminosidade) e em qual angulo essa medida foi encontrada.
  • Giramos então o robô de modo a orienta-lo ao angulo determinado anteriormente
  • Fazemos um pequeno ajuste no angulo final para alinharmos melhor com a luz polarizada.

Vídeos

Vídeo: Reconhecimento de Cores

Vídeo: Realização de Percursos

Vídeo:Alinhamento com a Luz Polarizada

cursos/introrobotica/2016-1/grupo06/quarto_trabalho_pratico.txt · Última modificação: por 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki