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.
Foram realizadas diversas montagens até chegar ao modelo final apresentado na figura abaixo.
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"); }
O controle desenvolvido para o trabalho tenta manter cada uma das rodas a uma velocidade predeterminada.
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); }
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; }
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.
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:
Esse exercício consistiu na implementação de um controle PD, de forma a igualar os resultados obtidos no livro.
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.
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.
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).
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.