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
Sem Iluminação constante, distância 3mm
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
O comportamento é não linear, mas para distâncias menores que 10mm e maiores que 3mm podemos fazer uma aproximação linear razuavel.
Fizemos entao uma regressão de quarta ordem que abrange os 4 pontos.
Efeito dos motores na leitura do sensor
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
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