GRUPO 3 - Breakway Builders - TP 1

Membros da Equipe

  • Douglas Martins
  • Elerson Rubens
  • Rodrigo Maffra
  • Roger Melo

Introdução

O objetivo deste trabalho é a familiarização dos alunos com a montagem lego e os principais meios de controle cinemático de um robô móvel. Para isso o grupo tem como tarefa a construção de um robô que execute ações específicas conforme descrito na tarefa.

Tarefas a serem realizadas

  1. Montar o HandyBug similar ao 9645 ([Martin] pg. 30-51)
  2. Controle PD - Utilizar os sensores break-beam para construir shaft-encoders. Fazer a montagem mostrada na Figura 5.9. Seção 5.2.3, exercícios 1 e 4.
  3. Montar uma caneta , marcador, etc. de tal forma que possa marcar a trajetória descrita pelo robô.
  4. Medir o erro de translação - Atuar os motores por um tempo constante e medir a distância percorrida para V = 20, 60 e 100.
  5. Medir o erro de rotação - Atuar os motores de forma que o robô gire 90 graus e medir o erro obtido para V = 20, 60 e 100.
  6. Tarefas a serem apresentadas:
  • Fazer o robô realizar uma trajetória quadrada de 30 cm x 30 cm por 3 vezes consecutivas.
  • Fazer o robô realizar uma trajetória circular de raio 30 cm por 3 vezes consecutivas.

Montagem do Robô

Foram realizadas diversas montagens até chegar ao modelo final apresentado na figura abaixo.

  • Versão 1: foi feita antes da disponibilização do TP1, sem se basear na montagem 9645([Martin] pg. 30-51). O robô apresentou diversos problemas que impossibilitaram o prosseguimento com aquele modelo.
  • Versão 2: A partir da disponibilização do TP1, o grupo começou a seguir o modelo proposto pelo trabalho. Tiveram que ser realizadas algumas modificações no projeto 9645, pois o projeto não comportava bem a montagem do motor que não pertencia ao lego. Além disso foram realizadas um aumento ao invés de uma redução na montagem das coroas, a fim de dar mais velocidade ao carro. O carro comportou-se bem, mas a inclusão dos shaft-encoders nos obrigou a realizar algumas modificações no projeto.

  • Versão 3: Com a disponibilização dos shaft-encoders, houve a necessidade de realizar uma modificação na montagem, a fim de obter um controle mais preciso, e para isso foram realizadas duas modificações principais: A primeira modificação consistiu na redução da velocidade do robô, com a troca das coroas, que possibilitaram correções mais amenas; A segunda modificação ocorreu no posicionamento dos shaft-encoders para leitura de velocidade, antes realizada diretamente no eixo da roda e depois sobre o eixo principal no qual o motor atuava, aumentando assim o número de rotações por minuto e conseqüentemente, tornando mais fina a calibragem passada para a programação do robô.
  • Versâo 4: Por fim, houve a necessidade de inserir a caneta entre os eixos dos motores de forma que a mesma fique no centro de rotação do robô. Esse trabalho ja estava previsto, mas devido a falta de encaixe entre caneta e lego, tivemos que realizar algumas adaptações no carro com a finalidade de inserir e prender a caneta no carro.

Programação do Robô

A partir da versão 2 da montagem do robô iniciamos a sua programação. Como o trabalho prático requeria a realização de duas formas geométricas ( circulo e quadrado) fizemos dois programas diferente que no final foram condensados em um unico programa com uma interface amigável para realizar a escolha do programa a ser rodado.

Código:

#use "quad2.ic"
#use "circ2.ic"
//#use "cmucamlib.ic"
 
void main()
{ 
    char a[3][16]={"Menu: Quad","Menu: Circ","Menu: Sair"};
 
    printf("Press START\n");
    while(!start_button());
    printf("rode o knob para selecionar programa\n");
    sleep(1.0);
    while(1) {
        int sel;
        printf("rode o knob para selecionar programa\n");
        sleep(1.0);
 
        sel = select_string(a,3);
        if(sel==0) quad();
        else if(sel==1) circ(); 
        else if(sel >=2 ) break;
    }
    printf("Terminou\n");
}

Controle de PD

O controle desenvolvido para o trabalho tenta manter cada uma das rodas a uma velocidade predeterminada.

Progroma do Círculo

O programa do circulo tem um objetivo simples: manter uma determinada velocidade em uma roda e manter uma velocidade 64% (exatamente 9/14) menor na roda interna a fim de fazer o robô realizar uma trajetoria circular. A programação apresentou um ótimo resultado. Após isso, tivemos apenas que calcular a distância que o robô deveria percorrer para realizar três voltas.

Código:

/* circle handyBoard program created by group 3 - robotics introduction - dcc - ufmg*/
#include sencdr5.icb
#include sencdr6.icb
 
#define CSLEEP 50L
//valor inicial de power
#define CPOWER0 68
#define CPOWER1 38
//velocidade dos motores para curva de 90 graus
#define CVELPD0 14
#define CVELPD1 9
// proporcao para curvaa de 90 graus
#define CPROP 0.64285
//constantes PD
#define Ckd  1.0
#define Ckp 0.2
//costantes de erro
#define Cerr 1.0
 
 
//tamanho do circulo
#define QFIM 13959   // 4653*3
 
void circ() {
 
    int velocidade0,velocidade1;
    int count0,count1;
    int power0,power1;
    float dif;
 
    encoder5_counts=0;
    encoder6_counts=0;
 
    while(!start_button());
 
    while (1)  {
 
        //calcula a velocidade  
        velocidade0 =  encoder6_velocity;
        velocidade1 =  encoder5_velocity;
 
        //calcula o power do motor0
        if(velocidade0 != CVELPD0)
        {    power0 -= (int) Ckd*(velocidade0 - CVELPD0) ;            
        }
 
        //calcula o power do motor1
        if(velocidade1 != CVELPD1) 
        {    power1 -= (int) Ckd*(velocidade1 - CVELPD1);          
        }
 
 
        //calcula a proporcao entre os counts ate o momento
        if(encoder5_counts != 0) {
            dif = ((float) encoder6_counts)/((float)encoder5_counts);
        }else
        {
            dif = CPROP;
        }
 
        //altera power pela porporcao do erro
        if(dif - CPROP > Cerr)
        {  power0 -= (int)(Ckp*(dif - CPROP));
        }
        else if(dif - CPROP < -Cerr)
        {  power1 -= -(int)(Ckp*(dif - CPROP)) ;
        }
 
        printf("pw0 %d vel %d",power0,encoder6_velocity);
        printf("pw1 %d vel %d %d\n",power1,encoder5_velocity,(int)(dif));
 
        motor(0,power0);
        motor(1,power1);
        //mantem countX atualizado
        count0 = encoder6_counts;
        count1 = encoder5_counts;
        msleep(CSLEEP);
 
        if(count0  >= QFIM) break;
        if(stop_button()) break;
 
    }
 
    printf("c0 %d c1 %d",count0,count1);
    off(0);
    off(1);
 
}

Programa do Quadrado

Houve maior dificuldade no desenvolvimento do programa que faz um quadrado, uma vez que há a necessidade de o robô mudar sua direção de 90º. A programação foi desenvolvida, porém pequenos erros na mudança de direção fizeram com que a trajetória do quadrado não fechasse conforme planejado. Apesar disso, a execução da trajetória assemelha-se muito a um quadrado.

Código:

/*square handyBoard program created by group 3 - robotics introduction - dcc - ufmg*/
#include sencdr5.icb
#include sencdr6.icb
 
#define QSLEEP 20L
//valor inicial de power para 90 graus
#define QNOVPOWER0 6.0
#define QNOVPOWER1 -6.0
//valor inicail de power para reta
#define QPOWERRETA0 6.0
#define QPOWERRETA1 6.0
 
//vlocidade curva 90 graus
#define QVELPD0 8
#define QVELPD1 -8
 
//vlocidade reta
#define QVELRETA0 8
#define QVELRETA1 8
 
//constantes PD
#define Qkd  0.3 //0.3
#define Qkp 0.04  // 0.07
 
//erro a ser considerado
#define Qerrcd 0.0 //0
#define QPROP 0.0
 
//constantes para inecia
#define QcountsAcel 100.0
#define QcountsDacel 30
 
//tamanho quadrado
#define QLADO 1284
 
// tamnho para curva 90 graus
#define QARETO 375 //375
 
//funcao que desenha quadrado
void quad() {
    int velocidade0,velocidade1;
    int count0,count1,countAux0,countAux1,i;
    int sair = 0;
 
    float power0,power1;
    float dif;
 
    encoder5_counts=0;
    encoder6_counts=0;
 
    while(!start_button());
 
    count0 = 0;
    count1 = 0;
 
    for(i = 0; i < 12; i++)
      {
 
        //inicia reta 
        power0 = QPOWERRETA0;
        power1 = QPOWERRETA1;
 
        //faz anda reto
        while (1)  {       
 
            //calcula a velocidade  
            velocidade0 = encoder6_velocity;
            velocidade1 = encoder5_velocity;                         
 
            power0 -= controleMotor(velocidade0,QVELRETA0);
            power1 -= controleMotor(velocidade1,QVELRETA1);
 
            printf("pw0 %f vel %d",power0,encoder6_velocity);
            printf("pw1 %f vel %d %d\n",power1,encoder5_velocity,(int)(dif));
 
            //calcula erro jah cometido
            dif = (float) (count0 - count1);
 
 
            //ajusta power de acordo com erro
            if(dif - QPROP > Qerrcd)
              {
                power1 += (Qkp*(dif - QPROP));
                // power0 -= (int)(kp)*dif + erro0;
            }
            else if(dif - QPROP < -Qerrcd)
              {
                power0 += -(Qkp*(dif - QPROP)) ;
                //power1 += (int)(kp)*dif - erro1;
            }
 
 
            motor(0,(int)power0);
            motor(1,(int)power1);
 
            //manrtem o numero de counts atualizado 
            count0 += encoder6_counts - countAux0 ;
            count1 += encoder5_counts - countAux1;
            countAux0 = encoder6_counts; 
            countAux1 = encoder5_counts;
 
            // completou lado quagrado
            if((count0 + count1) >= QLADO) break;
 
 
            msleep(QSLEEP);
            if(stop_button() || sair == 1){ sair = 1; break;}
 
        }
 
        off(0);
        off(1);
        msleep(200L);
        //inicia a curva
        power0 = QNOVPOWER0;
        power1 = QNOVPOWER1;
        count0 = 0;
        count1 = 0;
        //faz 90 graus       
        while (1)  {       
 
            //pega a velocidade
            velocidade0 = encoder6_velocity;
            velocidade1 = encoder5_velocity;                         
 
            //pega o power necessario para a velocidade de destino
            power0 -= controleMotor(velocidade0,QVELPD0);
            power1 -= controleMotor(-velocidade1,QVELPD1);
 
            printf("pw0 %f vel %d",power0,encoder6_velocity);
            printf("pw1 %f vel %d %d\n",power1,encoder5_velocity,(int)(dif));      
 
            //ativa os motores
            motor(0,(int)power0);
            motor(1,(int)power1);
 
            //mantem o numero de rotacoes atualizadas
            count0 += encoder6_counts - countAux0 ;
            count1 += encoder5_counts - countAux1;
            countAux0 = encoder6_counts; 
            countAux1 = encoder5_counts;
 
            //completou 90 graus
            if((count0 + count1) >= QARETO) break;//
 
            msleep(QSLEEP);
            if(stop_button() || sair == 1){ sair = 1; break;}
 
        }
 
        off(0);
        off(1);
        msleep(200L);
 
        // mantem o erro de rotacao
        if(count0 > count1) 
          {
            count1 = count0 - count1;
            count0 = 0;
        }else
          {
            count0 = count1 - count0;
            count1 = 0;
 
        }
 
        if(stop_button() || sair == 1) break;
 
 
    }    
 
}
//faz o controle dos motores utilizando a velociadade
float controleMotor(int velocidadeMotor,int velocidadeObjMotor)
{
 
    float power;
 
    //faz om que motor mantenha um certa velocidade
    if(velocidadeMotor != velocidadeObjMotor)
      {
        power = Qkd*((float)(velocidadeMotor - velocidadeObjMotor));            
 
    }
 
    return power;
}

Montagem da Caneta

A montagem da caneta foi realizada de forma que a mesma ficou entre os eixos dos motores do robô e próximo ao seu centro de rotação. A montagem exigiu uma remodelagem de algumas peças do robô além do redimencionamento da caneta, mas foi realizada com sucesso.

Apresentação

A apresentação ocorreu sem maiores problemas. O objetivo de fazer uma trajetoria circular e outra quadrada foram realizadas pelo robô. As imagens a seguir ilustram os resultados obtidos.

Vídeo da apresentação:

http://www.youtube.com/watch?v=_EOfrhQGVLY

Tarefas Complementares

Exercícios 1 e 4

Exercício 1

Esse exercício consistiu na implementação de um controle PD, de forma a igualar os resultados obtidos no livro.

Exercício 4

A principal dificuldade encontrada em manter o robô em linha reta esteve na calibragem do controle. Sendo que o fator que mais afetou nossa calibragem foi a localização dos sensores. Quando os sensores estavam localizados na roda diretamente tivemos dificuldades devido ao baixo valor da velocidade que era capturada, mudamos então a localização desses sensores de forma que esses ficassem diretamente nos motorores, conseguindo, assim, um controle mais acurado para nossos propósitos.

Medição do erro de translação

Os gráficos e tabelas acima foram obtidos medindo, para cada valor de velocidade(20%,60% e 100% da velocidade), a distância percorrida pelo robô em um determinado tempo. Para realizar essas medidas foram feitos três experimentos para cada valor de tempo, sendo a média obtida plotada nos gráficos. Nesses gráficos é apresentado também a regressão linear da média obtida nos experimentos, mostrando assim que o valor esperado estava próximo do valor obtido nas medições. A equação produzida pela regressão linear representa a formula d = v*t.

Medição do erro de rotação

Nesse experimento o objetivo era medir o erro de translação com o robô em diferentes velocidades. Assim, o robô deveria rodar em cima do eixo principal 90º. A tabela acima mostra os resultados obtidos para a média de três experimentos para cada velocidade (20%,60% e 100% da velocidade).

Conclusão

O objetivo de familiarização com os lego e a handyboard foi atingido com sucesso. Durante o processo de aprendizagem tivemos a chance ter contato com uma parte mais prática do curso, e mesmo com diversas dificuldades, conseguimos realizar todas as tarefas propostas para o trabalho.

cursos/introrobotica/2011-2/grupo03/tp1.txt · Última modificação: 2011/10/02 18:30 por dougmf