Tabela de conteúdos

Projeto Final

Introdução

O trabalho do projeto final teve o objetivo de aprimorar e corrigir problemas no robô com base no Trabalho Prático 3, de forma que ele fosse capaz de executar as seguintes tarefas na Competição de Robôs:

  1. Ser capaz de ser calibrado em 60 segundos ou menos;
  2. Entrar em modo de espera após a calibração;
  3. Não queimar a largada;
  4. Iniciar o cumprimento da tarefa após acesa a luz de início;
  5. Ser capaz de se orientar segundo a luz polarizada;
  6. Navegar autonomamente pelo campo;
  7. Coletar os blocos/esferas que se encontram dispersos no campo;
  8. Carregar o bloco/esfera até a base (ou mantê-lo preso ao robô);
  9. Desligar todos os atuadores ao término de 60 segundos.

O robô foi capaz de executar todas as tarefas propostas.

O objetivo era ser capaz de participar da competição, com o desenho de campo abaixo:

Construímos o robô com a estratégia de pegar blocos não pretos e levar para a base.

Estrutura física

Houve mudanças significativas na estrutura física para acomodar melhor o kit Arduino dentro do robô, pois a estrutura anterior se demonstrava frágil nesse quesito. Fizemos uma montagem ao redor das rodas para ajudar na sustentação e proteção lateral robô.

Uma estrutura estática em forma de “U” foi construída para que fosse possível captar os blocos espalhados na mesa da competição. Além disso, nas corridas de teste que fizemos, notamos que blocos se encaixavam nas laterais do robô e eram arrastados de forma não intencional, então tivemos que montar estruturas dos dois lados para evitar esse problema.

Estratégia

A estratégia do robô consistia de uma máquina de estados, com a seguinte lógica de operação :

  1. Esperar a luz de partida
  2. Se localizar, girando em 360 graus a procura da luz polarizada
  3. Girar em direção à luz polarizada
  4. Girar 180 graus, se posicionando para andar em direção aos blocos.
  5. Andar reto por um período de tempo, fazendo com que o robô ignore a primeira linha preta a sua frente. O objetivo aqui é ganhar tempo, visto que seguir todas as linhas tomaria muito tempo.
  6. Ativar o seguidor de linha e a detecção de objetos.
  7. Caso encontre um bloco preto, o robô realizará uma curva para direita, desviando do bloco, e em seguida retornará para a linha.
  8. Caso encontre um bloco não preto, o robô:
    1. Procura a luz polarizada
    2. Gira em sua direção.
    3. Anda por um período de tempo(levando o bloco até a base).
    4. Recua (deixando teoricamente o bloco na base).
    5. Gira em 180 graus
    6. Anda pra frente (na teoria evitando novamente seguir a linha preta próxima ao local de partida).
    7. Ativa o seguidor de linhas e a detecção de blocos para procurar um segundo objeto, retornando ao estado 6.

Algoritmo

Máquina de Estados

Como citado na sessão anterior, a máquina de estados era a base da lógica do robô. Ela possuía uma função principal, que chamava as funções de cada estados, por meio de um switch case. Dentro de cada estado são realizadas as lógicas e chamadas funções referentes a ações mais complexas.

int Localiza() {
	Tarefas::AlinhaComLampada();
	delay(1000);
	return GIRA180;
}
 
int Gira180() {
	gira_sentido_antihorario(12);
	return SAIDABASE;
}
 
int SaiDaBase() {
	set_speed(DEFAULT_LEFT_PWM_SPEED*1.2, DEFAULT_RIGHT_PWM_SPEED*1.2);
	anda(35);
	return SEGUELINHA;
}
 
int SegueLinha() {
	lcd.begin(16, 2);
	lcd.setCursor(8, 1);
	if(DetectaObjeto()) {
		lcd.print("DETECTEI");
		para();
		return OLHACOR;
	}
	else {
		Tarefas::SegueLinha();		 
	}
	delay(10);
	return SEGUELINHA;
}
 
int OlhaCor() {
  	delay(100);
	char cor = DetectaCor();
  	delay(10);
	if(cor == black ) {
		return RECUA; 
	}
	else {
		return GIRABASE;
	}
}
 
int GiraBase() {
	Tarefas::AlinhaComLampada();
	return RETORNABASE;
}
 
int RetornaBase() {
	anda(60);
	return RECUABASE;
}
 
int RecuaBase() {
	anda_re(10);
	return GIRA1802;
}
 
int Gira1802() {
	gira_sentido_antihorario(12);
	return SAIDABASE2;
}
 
int SaiDaBase2() {
	anda(20);
	return SEGUELINHA;
}
int Recua() {
	anda_re(10);
	return GIRA60;
}
 
int Gira60() {
	gira_sentido_horario(2);
	return ANDARETO;
}
 
int GiraMenos60() {
	gira_sentido_antihorario(4);
	return SEGUELINHA;
}
 
int AndaReto() {
	set_speed(DEFAULT_LEFT_PWM_SPEED, DEFAULT_RIGHT_PWM_SPEED);
	anda(12);
	return GIRAMENOS60;
}
 
int MaquinaDeEstados(int estadoAtual) {
	int proximoEstado;
	switch(estadoAtual) {
		case LOCALIZA:
			proximoEstado = Localiza();
			break; 
		case GIRA180:
			proximoEstado = Gira180();
			break;
		case SEGUELINHA:
			proximoEstado = SegueLinha();
			break;
		case GIRABASE:
			proximoEstado = GiraBase();
			break; 
		case RETORNABASE:
			proximoEstado = RetornaBase();
			break;
		case RECUABASE:
			proximoEstado = RecuaBase();
			break;
		case RECUA:
			proximoEstado = Recua();
			break; 
		case GIRA60:
			proximoEstado = Gira60();
			break;
		case ANDARETO:
			proximoEstado = AndaReto();
			break; 
		case GIRAMENOS60:
			proximoEstado = GiraMenos60();
			break;	
		case OLHACOR:
			proximoEstado = OlhaCor();
			break;			
		case SAIDABASE:
			proximoEstado = SaiDaBase();
			break; 
		case SAIDABASE2:
			proximoEstado = SaiDaBase2();
			break;
		case GIRA1802:
			proximoEstado = Gira1802();
			break;
	}
	return proximoEstado;
}

Desafios

Os maiores desafios nesse ponto foram fazer o robô detectar com precisão os blocos e ajustar os giros quando ele estava se localizando, saindo da base e seguindo a linha. Na detecção de blocos, o bloco preto foi um desafio a parte, pois sua cor dificulta a detecção. Esta detecção falhou na competição. Tivemos problemas com os giros também devido à falha em cima da hora da apresentação de nossos encoders e a consequente necessidade de adaptar algumas funções para executarem com base em tempo e não mais na medição das rotações das rodas.

Registro AudioVisual