===== Trabalho Pratico 2 ===== ==== Objetivo ==== * Maior Familiarização com a HandyBoard e com o ambiente de programção IC. * Adquirir noções sobre o funcionamento de sensores e a melhor utilização destes com a HandyBoard. * Noções basicas sobre processamento dos sinais adquiridos atraves dos sensores. ==== Montagem do robô ==== As unicas modificações no robô foram as intalações dos sensores e a adição de um pequeno compartimento para a realização da identificação dos blocos, cujo objetivo é manter as condições de luminosidade constanstes. ==== Dificuldades encontradas ==== == - Lidar com os sensores == Os sensores se mostraram um pouco ineficientes quando a superficie do objeto a ser identificado nao era liso (exemplo:Blocos fornecidos, eram muito porosos o que dificulta a reflexão da luz proveniente do emissor). Tambem apresentaram resultados ruins quando havia muito reflexão na superfie (exemplo: plista sobre a qual foi montada a trajetoria com a linha preta quando esta estava sujeita a forte iluminação artificial). == - Resolução dos problemas == A solução é tratar os sinais dos sensores por meio de algoritimos adequados a cada aplicação. === Resultados Obtidos dos testes === Apos a realização dos testes propostos obtivemos os seguintes resultados: == Iluminação constante, distância 3mm == {{:cursos:introrobotica:2007-2:grupo6:Constante_3mm.jpg?640x480|Constante_3mm.jpg}} == Sem Iluminação constante, distância 3mm == {{:cursos:introrobotica:2007-2:grupo6:Variante_3mm.jpg?640x480|Variante_3mm.jpg}} Podemos observar que a variação da luminosidade causou tambem uma flutuação do sinal em torno da média e um deslocamento para baixo da média. == Curva Sinal x Distância == {{:cursos:introrobotica:2007-2:grupo6:Sinal_x_Dist.jpg?640x480|Sinal_x_Dist.jpg}} O comportamento é não linear, mas para distâncias menores que 10mm e maiores que 3mm podemos fazer uma aproximação linear razuavel. {{:cursos:introrobotica:2007-2:grupo6:Regressao_4.jpg?640x480|Regressao_4.jpg}} Fizemos entao uma regressão de quarta ordem que abrange os 4 pontos. == Efeito dos motores na leitura do sensor == {{:cursos:introrobotica:2007-2:grupo6:Motor_3mm.jpg?640x480|Motor_3mm.jpg}} Os motores provocam oscilação do sinal e queda no valor médio. == Validação == Para distâncias diferentes das anteriores obtivemos 4 medidas e 4 valores calculados apartir da equação da regressão de 4 ordem mostrada em figura anterior e os respectivos erros: * Para Dist = 4,5mm Medido = 11 Calculado = -7,48 Erro = 18,48 * Para Dist = 7,5mm Medido = 92,98 Calculado = 69,94 Erro = 23,04 * Para Dist = 10,5mm Medido = 171,84 Calculado = 162,65 Erro = 9,19 * Para Dist = 13,5mm Medido = 212,92 Calculado = 206,49 Erro = 6,43 == Influência da superfície na identificação dos blocos == {{:cursos:introrobotica:2007-2:grupo6:Cores_x_Dist.jpg?640x480|Cores_x_Dist.jpg}} Vemos pelo gráfico que a melhor distancia é 3mm, pois propicia a maior distancia entre os sinais. Além disso vimos que penas variações na distancia podem provocar troca entre as cores. O algoritimo que utilizamos é baseado na media do sinal obtido atraves do sensor. === LISTA DE EXERCICIOS === Normalização: 1-Para os valores medidos do sensor temos: Máximo de Luz Refletida = 6 Mínimo de Luz Refletida = 252 /*normal.c*/ int normalize (int light) { int MAX_LIGHT = 6; int MIN_LIGHT = 252; int output = 100 - ( (light – MAX_LIGHT)*100 / (MIN_LIGHT – MAX_LIGHT) ); if (output < 0) output = 0; if (output > 100) output = 100; return output; } 2-Utilizando a função normalize para o sensor fotoelétrico QRB1113 obtivemos os valores esperado, uma vez que foram normalizados. A faixa de valores que a função retorna é de zero a cem. 3-Quando o sensor estiver em contato com uma superfície mais refletora do que a utilizada na calibração (superfícies brancas) ou quando a superfície for menos refletora que a utilizada na calibração (superfícies pretas) o valor encontrado estará fora do range; ou seja, MAX_LITHG > valor medido ou MIN_LIGHT < valor medido. Valores Históricos: 1-Para um array de 50 posições e uma frequência de aquisição de dados de 7,8125Hz temos: Tempo = 50/7,8125 e Tempo = 6,4 segundos 3-/* stuck.c*/ void STUCKROBOT() { int valores[50]; int i = 0; float x; while(1) { If(i!=0) { x = analog(2); if( x != valores( i – 1 ) ) { i = 0; } valores( i ) = x; if( i == 49) { printf(“stucked”); } } else{ valores( i ) = analog(2); } i++; sleep(0.1); } } O programa compara o valor lido com o último valor do buffer, caso seja igual armazena na posição corrente do buffer, caso seja diferente armazena na primeira posição do buffer. Se o buffer encher indica que todos os valores são iguais e que o robô está parado. ==== Codigo Fonte ==== === funcoes.ic === /*Variavel global*/ int vetCont; int vetCont2; /* * * Funcionalidades * * */ int calibraCor(int cor) { float media, desvio; calculaDados(); media = calculaMedia(); MEDIA_COR[cor] = media; return 1; } int calibraPretoBranco() { float sensorLocomocao[2][2]; printf("Calibrar preto nos sensores.\n"); while(!start_button()); while(start_button()); calculaDadosPretoBranco(PRETO, sensorLocomocao); printf("Calibrar branco nos sensores.\n"); while(!start_button()); while(start_button()); calculaDadosPretoBranco(BRANCO, sensorLocomocao); calculaMediaPretoBranco(sensorLocomocao); FUNCAO_ATIVA = 0; } int identificaCor() { int melhor_cont, i; float media, melhor, temp; calculaDados(); media = calculaMedia(); melhor = 256.0; for(i = 0; i < 4; i++) { temp = (media - MEDIA_COR[i]); if(temp < 0.0) { temp = temp*-1.0; } if (temp < melhor) { melhor = temp; melhor_cont = i; } } if (melhor_cont == VERDE) printf("Verde.\n"); else if (melhor_cont == VERMELHO) printf("Vermelho.\n"); else if (melhor_cont == AZUL) printf("Azul.\n"); else if (melhor_cont == AMARELO) printf("Amarelo.\n"); sleep(5.0); beep(); return 1; } /* * * Locomocao * * */ int locomocao() { int tarefa_caminhar; int tarefa_matar; FUNCAO_ATIVA = 1; andarReto(); tarefa_caminhar = start_process(caminhar()); tarefa_matar = start_process(parar()); while(FUNCAO_ATIVA); kill_process(tarefa_caminhar); kill_process(tarefa_matar); ao(); return 1; } void caminhar() { while(1) { //Se sensor esquerdo entrar numa faixa branca vira pra esquerda if(((float)analog(PORTA_SENSOR_ESQ)) < MEDIA_PRETO_BRANCO[SENSOR_ESQ] && ((float)analog(PORTA_SENSOR_DIR)) < MEDIA_PRETO_BRANCO[SENSOR_DIR]) { virarEsquerda(); } //Se sensor direito entrar numa faixa preto vira pra direita if(((float)analog(PORTA_SENSOR_DIR)) > MEDIA_PRETO_BRANCO[SENSOR_DIR] && ((float)analog(PORTA_SENSOR_ESQ)) > MEDIA_PRETO_BRANCO[SENSOR_ESQ]) { virarDireita(); } //Se sensor direito entrar numa faixa preto vira pra direita /*if(((float)analog(PORTA_SENSOR_DIR)) > MEDIA_PRETO_BRANCO[SENSOR_DIR] && ((float)analog(PORTA_SENSOR_ESQ)) < MEDIA_PRETO_BRANCO[SENSOR_ESQ]) { virarDireita(); }*/ //Se sensor direito entrar numa faixa preto vira pra direita if(((float)analog(PORTA_SENSOR_DIR)) < MEDIA_PRETO_BRANCO[SENSOR_DIR] && ((float)analog(PORTA_SENSOR_ESQ)) > MEDIA_PRETO_BRANCO[SENSOR_ESQ]) { andarReto(); } } } void virarEsquerda() { motor(MOTOR_ESQ, (int)(-1*POTENCIA_MOTOR_ESQ)); motor(MOTOR_DIR, POTENCIA_MOTOR_DIR); } void virarDireita() { motor(MOTOR_ESQ, POTENCIA_MOTOR_ESQ); motor(MOTOR_DIR, (int)(-1*POTENCIA_MOTOR_DIR)); } void andarReto() { motor(MOTOR_ESQ, POTENCIA_MOTOR_ESQ); motor(MOTOR_DIR, POTENCIA_MOTOR_DIR); } /* * * * Funcoes auxiliares * */ float calculaMedia() { int i; int m = 0; for(i = 0; i < vetCont; i++) { m += VET_DADOS[i]; } return ((float) m / (float) vetCont); } float calculaMediaPretoBranco(float sensorLocomocao[][]) { MEDIA_PRETO_BRANCO[SENSOR_ESQ] = (sensorLocomocao[SENSOR_ESQ][PRETO] + sensorLocomocao[SENSOR_ESQ][BRANCO])/2.0; MEDIA_PRETO_BRANCO[SENSOR_DIR] = (sensorLocomocao[SENSOR_DIR][PRETO] + sensorLocomocao[SENSOR_DIR][BRANCO])/2.0; } int calculaDados() { int tarefa_dados; tarefa_dados = start_process(adquirirDadosCor()); sleep(5.0); beep(); kill_process(tarefa_dados); return 1; } void adquirirDadosCor() { vetCont = 0; printf("Aguarde...\n"); while(1) { VET_DADOS[vetCont++] = analog(PORTA_SENSOR_COR); sleep(0.1); } } void calculaDadosPretoBranco(int cor, float sensorLocomocao[][]) { int i; int m = 0; int tarefa_dados; tarefa_dados = start_process(adquirirDadosPretoBranco()); sleep(5.0); beep(); kill_process(tarefa_dados); m = 0; for(i = 0; i < vetCont; i++) { m += VET_DADOS[i]; } sensorLocomocao[SENSOR_ESQ][cor] = ((float) m / (float) vetCont); m = 0; for(i = 0; i < vetCont2; i++) { m += VET_DADOS2[i]; } sensorLocomocao[SENSOR_DIR][cor] = ((float) m / (float) vetCont2); } void adquirirDadosPretoBranco() { vetCont = 0; vetCont2 = 0; printf("Aguarde...\n"); while(1) { VET_DADOS[vetCont++] = analog(PORTA_SENSOR_ESQ); VET_DADOS2[vetCont2++] = analog(PORTA_SENSOR_DIR); sleep(0.1); } } void parar() { while(!stop_button()); while(stop_button()); FUNCAO_ATIVA = 0; } === menu.ic === #define MOTOR_ESQ 1 #define MOTOR_DIR 3 #define TEMPO_30_CM 2.0 #define TEMPO_90_GRAUS 1.15 #define VERDE 0 #define VERMELHO 1 #define AZUL 2 #define AMARELO 3 #define PRETO 0 #define BRANCO 1 #define PORTA_SENSOR_COR 4 #define PORTA_SENSOR_ESQ 2 #define PORTA_SENSOR_DIR 6 #define SENSOR_ESQ 0 #define SENSOR_DIR 1 /*Variavel global responsavel pelo armazenamento da potencia dos motores*/ int POTENCIA_MOTOR_ESQ, POTENCIA_MOTOR_DIR; int FUNCAO_ATIVA; int VET_DADOS[100]; int VET_DADOS2[100]; float MEDIA_COR[4]; float MEDIA_PRETO_BRANCO[2]; void menu() { char menuPrincipal[5][30] = {"1- Seguir linha preta", "2- Identificar blocos", "3- Calibrar cores", "4- Calibrar preto e branco", "5- Pegar Dados"}; int item, contador, retorno = 1; POTENCIA_MOTOR_ESQ = 50; POTENCIA_MOTOR_DIR = 50; while(1) { #ifdef DEBUG printf("Opcao escolhida: %d\n", contador); #endif if(start_button()) { //Caso alguma opcao tenha sido marcada while(start_button()); //Aguarda que tire-se o dedo do butao start if (contador == 1) { retorno = locomocao(); } else if (contador == 2) { retorno = identificaCor(); } else if (contador == 3) { retorno = menuCalibracaoCor(); } else if (contador == 4) { retorno = menuCalibracaoPretoBranco(); } else if (contador == 5) { retorno = calculaDados(); } } else { if(retorno == 1) { imprimeMenu2(&contador, 4, menuPrincipal); retorno = 0; } else { imprimeMenu(&contador, 4, menuPrincipal); } } } } int menuCalibracaoCor() { int item; int retorno; char menu[4][20] = {"1- Verde", "2- Vermelho", "3- Azul", "4- Amarelo"}; while(1) { #ifdef DEBUG printf("loop motoresMenu\n"); #endif if(stop_button()) { while(stop_button()); return 1; } else if(start_button()) { while(start_button()); retorno = calibraCor(item - 1); #ifdef DEBUG printf("Retornou de calibrar angulos\n"); #endif } else { if(retorno == 1) { imprimeMenu2(&item, 4, menu); retorno = 0; } else { imprimeMenu(&item, 4, menu); } } } } int menuCalibracaoPretoBranco() { int tarefa_calibra; int tarefa_matar_calibra; FUNCAO_ATIVA = 1; tarefa_calibra = start_process(calibraPretoBranco()); tarefa_matar_calibra = start_process(parar()); while(FUNCAO_ATIVA); kill_process(tarefa_calibra); kill_process(tarefa_matar_calibra); return 1; } /*Funcao chamada para imprimir a opcao do menu possibilitando a livre movimentacao entre as mesmas.*/ void imprimeMenu(int *contador, int tam, char arranjo[][]) { int resultado, item; item = (255 / tam) + 1; resultado = (*contador) * item; if (knob() > resultado) { //(*contador)++; (*contador) = (knob() / item) +1; printf("%s\n",arranjo[knob() / item]); //printf("%s\n",arranjo[((*contador)-1) % tam]); } else if (knob() < ((*contador)-1) * item) { (*contador) = (knob() / item) +1; printf("%s\n",arranjo[knob() / item]); // (*contador)--; // printf("%s\n",arranjo[((*contador)-1) % tam]); } } void imprimeMenu2(int *contador, int tam, char arranjo[][]) { int item; item = (255/tam) + 1; printf("%s\n",arranjo[knob() / item]); (*contador) = (knob() / item) +1; } === main.ic === main apenas chama a função menu === Documentação PDF === | {{:cursos:introrobotica:2007-2:grupo6:Documentacao_TP2.pdf|Documentacao_TP2.pdf}} | \\ \\