Ferramentas do usuário

Ferramentas do site


cursos:introrobotica:2019-1:grupo06:tp3

Trabalho Prático 3

Introdução

O trabalho prático consistia na elaboração de um robô que deveria realizar três tarefas :

  1. Por meio de um sensor LDR diferencial e lentes polarizadas, o robô deverá se alinhar com a fonte de luz mais próxima;
  2. Utilizando sensores break-beam, deve-se criar encoders para medir a rotação de cada roda. A partir disso, a velocidade do robô deve ser controlada para percorrer caminhos pré-determinados (Reta, Triângulo, Quadrado);
  3. O robô deve ser capaz de seguir linhas pretas no chão. Para isso, será utilizado sensores de infravermelho reflexivos;
  4. A escolha de tarefas deve ser feita a partir de um menu, utilizando os botões e o LCD do kit Arduino.

Estrutura física

Para a locomoção, foi utilizada essência a mesma estrutura física do trabalho anterior (TP2). A grande vantagem dessa base é a sua compacticidade e o fato de as duas rodas estarem no meio do corpo do robô, fato que permite uma facilidade maior para realizar curvas e girar em torno de seu eixo.

Sensores

Foram construídos 5 sensores para este trabalho, sendo 2 encoders, 2 infravermelho e 1 LDR diferencial.

Encoders

Os encoders são sensores utilizados para medir a rotação de uma roda. Montamos 2 e utilizamos 1 para cada roda do robô.
Utilizamos chaves ópticas break-beam em conjunto com resistores para construir o circuito abaixo:

Assim, em conjunto com uma rodinha com furos das peças do lego, o sensor é capaz de medir rotação. A construção final ficou como abaixo:

LDR Diferencial

O LDR diferencial é o sensor utilizado para a localização do robô. Ele consiste em um circuito divisor de tensão composto por 2 LDRs, em que o sinal é lido no ponto entre eles.
Na mesa que o robô precisa se localizar, existem 2 lâmpadas nas extremidades com filtros de luz direcionais em que, uma delas deixa a luz passar na direção vertical e a outra deixa a luz passar na direção horizontal. Assim, utilizando esses filtros em cada um dos LDRs (vertical em um e horizontal no outro), o sensor irá medir uma intensidade máxima quando apontado para uma das lâmpadas e mínima quando apontado para a outra. O circuito e a montagem estão abaixo:

Sensores Infravermelho

Esses sensores são utilizados para detectar objetos, mas funcionam muito bem para distinguir cores preto e branco. Assim, foram utilizados para detectar a linha preta sobre a mesa branca. Eles são compostos por um LED emissor de luz infravermelho e um transistor receptor dessa luz. O LED emite a luz que reflete no objeto à sua frente, fazendo com que o o transistor receba esse feixe.

Algoritmo

Controle

Para a realização do controle, utilizou-se como base um PID clássico. A função de controle recebe como base o erro entre a velocidade desejada (setpoint) e a velocidade atual, e retorna um valor de tensão PWM para o motor. É importante ressaltar que cada motor(esquerdo e direito) possui uma malha de controle independente.

 
double Controlador::LeiDeControle(double erro){
 
  unsigned long now=millis();
 
 
  double dt = (now - this->TempoAnterior);
 
  this->SomatorioErro += erro * dt; 
  double dErr = (erro - this->ErroAnterior);
 
  double output = this->Kp*erro + this->Ki*SomatorioErro + this->Kd*dErr;
 
  this->TempoAnterior=now;
  this->ErroAnterior=erro;
 
  return(output);
}
Localização

A localização feita com o sensor diferencial implica em valores de máximo em mínimo conforme o alinhamento do sensor com a lâmpada de luz polarizada mais próxima. Como não havia necessidade de alinhar com uma lâmpada em especifico e sim com a mais próxima, pode-se transformar o minimo em um maximo subtraindo um limiar do valor medido. Os dados obtidos ao girar o sensor foram obtidos quando este estava próximo das lâmpadas.

Como pode-se observar, existe muito ruído, implicando na necessidade de implementar um filtro smoothing.

O código resultando é o seguinte:

bool Localizacao::EstaAlinhado()
{
    int sinalAnterior = 0;
    if (this->readIndex == 0)
    {
        sinalAnterior = readings[19];
    } 
    else
    {
        sinalAnterior = readings[this->readIndex -1];
    }
    this->RetornaSinal();
    int val = readings[this->readIndex]; // Buffer utilizado pelo smoothing
    if( val < sinalAnterior)
    {
        return true;
    }
    else
    {
        return false;
    }
}
Odometria

Para realizar a medição de velocidade do robô, utilizados chaves ópticas como encoders e interrupção para realizar a contagem de voltas. Isso foi feito com uma classe:

class Encoder
{
 
	int const Pino;
	unsigned long int Voltas = 0;
	unsigned long int VoltasDuranteUltimoConsumo = 0;
	unsigned long int TempoDesdeUltimoConsumo;
	public:
 
	Encoder(const int pino);
 
	void IncrementaVoltas() { Voltas++; };
 
	void operator++() { Voltas++; } 
 
	float RetornaRPM();
 
	void  ZeraVoltas()  { Voltas = 0; } 
 
	static float CalculoRPMdeVoltas(int);
 
	int RetornaVolta(){return Voltas;}
 
	float CalculoVoltas(int v);
};
 
float Encoder::RetornaRPM()
{
	unsigned long int tempoAtual = millis();
	unsigned long int deltaTempo  = float(tempoAtual - this->TempoDesdeUltimoConsumo); 
	float  deltaRotacoes = this->CalculoVoltas(this->Voltas - this->VoltasDuranteUltimoConsumo);
	this->VoltasDuranteUltimoConsumo = this->Voltas;
	this->TempoDesdeUltimoConsumo = tempoAtual;
	return deltaRotacoes*60000.0/88.0/float(deltaTempo); // 60000   88 // 1916.92
}

A implementação da interrupção não pode ser feita utilizando uma função membro de uma classe porque ela usa um argumento, mesmo que nenhum seja declarado, o ponteiro this que aponta para o objeto instanciado do qual o método é chamado. A solução para contornar esse problema é implementar uma função void que chama a função desse membro e realizar a associação da interrupção com o pino no arquivo .ino

void leftMotorInterruptHandler()
{
  encoderMotorEsquerda.IncrementaVoltas();
}
 
void setup(){
  attachInterrupt(digitalPinToInterrupt(LEFT_ENCODER_PIN), leftMotorInterruptHandler , RISING );
  .
  .
  .
}
Seguir Linha
void SeguidorDeLinha::Seguir (int esquerda, int direita){
 
	if(esquerda < LIMIAR_LINHA && direita < LIMIAR_LINHA){
 
                  //SE OS DOIS ESTIVEREM DENTRO DA LINHA, O ROBO ANDARÁ PARA FRENTE
	}else if(esquerda < LIMIAR_LINHA && direita > LIMIAR_LINHA){ 
                  // SE O LADO ESQUERDO ESTIVER FORA, O ROBO FARÁ UMA CURVA PARA DIREITA
 
	}else if (esquerda > LIMIAR_LINHA && direita < LIMIAR_LINHA){ 
                       //ANALOGO AO ANTERIOR, 
 
	}else { 
                //SE OS 2 LADOS ESTIVEREM FORA DA LINHA O ROBO GIRA NO PRÓPRIO EIXO PROCURANDO UMA LINHA
 
	}
 
 
}

Desafios

Os prncipais desafios do tp foram a integração dos algoritmos e a realização do controle.


O controle PID deve ser tunado de forma paramétrica, o que pe inviável de se fazer por tentativa e erro sem o surporte de um sistema automatizado de testes. O controle proporcional usando árvore de decisões (um amontoado de if else) também foi dificil de desenvolver apesar de ter funcionado durante uma etapa do desenvolvimento. O contole por chaveamente com histerese funcionou bem mas num momento muito tardio para que desse tempo de integrar com o restante do código.


A integração foi difícil de realizar em função do alto nível de acoplamento das funções e classes desenvolvidas.


Outro desafio a ser infrentado é a calibração do sensor de localização. Os problemas sencontrados foram

  1. Sensores tem sensibilidades diferentes à luz
  2. Pequenas alterações de ângulo implicavam em grande perda do alinhamento com a luz polarizada
  3. O sensor encontrava o máximo em um ângulo diferente do desejado, de forma persistente

Registro AudioVisual

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

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki