Grupo 1 - Skynet
Integrantes
- Álvaro Caetano - alvaro.caetano@hotmail.com
- Gabriel Duarte Pasa - gabrieldpasa@gmail.com
- Olívia Maria Alves Coelho - olivia.ac@hotmail.com
- Lucas Raphael Leão Martins - lucasraphaellm@gmail.com
O Robô: T-800
Trabalhos Práticos
Trabalho Prático 1
Objetivos
- Montagem de um robô baseado no “Handybug” (Robotics Exploration, de Fred Martin);
- Adicionar um marcador (pincel de quadro branco) de tal forma que a trajetória do robô seja desenhada;
- Medição de erros de translação e rotação para diferentes potências;
- Fazer o robô realizar trajetórias quadradas e circulares para apresentação.
Ideias Iniciais
O início da elaboração das estratégias para o projeto do robô começou primeiro pelo projeto mecânico, com decisões baseadas nos movimentos que o robô precisava fazer para executar as tarefas propostas. Baseado no projeto do “Handybug” idealizamos um robô de duas rodas motorizadas e um apoio (esfera de desodorante roll-on), também resolvemos que o nosso marcador ficaria perpendicular aos eixos das rodas, pois dessa forma, desenharia o caminho correto do robô, até mesmo nas curvas.
Para o software, após uma lida no “The Handy Board Technical Reference”, decidimos que faríamos uma interface mais elaborada, para executarmos todas as funções necessárias para as tarefas, sem a necessidade de fazer vários downloads a cada novo teste.
Montagem
Após planejarmos um pouco resolvemos que faríamos protótipos de montagem para decidirmos qual a melhor forma de ligação do motor às rodas. Utilizando os dois motores que já estavam no kit, fizemos uma montagem com os motores ligados a uma redução a partir de uma rosca sem fim:
Reforçando um pouco a estrutura:
O resto da montagem foi feita de forma a garantir a passagem do marcador e manter a estrutura do robô firme com algumas travas feitas com as peças de LEGO.
Por fim, foi necessário a montagem de um suporte para a Handy Board, adicionando algumas vigas travadas na lateral para que esta não deslizasse lateralmente. Fizemos dois projetos de suporte e escolhemos o suporte menor, pois garantiria mais estabilidade e tração nas rodas dianteiras.
Características do robô:
Ao final da montagem, obtivemos um robô com as seguintes características:
- Estrutura rígida e firme, utilizando travamentos com peças LEGO;
- Três rodas: duas dianteiras e uma traseira. As rodas dianteiras realizam o movimento de translação e não têm liberdade de rotação. A roda traseira realiza movimentos livres de rotação;
- Sistemas de redução baseados em roscas sem fim;
- Pincel localizado perpendicularmente ao centro do eixo das rodas dianteiras.
Medições de Erros
Erro de Translação
Potência = 60/Tempo = 4,0 s
Medida | Distância (cm) |
---|---|
1 | 36,0 |
2 | 37,0 |
3 | 37,0 |
4 | 37,3 |
5 | 37,3 |
6 | 35,5 |
7 | 36,7 |
Desvio padrão = 0.69
Potência = 100/Tempo = 3,01 s
Medida | Distância (cm) |
---|---|
1 | 38,4 |
2 | 39,1 |
3 | 38,4 |
4 | 38,0 |
5 | 38,1 |
6 | 38,9 |
7 | 39,3 |
Desvio padrão = 0.5
Erro de Rotação
Potência = +-60/Tempo = 1,87 s
Medida | Rotação |
---|---|
1 | 87º |
2 | 89º |
3 | 90º |
4 | 90º |
5 | 92º |
6 | 91º |
7 | 89º |
Desvio padrão = 2.1
Potência = +-100/Tempo = 1,09 s
Medida | Rotação |
---|---|
1 | 92º |
2 | 91º |
3 | 92º |
4 | 92º |
5 | 93º |
6 | 96º |
7 | 89º |
Calibração
A calibração foi feita no mesmo programa usado na apresentação (execução de quadrados e círculos). Um menu é mostrado na tela e permite a escolha da opção de calibração, de modo a facilitar o processo. Os valores de calibração foram implementados em variáveis permanentes, de forma que fossem retidos mesmo após o desligamento da placa. Estes valores são as potências percentuais para o acionamento dos motores (um costumava ser mais forte que o outro) e os tempos de espera para a execução dos movimentos (giro 90º, translação ao longo do círculo, da aresta do quadrado, etc). Como não foram utilizados sensores (shaft encoders), a calibração teve papel fundamental na execução correta dos movimentos.
Desenvolvimento do Software
Código:
- TP1.c
//////////////////////////////////// // Constantes // //////////////////////////////////// #define NUM_OPCOES 5 #define FAZ_QUAD 4 #define FAZ_CIRC 3 #define CALIBRACAO_RETA 2 #define CALIBRACAO_QUAD 1 #define CALIBRACAO_CIRC 0 #define WIDTH 15.5 //////////////////////////////////// // Variaveis Globais (calibracao) // //////////////////////////////////// // Motor 1 persistent int motor1 = 70; // Motor 2 persistent int motor2 = 68; // Motor 1 circulo persistent int motor1circ = 100; // Motor 2 circulo persistent int motor2circ = 32; // Aresta 30 cm persistent float tempo_aresta = 2.70; // Canto 90 graus persistent float tempo_canto = 1.24; // Circulo 30 cm raio persistent float tempo_circ = 17.5; //////////////////////////////////// // Funcoes // //////////////////////////////////// /**********************************/ // Desenha o quadrado // /**********************************/ void quadrado(){ int lado, lado_old; int i; float tempo; while(1) { lado_old = -1; do { lado = knob()*50/255; if (lado != lado_old) { printf ("LADO: Escolha o Lado %d\n", lado); lado_old = lado; } } while(!start_button() && !stop_button()); // Volta para o menu inicial if (stop_button()) { while(stop_button()); return; } while(start_button()); printf("Desenhando quadrado de lado %d\n", lado); tempo = ((float)lado*tempo_aresta)/30.0; for (i = 0; i < 12 && !stop_button(); ++i) { motor(1, motor1); motor(2, motor2); sleep(tempo); alloff(); sleep(0.5); motor(1, motor1); motor(2, -motor2); sleep(tempo_canto); alloff(); sleep(0.5); } while(stop_button()); } } /**********************************/ // Desenha o circulo // /**********************************/ void circulo(){ int raio, raio_old; int i; int pot1, pot2; float k, tempo; while(1) { raio_old = -1; do { raio = knob()*50/255; if (raio != raio_old) { printf ("RAIO: Escolha o Raio %d\n", raio); raio_old = raio; } } while(!start_button() && !stop_button()); // Volta para o menu inicial if (stop_button()) { while(stop_button()); return; } while(start_button()); printf("Desenhando circ de raio %d\n", raio); // Nao implementado pot1 = motor1circ; pot2 = motor2circ; tempo = 3.0*tempo_circ; motor(1, pot1); motor(2, pot2); sleep(tempo); alloff(); } } /**********************************/ // Calibracao da reta // /**********************************/ void calibracao_reta() { int pot1, pot_old1; int pot2, pot_old2; float tempo, tempo_old; int voltar; while(1) { voltar = 0; pot_old1 = 200; pot_old2 = 200; tempo_old = -1.0; printf("Calibrando reta de 30 cm\n"); // Volta para o menu inicial while(!start_button() && !stop_button()); if (stop_button()){ while(stop_button()); return; } while(start_button()); do { pot1 = ((knob() - 127)*100)/127; if (pot_old1 != pot1) { printf("Potencia motor 1 = %d\n", pot1); pot_old1 = pot1; } } while(!start_button() && !stop_button()); if (stop_button()) voltar = 1; while(start_button() && !voltar); do { pot2 = ((knob() - 127)*100)/127; if (pot_old2 != pot2) { printf("Potencia motor 2 = %d\n", pot2); pot_old2 = pot2; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); do { tempo = ((float)knob()*7.)/255.; if (tempo_old != tempo) { printf("Tempo = %f\n", tempo); tempo_old = tempo; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); while(!voltar) { printf("Pressione START ou STOP\n"); while(!start_button() && !stop_button()); if (stop_button()){ while(stop_button()); break; } while(start_button()); printf("p1=%d p2=%d t = %f\n", pot1, pot2, tempo); // Atualiza as variaveis de calibracao motor1 = pot1; motor2 = pot2; tempo_aresta = tempo; motor(1, pot1); motor(2, pot2); sleep(tempo); alloff(); } } } /**********************************/ // Calibracao do quadrado // /**********************************/ void calibracao_quadrado() { float tempo1, tempo_old1; float tempo2, tempo_old2; int voltar, i; while(1) { voltar = 0; tempo_old1 = -1.0; tempo_old2 = -1.0; printf("Calibrando tempos quadrado.\n"); while(!start_button() && !stop_button()); // Volta para o menu inicial if (stop_button()) { while(stop_button()); return; } while(start_button()); do { tempo1 = ((float)knob()*15.)/255.; if (tempo_old1 != tempo1) { printf("Tempo aresta = %f\n", tempo1); tempo_old1 = tempo1; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); do { tempo2 = ((float)knob()*7.)/255.; if (tempo_old2 != tempo2) { printf("Tempo canto = %f\n", tempo2); tempo_old2 = tempo2; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); while(!voltar) { printf("Pressione START ou STOP\n"); while(!start_button() && !stop_button()); if (stop_button()) break; while(start_button()); printf("aresta=%f canto=%f\n", tempo1, tempo2); // Atualiza as variaveis de calibracao tempo_aresta = tempo1; tempo_canto = tempo2; for (i = 0; i < 4 && !stop_button(); ++i) { motor(1, motor1); motor(2, motor2); sleep(tempo1); alloff(); sleep(0.3); motor(1, -motor1); sleep(0.2); off(1); motor(1, -motor1); motor(2, motor2); sleep(tempo2); alloff(); sleep(0.3); } if (stop_button()) { while(stop_button()); voltar = 1; } } } } /**********************************/ // Calibracao do circulo // /**********************************/ void calibracao_circulo() { int pot1, pot_old1; int pot2, pot_old2; float tempo, tempo_old; int voltar; while(1) { voltar = 0; pot_old1 = 200; pot_old2 = 200; tempo_old = -1.0; printf("Calibrando circ de raio 30 cm\n"); // Volta para o menu inicial while(!start_button() && !stop_button()); if (stop_button()){ while(stop_button()); return; } while(start_button()); do { pot1 = ((knob() - 127)*100)/127; if (pot_old1 != pot1) { printf("Potencia motor 1 = %d\n", pot1); pot_old1 = pot1; } } while(!start_button() && !stop_button()); if (stop_button()) voltar = 1; while(start_button() && !voltar); do { pot2 = ((knob() - 127)*100)/127; if (pot_old2 != pot2) { printf("Potencia motor 2 = %d\n", pot2); pot_old2 = pot2; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); do { tempo = ((float)knob()*40.)/255.; if (tempo_old != tempo) { printf("Tempo = %f\n", tempo); tempo_old = tempo; } } while((!start_button() && !stop_button()) && !voltar); if (stop_button()) voltar = 1; while(start_button() && !voltar); while(!voltar) { printf("Pressione START ou STOP\n"); while(!start_button() && !stop_button()); if (stop_button()){ while(stop_button()); break; } while(start_button()); printf("p1=%d p2=%d t = %f\n", pot1, pot2, tempo); // Atualiza as variaveis de calibracao motor1circ = pot1; motor2circ = pot2; tempo_circ = tempo; motor(1, pot1); motor(2, pot2); sleep(tempo); alloff(); } } } /**********************************/ // Programa Principal // /**********************************/ int main(){ int modo, modo_old; while(1) { modo_old = -1; printf ("T-800 TP1 Aperte START \n"); while(!start_button()); while(start_button()); do { modo = knob()*(NUM_OPCOES - 1)/255; if (modo != modo_old) { modo_old = modo; switch(modo){ case FAZ_QUAD: { printf("Faz quadrado Aperte START\n"); } break; case FAZ_CIRC: { printf("Faz circulo Aperte START\n"); } break; case CALIBRACAO_RETA: { printf("Calibracao reta Aperte START\n"); } break; case CALIBRACAO_QUAD: { printf("Calibracao quad Aperte START\n"); } break; case CALIBRACAO_CIRC: { printf("Calibracao circ Aperte START\n"); } break; } } } while(!start_button()); while(start_button()); switch(modo){ case FAZ_QUAD: { quadrado(); } break; case FAZ_CIRC: { circulo(); } break; case CALIBRACAO_RETA: { calibracao_reta(); } break; case CALIBRACAO_QUAD: { calibracao_quadrado(); } break; case CALIBRACAO_CIRC: { calibracao_circulo(); } break; } } }
Resultados
Conclusão
Todos os objetivos do trabalho foram efetuados satisfatoriamente, dentre eles estão: adquirir certo costume com peças, motores, programação de Handy Board, testes e execução de tarefas. Para a realização deste trabalho, optamos por não utilizarmos sensores ainda, logo, não implementamos nenhuma forma de controle. Observamos que dessa forma a transformação de uma trajetória em um caminho, para o nosso robô, é uma tarefa bastante complicada, pois o comportamento deste depende de muitas variáveis além de acionamento de motores. O T-800 foi capaz de realizar os testes e as tarefas de forma satisfatória, apresentando desvios aceitáveis pela forma como foi projetado.
Trabalho Prático 2
Objetivos
- Adicionar sensores de luz ao robô, de modo a permitir que ele siga linhas pretas no chão e reconheça cores.
- Caracterização dos sensores de luz.
Ideias Iniciais
Escolha dos sensores:
Para fazer o reconhecimento da linha, optamos por utilizar um par de sensores infravermelho:
Eles são constituídos por um LED infravermelho e um fotodiodo ou fototransistor que detecta a luz refletida. Este tipo de sensor é especialmente bom nesse caso, pois, se tratando de um sensor infravermelho, ele é menos suscetível à variação da iluminação ambiente.
Apesar de ser ruim para detectar cores, ele é bom para detectar variações de claro/escuro, o que é ideal para o reconhecimento da linha preta contra o tablado branco.
A montagem usada também foi ideal, pois dispõe os sensores numa distância entre si que é próxima da largura da linha preta, o que facilita o controle pois qualquer desvio é percebido rapidamente.
Para o sensor de reconhecimento de cores, foi utilizado um LDR (light dependent resistor), que nada mais é que um resistor que varia a resistência de acordo com a intensidade de luz que incide sobre ele. Além disso, utilizamos LEDs coloridos (vermelho, verde e azul):
Os LEDs são utilizados de forma a obter três valores de intensidade luminosa (RGB), ligando um de cada vez e checando o valor retornado pelo sensor. Um objeto com uma cor dominante irá refletir mais luz naquela frequência (ou faixas de frequência). Ou seja, um objeto azul irá refletir mais a luz emitida pelo LED azul, por exemplo. Dessa forma é possível determinar com razoável precisão a cor do objeto colocado à frente do sensor, observando os padrões para os valores RGB retornados para cada cor.
Caracterização do Sensor
Testes feitos com o Bloco Verde
Iluminação constante
RED | BLUE | GREEN | |
---|---|---|---|
1 | 52 | 63 | 22 |
2 | 45 | 61 | 22 |
3 | 52 | 63 | 22 |
4 | 50 | 60 | 22 |
5 | 50 | 60 | 22 |
6 | 48 | 62 | 22 |
7 | 49 | 62 | 22 |
8 | 50 | 62 | 22 |
9 | 55 | 62 | 22 |
10 | 50 | 62 | 22 |
11 | 49 | 62 | 22 |
12 | 50 | 61 | 22 |
13 | 47 | 62 | 22 |
14 | 50 | 61 | 22 |
15 | 50 | 61 | 22 |
16 | 50 | 61 | 22 |
17 | 47 | 62 | 22 |
18 | 49 | 61 | 22 |
19 | 50 | 61 | 22 |
20 | 50 | 62 | 22 |
Iluminação variável
RED | BLUE | GREEN | |
---|---|---|---|
1 | 50 | 60 | 25 |
2 | 52 | 62 | 24 |
3 | 52 | 61 | 25 |
4 | 52 | 59 | 24 |
5 | 51 | 59 | 24 |
6 | 50 | 59 | 25 |
7 | 51 | 59 | 24 |
8 | 52 | 61 | 25 |
9 | 52 | 55 | 25 |
10 | 52 | 62 | 26 |
11 | 56 | 63 | 25 |
12 | 54 | 61 | 24 |
13 | 53 | 61 | 24 |
14 | 54 | 63 | 25 |
15 | 52 | 61 | 25 |
16 | 53 | 62 | 24 |
17 | 52 | 60 | 25 |
18 | 52 | 62 | 24 |
19 | 53 | 60 | 24 |
20 | 52 | 59 | 24 |
Sinal x Distância
0,5 | 1,5 | 2,5 | 3,5 | 4,5 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | |
1 | 51 | 61 | 22 | 47 | 37 | 23 | 31 | 29 | 18 | 27 | 24 | 21 | 22 | 21 | 18 |
2 | 55 | 60 | 22 | 45 | 32 | 20 | 34 | 31 | 23 | 29 | 18 | 16 | 23 | 15 | 15 |
3 | 57 | 61 | 22 | 44 | 35 | 24 | 32 | 20 | 16 | 28 | 21 | 16 | 24 | 21 | 21 |
4 | 53 | 61 | 22 | 44 | 32 | 22 | 30 | 38 | 20 | 25 | 20 | 18 | 22 | 15 | 19 |
Motores acionados
RED | BLUE | GREEN | |
---|---|---|---|
1 | 55 | 63 | 25 |
2 | 54 | 62 | 25 |
3 | 53 | 62 | 25 |
4 | 52 | 61 | 25 |
5 | 56 | 62 | 25 |
6 | 52 | 61 | 24 |
7 | 52 | 61 | 25 |
8 | 53 | 61 | 25 |
9 | 52 | 61 | 24 |
10 | 52 | 62 | 25 |
11 | 52 | 61 | 25 |
12 | 52 | 61 | 25 |
13 | 52 | 61 | 24 |
14 | 52 | 61 | 24 |
15 | 52 | 60 | 24 |
16 | 50 | 61 | 24 |
17 | 55 | 61 | 24 |
18 | 49 | 60 | 23 |
19 | 52 | 61 | 23 |
20 | 52 | 60 | 23 |
Influência da Superfície e cor do Objeto
Testes para definir padrões para cores dos blocos
VERDE | AZUL | MARROM | PRETO | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | |
1 | 50 | 60 | 24 | 55 | 29 | 39 | 39 | 56 | 44 | 58 | 60 | 66 |
2 | 53 | 60 | 25 | 62 | 28 | 39 | 41 | 59 | 42 | 60 | 72 | 65 |
3 | 53 | 60 | 25 | 61 | 28 | 39 | 42 | 54 | 43 | 59 | 71 | 65 |
4 | 51 | 60 | 26 | 58 | 28 | 38 | 42 | 58 | 43 | 59 | 72 | 65 |
5 | 54 | 60 | 23 | 59 | 28 | 38 | 39 | 56 | 42 | 57 | 71 | 65 |
VERMELHO | AMARELO | AZUL ESPUMA | VERDE ESPUMA | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | RED | BLUE | GREEN | |
1 | 10 | 65 | 55 | 7 | 49 | 16 | 22 | 15 | 18 | 19 | 22 | 16 |
2 | 10 | 61 | 54 | 7 | 43 | 16 | 22 | 16 | 18 | 20 | 21 | 16 |
3 | 11 | 62 | 55 | 7 | 45 | 17 | 22 | 16 | 18 | 19 | 21 | 16 |
4 | 11 | 62 | 55 | 7 | 43 | 17 | 22 | 16 | 18 | 19 | 22 | 16 |
5 | 10 | 61 | 55 | 7 | 48 | 16 | 21 | 16 | 18 | 19 | 22 | 16 |
VERMELHO ESPUMA | |||
---|---|---|---|
RED | BLUE | GREEN | |
1 | 10 | 30 | 27 |
2 | 10 | 33 | 29 |
3 | 10 | 33 | 30 |
4 | 10 | 33 | 29 |
5 | 10 | 32 | 30 |
Interface de Sensores
Normalizing Exercises
1 - MIN_LIGHT = 150, MAX_LIGHT = 10
2 - Sim. Com a mão tampando o sensor temos o valor mínimo e com o sensor apontado para a luz temos o valor máximo.
3 - Isso pode ocorrer obtendo leituras menores que 'MIN_LIGHT' ou maiores que 'MAX-LIGHT', ou seja, valores fora dos limites estipulados para os experimentos.
Line Following
O programa seguidor de linha implementa a máquina de estados abaixo:
O robô lê os valores dos sensores IR e com isso pode determinar se:
- Não houve desvio (direita = esquerda = escuro);
- Houve um desvio para a direita (direita = claro, esquerda = escuro);
- Houve um desvio para a esquerda (esquerda = claro, direita = escuro);
- Perdeu a linha (esquerda = direita = claro).
As leituras de claro/escuro são determinadas comparando o valor lido pelos sensores com um valor limite pré-determinado (o que não gerou problemas, uma vez que o sensor distingue bem a linha do tablado, mesmo com variações na iluminação ambiente).
Se não houver desvio, o robô segue reto. Se houver desvios, ele tenta corrigí-los, acionando os motores com potências diferentes (de acordo com a direção do desvio detectado).
Por fim, se o robô perde a linha (uma quina no caminho, por exemplo), ele tenta achá-la novamente, dando preferência para o lado em que ela foi vista pela última vez.
Código
Código:
- TP2.c
////////////VARIAVEIS//////////// #define hivel_0 80 #define hivel_1 80 #define lovel_0 40 #define lovel_1 40 #define tempo_procura 900L #define threshold 100 ///////////////////////////////// //////////RECONHECE COR////////// /* Configuracao fisica dos pinos SPI +5V |X|X| GND bit 2 |X|X| bit 5 bit 3 |X|X| bit 4 N.C. |X|X| N.C. +5V |X|X| GND AZUL |X|X| BRANCO ROXO |X|X| CINZA N.C. |X|X| N.C. bits referentes ao endereco 0x1008 */ void liga_led(int n) { int mask1, mask2; switch(n) { //VERMELHO case 0: { mask1 = 0x04; bit_clear(0x1008, 0x08); bit_clear(0x1008, 0x10); bit_clear(0x1008, 0x20); }break; //AZUL case 1: { mask1 = 0x10; bit_clear(0x1008, 0x04); bit_clear(0x1008, 0x08); bit_clear(0x1008, 0x20); }break; //VERDES case 2: { mask1 = 0x20; mask2 = 0x08; bit_clear(0x1008, 0x04); bit_clear(0x1008, 0x10); bit_set(0x1008, mask2); }break; default: return; } bit_set(0x1008, mask1); } void desliga_led() { bit_clear(0x1008, 0x04); bit_clear(0x1008, 0x08); bit_clear(0x1008, 0x10); bit_clear(0x1008, 0x20); } void reconhece_cor(int vermelho, int azul, int verde) { //PRETO: TODOS > 45 if (vermelho > 45 && azul > 45 && verde > 45) { printf("PRETO\n"); return; } //MARROM: MENOR VERMELHO MAS MAIOR QUE 25 if (vermelho > 25 && azul > vermelho && verde > vermelho) { printf("MARROM\n"); return; } //VERMELHO: MENOR VERMELHO < 25 else if (vermelho < 25 && azul > vermelho && verde > vermelho && verde > 25) { printf("VERMELHO\n"); return; } //AMARELO: VERMELHO MENOR E VERDE MENOR QUE 25 else if (azul > vermelho && verde > vermelho && verde < 25) { printf("AMARELO\n"); return; } //VERDE: MENOR VERDE else if (vermelho > verde && azul > verde) { printf("VERDE\n"); return; } //AZUL: MENOR AZUL else if (vermelho > azul && verde > azul) { printf("AZUL\n"); return; } else { printf("NAO RECONHECI\n"); return; } } void reconhecimento_cor() { int i = 0; int cores[3]; // Converte os pinos SPI em saidas poke(0x1009, 0x3c); beep(); printf("Reconhecimento de Cores: START\n"); while(!start_button()); start_press(); while(1) { if (start_button()){ for(i = 0; i < 3; i++) { liga_led(i); sleep(0.15); cores[i] = analog(6); sleep(0.15); desliga_led(); } reconhece_cor(cores[0], cores[1], cores[2]); } } } ///////////////////////////////// ///////////SEGUE LINHA/////////// void segue_linha() { int s2; // Direita int s3; // Esquerda int ultima_linha = 1; // Direita = 1, Esquerda = -1 beep(); printf("Segue Linha START\n"); while(!start_button()); start_press(); printf("Procurando a linha preta.\n"); while(!stop_button()) { s2 = analog(2); s3 = analog(3); // Totalmente fora da linha if (s2 < threshold && s3 < threshold) { printf("Procurando Curva\n"); // Procura na ultima linha motor(0, -ultima_linha*hivel_0); motor(1, ultima_linha*hivel_1); msleep(tempo_procura); motor(0, 0); motor(1, 0); s2 = analog(2); s3 = analog(3); if (s2 >= threshold || s3 >= threshold) { // Achou a curva printf("Achei a curva\n"); } else { // Procura no sentido contrario motor(0, ultima_linha*hivel_0); motor(1, -ultima_linha*hivel_1); msleep(2L*tempo_procura); motor(0, 0); motor(1, 0); s2 = analog(2); s3 = analog(3); if (s2 >= threshold || s3 >= threshold) { // Achou a curva printf("Achei a curva\n"); ultima_linha = -ultima_linha; } else { printf("Estou Perdido!\n"); while(!start_button() && !stop_button()); } } } // Desviou para a esquerda else if (s2 < threshold && s3 >= threshold) { printf("Corrigindo...\n"); ultima_linha = -1; motor(0, hivel_0); motor(1, lovel_1); } // Desviou para a direita else if (s2 >= threshold && s3 < threshold) { printf("Corrigindo...\n"); ultima_linha = 1; motor(0, lovel_0); motor(1, hivel_1); } // Continua na linha else { printf("Seguindo a linha\n"); motor(0, hivel_0); motor(1, hivel_1); } } } ///////////////////////////////// int main() { int modo = -1; printf ("T-800 TP1 Aperte START \n"); start_press(); while(1) { if (knob() > 128) { if (modo != 0) { printf("Segue Linha\n"); } modo = 0; if (start_button()) { segue_linha(); modo = -1; } } else { if (modo != 1) { printf("Reconhece Cor\n"); } modo = 1; if (start_button()) { reconhecimento_cor(); modo = -1; } } } }
Resultados
Trabalho Prático 3
Objetivos
- Construção de sensores ópticos ativos, para identificação de presença/cores de blocos.
- Construção de um sensor diferencial, para localização por meio de fontes de luz polarizada.
- Construção de shaft-encoders, para construção de um controlador PD que auxilia na precisão dos movimentos.
Ideias Iniciais
Escolha dos sensores:
Para fazer o reconhecimento da presença de blocos, optamos por utilizar um conjunto de sensores, constituídos por um sensor de reconhecimento de cores (utilizado no TP2) e um sensor infravermelho, que nos permite identificar quando um bloco/parede está perto o suficiente para a leitura do sensor de cores.
(Foto do sensor de cores)
Já para o sensor diferencial, foi utilizado um par de sensores LDR, recobertos com filtros de luz polarizada, tais filtros estão a uma diferença de 90º em relação ao outro.
(Foto do sensor diferencial)
Para os shaft-encoders, utilizamos sensores do tipo break-beam e um aro com furos do conjunto de peças do LEGO.
(Foto do shaft-encoder)
Segue Luz Polarizada
Código
(Adicionar todos os códigos)
Resultados
Prévia e Competição
Objetivos
Para participar da competição Robô Marte o robô deve ser capaz de:
- Ser calibrado em 60 segundos ou menos;
- Entrar em modo de espera após a calibração;
- Após ser posicionado manualmente sobre a luz de partida com orientação arbitrária, se orientar segundo a luz polarizada;
- Iniciar o cumprimento da tarefa após acesa a luz de início;
- Não queimar a largada;
- Orientar-se autonomamente no campo (Identificar linhas pretas e luz polarizada);
- Identificar a presença, a cor e coletar blocos;
- Levar o bloco até a base;
- (Preferencialmente)Subir e descer uma rampa de 5 cm de altura e 18 graus de inclinação;
- Desligar todos os atuadores ao término de 60 segundos.
A competição simulará uma missão à Marte onde os robôs devem coletar amostras e levá-las à área de análise. As pedras marcianas serão representadas por esferas e cubos de isopor coloridos espalhados pelo campo, os robôs se enfrentarão par a par e aquele que marcar mais pontos na partida será o vencedor e receberá os pontos equivalentes. Ao final dos confrontos, os dois robôs que tiverem marcado mais pontos se enfrentarão pelo título de campeão. A pontuação da partida é baseada no número de amostrar coletadas e o tipo de cada uma delas, cada tipo tem um valor de pontos associados (podendo ser negativo). As regras podem ser vistas com detalhe em: http://www.verlab.dcc.ufmg.br/cursos/introrobotica/2012-2/competicao
Prévia
O robô já estava preparado para seguir linha, identificar a cor dos blocos (TP2), se orientar a partir da luz polarizada e controlar seus movimentos a partir de um shaft encoder (TP3), agora era necessário integrar essas habilidades de forma que ele pudesse completar sua missão: coletar as pedras marcianas no campo de competição.
O primeiro passo foi fazer com que ele entrasse em modo de espera, começasse a atividade quando a luz de partida fosse acionada e parasse sozinho depois de 60 segundo. Para isso utilizamos o par de sensores infra vermelho que ele já possuía para seguir a linha, a partir da leitura deles esta tarefa pode ser feita sem muita dificuldade.
Para a temporização utilizamos um programa com alta prioridade executado em paralelo que a todo tempo verifica o retorno da função mseconds(), quando os 60s são atingidos este programa para os motores.
Outro desafio era desenvolver um método para capturar os blocos, uma garra controlada por um terceiro motor foi acoplada ao robô. A posição da garra era controlada por uma chave de fim de curso.
O robô estão aguardava a largada, depois disso seu comportamento, em alto nível, pode ser descrito pela seguinte FSM:
Sendo que a qualquer momento se o tempo de execução atingir 60s ele para imediatamente (esta informação foi omitida da imagem apenas para que esta não ficasse sobrecarregada).
O maior problema encontrado foi a rampa. Nosso robô tinha a estrutura muito rebaixada e por isso não conseguia executar a tarefa. Modificamos a estrutura, colocamos rodas maiores e afastamos a distância entre elas e seu ponto de apoio, desta forma o robô foi capaz de subir a rampa:
http://www.youtube.com/watch?v=3ZvS94AgWC0
Mas, devido à nova estrutura, ele não era mais capaz de executar as outras tarefas básicas como antes. Analisamos a situação e, principalmente devido ao prazo, decidimos voltar com a estrutura antiga do robô e desistir de subir a rampa para a competição.
Competição
O robô já estava apto a participar da competição, mas um importante ajuste ainda precisava ser feito para melhorar consideravelmente sua performance: a adição de bumpers. O robô detectava a presença da parede através do seu sensor IR detector de blocos, mas isso era ineficiente uma vez que ele demorava um tempo considerável para reagir, os motores eram um pouco forçados até que ele ficasse na posição ideal para a detecção e isso não era o suficiente para que a rampa fosse detectada. Um par de bumpers foi adicionado à frente do robô de forma que fosse possível detectar tanto as paredes quanto a rampa.
Mesmo assim ainda havia um problema, o robô capturava o bloco e seguia de frente em direção à base, mas, como nesta hora sua garra estava abaixada os bumpers eram inúteis. Para resolver este problema outro par de bumpers foi adicionado às costas do robô e ele passou a retornar para a base de costas.
Para otimizar esta nova estratégia o sensor de luz polarizada foi transferido para as costas do robô, otimizando a largada e a volta.
O comportamento do robô pode ser descrito pela FSM:
A função orienta_luz é uma adaptação da função segue_luz para que o robô possa fazer a largada. O robô se orienta procurando sua luz, como o sensor agora está nas suas costas ele fica posicionado de frente para a rampa e para o campo adversário. Ele então vira para um lado que é definido por uma variável que começa aleatória e depois vai ser alternando entre esquerda e direita, e então segue reto.
Esta variável foi introduzida para evitar que o robô siga em direção à rampa e que ele fique preso num determinado ponto do percurso. A ação desencadeada pelo acionamento dos bumpers depende desta variável e foi planejada para evitar que o robô fique preso.
O robô consegue então realizar bem as tarefas de seguir linha, se orientar e coletar os blocos desejados. Uma pequena demonstração pode ser vista no vídeo:
http://www.youtube.com/watch?v=8jDPrb_3_QA
Dificuldades
A maior dificuldade encontrada, e que decidimos não resolver, foi a tarefa de subir a rampa. Seria necessária uma reconstrução, que chegou a ser feita, e uma total reformulação dos programas e estratégias já prontos e que funcionavam muito bem, o grupo decidiu que era melhor investir seu tempo fazendo com que o robô executasse muito bem e de maneira confiável as tarefas mais básicas pois acreditamos que assim ele teria grandes chances de ser bem sucedido na competição.
Mas, o fato de nosso robô não ser capaz de subir a rampa nos trouxe outro problema: evitá-la. Para isso tivemos que fazer com que os bumpers frontais fossem capazes de detectar tanto a parede quanto a rampa e esta tarefa não foi trivial. Esse problema foi resolvido com adaptações mecânicas.
Um problema que precisou ser resolvido com reformulação de software foi o que fazia com que ele ficasse preso em determinada parte do percurso. A variável que indica para que lado o robô deve virar foi suficiente para resolver este problema.
Outro problema de software foi que a quantidade de processos que estava sendo rodada ao mesmo tempo não foi suportada (o limite encontrado foi 4), então alguns processos precisaram ser integrados como o de checagem do temporizador e do botão de stop.
A dificuldade que não foi resolvida nem contornada foi a de capturar blocos presos à parede, como nesta situação a garra do robô fica presa ele não consegue capturar o bloco.
Projeto Final
A versão final do robô T-800 tem as seguintes características:
Sensores e Atuadores:
- Robô diferencial com um ponto de apoio e duas rodas acionadas por motores independentes
- Um terceiro motor para acionar a garra usada para capturar os blocos e bolas
- Uma chave de fim de curso para controlar a atuação nessa garra
- Dois sensores compostos por um emissor e um receptor infra vermelho utilizados para detectar a linha preta e a luz de início da partida
- Um terceiro sensor deste mesmo tipo utilizado para identificar a presença de objetos
- Um sensor de cor composto por um sensor de luz LDR e 4 leds (1 vermelho, 2 verdes e 1 azul), este LDR também é usado para auxiliar a detecção de objetos
- Um sensor diferencial de luz polarizada composto por 2 sensores de luz LDR cobertos por filtros polarizadores com uma defasagem de 90º
- Dois encoders, que são compostos por um emissor e um receptor infra vermelho, utilizados para realizar a contagem de giros das rodas
- Duas chaves utilizadas como bumpers frontais para evitar que ele bata nas paredes e suba a rampa
- Dois push-buttons utilizados como bumpers traseiros que tem o mesmo objetivo que os frontais mas para quando o robô está andando de costas
Processos:
- Um processo de altíssima prioridade que começa a funcionar quando a partida se inicia e verifica o temporizador, o botão de stop e o acionamento dos bumpers
- Um processo para a localização no campo utilizando as luzes polarizadas (acionado em pontos específicos da FSM)
- Um processo de prioridade baixa para seguir linha
- Um processo de identificação de blocos com prioridade alta