Grupo 1 - Skynet

Skynet T-800

Integrantes

O Robô: T-800

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:

Figura 1

Reforçando um pouco a estrutura: Figura 2

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. Figura 3 Figura 4

Características do robô:
Ao final da montagem, obtivemos um robô com as seguintes características:

  1. Estrutura rígida e firme, utilizando travamentos com peças LEGO;
  2. 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;
  3. Sistemas de redução baseados em roscas sem fim;
  4. 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º

Desvio padrão = 1.6

Gráfico 1

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

Montagem Final

Desenho Apresentado

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:

Sensor IR 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.

Montagem dos sensores IR


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:

Máquina de estados finitos de alto nível

O robô lê os valores dos sensores IR e com isso pode determinar se:

  1. Não houve desvio (direita = esquerda = escuro);
  2. Houve um desvio para a direita (direita = claro, esquerda = escuro);
  3. Houve um desvio para a esquerda (esquerda = claro, direita = escuro);
  4. 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
Códigos
cursos/introrobotica/2012-2/grupo01/index.txt · Última modificação: 2012/12/18 17:37 por gabrieldpasa