Trabalho Prático 2 - Locomoção
A missão dessa vez era construir um robô móvel que ainda fosse capaz de detectar objetos e suas cores. As tarefas que o Colorful Potato deveria executar são:
A fim de diminuir os efeitos da diferença de velocidade dos motores, a redução feita foi simétrica. As paredes verticais do robô foram feitas com uma peça furada travada em vez de uma pilha de peças convencionais.
O LDR foi utilizado como sensor para detectar as cores e para detectar objetos na frente do robô, com o auxílio de um LED RGB. A luminosidade medida pelo LDR variava muito nos nossos testes, então a etapa seguinte foi fixar a posição relativa do LDR ao LED. Foram furadas 3 peças de lego para encaixar o LED RGB e o LDR de forma que fosse possível montar o sensor convenientemente no robô.
O código foi modularizado de forma a criar camadas de abstração, permitindo a colaboração mesmo sem a implementações de partes do código ou que todas as pessoas estivessem se preocupando com especificidades da implementação.
O arquivo principal “ColorfulPotato.ino” é onde foi implementado o menu, que chama as tarefas de Tarefas.h optadas pelo usuário.
Cada tarefa tem uma função que corresponde a um requisito de comportamento do robô, por exemplo:
void MostraNoLCDCorDetectada(); void ExploraAmbiente();
Cada uma dessas funções executa a sequencia de ações para realizar a tarefa. Essas ações são acionamentos e medições feitas em Movimentacao.h e SensorDeLuz.h
Movimentação:
void para(); void anda(int d); void gira_sentido_horario(double t); void anda_re(int d); void gira_sentido_antihorario(double t); void set_speed(int left_speed , int right_speed); void set_speed()
SensorDeLuz
bool DetectaObjeto(); char DetectaCor(); void SENSORDELUZ_SETUP();
Para detecção das cores, foram feitos os procedimentos abaixo:
1) Fazer uma leitura da iluminação ambiente com o LDR, com o LED apagado;
2) Acender separadamente cada uma das 3 cores do LED e medir a reflexão com o LDR;
3) Subtrair a leitura de iluminação ambiente das leituras das cores e armazenar esses valores.
Com esses procedimentos, foi possível realizar diversas medidas com os blocos a detectar e chegar empiricamente ao algoritmo abaixo, com resultados satisfatórios:
// Algoritmo que calcula a cor if(blueOutput > redOutput && blueOutput > greenOutput){ Serial.println("BLUE"); }else if(greenOutput > redOutput && greenOutput > blueOutput){ Serial.println("GREEN"); }else if(redOutput*0.55 > greenOutput){ Serial.println("RED"); }else if(redOutput*0.6 < blueOutput){ Serial.println("BLACK"); }else { Serial.println("YELLOW"); }
A lógica por trás desse algoritmo consiste do fato de que para blocos vermelhos, amarelos e pretos a resposta do led vermelho é a mais intensa. Dessa forma, para distinguir entre os três, utiliza-se da proporção entre o valor da resposta ao led vermelho e as demais cores, calculada de forma empírica. Por fim, os blocos são detectados como azuis ou verdes quando a respostas dos leds de suas respectivas cores são as maiores entre as três.
Para detectar a presença de objetos na frente do sensor, foi definido a utilização de um valor limiar de escuridão (THRESHOLD_OBSTACULO_DE_LUZ) que, se houvesse uma medida abaixo desse valor, seria considerado que um objeto havia sido detectado.
As constantes de pinagem, velocidade, limiares, dimensões, etc., necessárias para o código foram definidas em Configuracao.h, que ficou com essa cara:
/* LED E LDR */ // Pinos dos LEDs const int RED_PIN = 23; // Fio vermelho const int GREEN_PIN = 25; // Fio azul const int BLUE_PIN = 27; // Fio laranja; Fio marrom é o terra // Pino do LDR const int LDR_PIN = A8; // VCC=vermelho, GND=marrom, SIG(A8)=amarelo /* LUZ E LUMINOSA */ const int THRESHOLD_OBSTACULO_DE_LUZ = 150;
O uso de #define's foi substituido por definições com const tanto quanto possível em função de uma recomendação encontrada nessa referência
Os maiores desafios desse trabalho foram a elaboração do algoritmo de detecção de cores, fazer com que o LDR detectasse um objeto e realizar as tarefas de maneira assíncrona da atividade de multitarefas.
O algoritmo de cores, apesar de ter um código simples, foi complicado de ser elaborado por não haver uma forma teórica de prever e calcular os valores, visto que o LDR é um sensor bem básico para medição de luminosidade e só possui alta sensibilidade em parte do espectro vísivel dos comprimentos de onda da luz. Assim, o algoritmo exigiu que fosse feito um experimento empírico para elaboração do código.
Para detectar um objeto, a dificuldade foi parecida com a do algoritmo de cores. Nesse caso, um sensor óptico deveria ter sido utilizado para maior confiabilidade na detecção, mas no fim foi possível realizar detecção com o LDR satisfatoriamente.
Na operação multitarefa, o desafio era evitar que o código ficasse preso em loops e principalmente delays de uma tarefa específica, impedindo que outras tarefas fossem executadas simultaneamente. Desta forma, foram elaboradas funções para movimentar o robô para frente e para trás que, com os devidos valores passados por parâmetros, não prendem a execução do código dentro das mesmas. Então, foi possível chamar uma função que manda o robô andar indefinidamente, sem travar o código, e realizar outras tarefas como chamar a detecção de objetos e verificar se o tempo de 10 segundos que o robô estava andando havia se esgotado para poder encerrar a tarefa.