Um algoritmo para a solução de labirintos com uso de um
Transcrição
Um algoritmo para a solução de labirintos com uso de um
INSTITUTO FEDERAL DO ESPÍRITO SANTO PÓS GRADUAÇÃO LATO SENSU EM ENGENHARIA ELÉTRICA COM ÊNFASE EM SISTEMAS INTELIGENTES APLICADOS À AUTOMAÇÃO ANDERSON SACHETTO ROSA UM ALGORITMO PARA A SOLUÇÃO DE LABIRINTOS COM USO DE UM ROBÔ MÓVEL VITÓRIA 2015 ANDERSON SACHETTO ROSA UM ALGORITMO PARA A SOLUÇÃO DE LABIRINTOS COM USO DE UM ROBÔ MÓVEL Trabalho apresentado ao curso de Pós-Graduação Lato Sensu em Engenharia Elétrica com Ênfase em Sistemas Inteligentes Aplicados à Automação do Instituto Federal do Espírito Santo como requisito parcial para obtenção do certificado de Especialista em Sistemas Inteligentes Aplicados à Automação. Orientador: Prof. Dr. Luis Eduardo Martins de Lima VITÓRIA 2015 (Biblioteca Nilo Peçanha do Instituto Federal do Espírito Santo) R788a Rosa, Anderson Sachetto. Um algoritmo para a solução de labirintos com uso de um robô móvel / Anderson Sachetto Rosa. – 2015. 49 f. : il. ; 30 cm Orientador: Luis Eduardo Martins de Lima. Monografia (especialização) – Instituto Federal do Espírito Santo, Coordenadoria de Pós-Graduação em Engenharia Elétrica, Curso PósGraduação Lato Sensu em Engenharia Elétrica com Ênfase em Sistemas Inteligentes Aplicados à Automação, 2015. 1. Engenharia elétrica. 2. Sistemas de controle inteligente. 3. Robótica. 4. Algorítmos computacionais. 5. Labirintos. I. Lima, Luis Eduardo Martins de. II. Instituto Federal do Espírito Santo. III. Título. CDD 21 – 621.3 AGRADECIMENTOS Agradeço a Deus, pelas oportunidades proporcionadas a mim. E aos meus pais e amigos pelo incentivo e paciência. RESUMO O desenvolvimento de sistemas inteligentes autônomos tem sido um campo de inúmeros estudos há vários anos. Atualmente, a robótica móvel assitiva tem se caracterizado como um ramo dos sistemas autônomos de grande apelo social, nos que diz respeito ao suporte dado a pessoas com deficiência física. Os robôs capazes de se locomoverem de forma autônoma por ambientes, podem auxiliar deficientes visuais a se locomoverem dentro de suas residências, por exemplo. A resolução de labirintos com o uso de robôs móveis de forma autônoma, viabiliza a elaboração de técnicas/ algoritmos que podem vir a ser extrapolados para ambientes físicos reais. Este trabalho tem por objetivo desenvolver um algoritmo, embarcado em uma plataforma robótica, capaz de explorar um labirinto desconhecido em busca de um ponto demarcado como destino, em busca de um caminho que o leve diretamente de um ponto de origem a outro de destino. Ao encontrar o ponto de destino, o robô retorna ao ponto de partida executando o trajeto que o leva diretamente de volta, para então navegar novamente rumo ao destino, executando o trajeto que o leva diretamente ao destino. Estas constituem as três etapas do algoritmo proposto, denominadas exploração, volta a origem e navegação. Palavras-chaves: Robótica móvel. Resolução de Labirintos. Algoritmo. Micromouse. LISTA DE FIGURAS Figura 1 - Exemplo de labirinto tradicional.............................................................................. 13 Figura 2 – Exemplo de labirinto utilizado. ............................................................................... 14 Figura 3 - Estrutura de hardware utilizada. .............................................................................. 14 Figura 4 - Robô Zumo. a) Vista em perspectiva; b) Principais módulos. ................................ 15 Figura 5 - Barra de sensores IR. ............................................................................................... 16 Figura 6 - Modelo de encoder utilizado. .................................................................................. 17 Figura 7 - Plataforma de desenvolvimento Arduino Mega 2560. ............................................ 17 Figura 8 - Bifurcações possíveis de serem encontradas nos labirintos..................................... 19 Figura 9 - Percepção e diferenciação de bifurcações. a) e c) Momento em que uma bifurcação é percebida; b) Leitura que caracteriza a bifurcação percebida em a); d) Leitura que caracteriza a bifurcação percebida em c). ................................................................ 20 Figura 10 - Comportamento do robô para uma dada situação. a) Robô se aproximando da bifurcação; b) Identifica-se o sentido e segue por ele; c) Não há caminhos para prosseguir nesta direção; d) Segue por um novo caminho. ..................................... 21 Figura 11 - Código em "C" que define a estrutura Crossing. ................................................... 22 Figura 12 - Inserção de uma nova bifurcação à lista. ............................................................... 23 Figura 13 - Etapa de exploração. Eliminando bifurcações que não contribuem para a resolução. .................................................................................................................................. 24 Figura 14 - Fluxograma que representa o funcionamento do algoritmo na fase de exploração. .................................................................................................................................. 25 Figura 15 – Exemplo de composição da lista de bifurcações. .................................................. 27 Figura 16 - Exemplo de trajeto oval, utilizado na primeira etapa de testes. ............................. 29 Figura 17 - Módulo Bluetooth HC-06 ...................................................................................... 30 Figura 18 - Labirinto de teste do sistema de coordenadas. ....................................................... 31 Figura 19 – Trajetos resultantes do labirinto de testes. ............................................................ 32 Figura 20 - Trajetos resultantes do labirinto de validação........................................................ 34 Figura 21 - Problema referente a labirintos circulares. ............................................................ 35 LISTA DE SIGLAS IEEE – Institute of Electrical and Electronics Engineers (Instituto de Engenheiros Eletricistas e Eletrônicos); IR – Infra Red (Infravermelho); PC - Personal Computer (Computador Pessoal); PCI – Placa de Circuito Impresso; PWM – Pulse Width Modulation (Modulação por Largura de Pulso); SPD – Seguidor de Parede à Direita; SPE – Seguidor de Parede à Esquerda. SUMÁRIO 1 INTRODUÇÃO .............................................................................................................. 9 1.1 TRABALHOS RELACIONADOS ................................................................................ 11 2 MATERIAIS ................................................................................................................. 13 3 MÉTODOS .................................................................................................................... 19 3.1 ETAPA DE EXPLORAÇÃO ......................................................................................... 20 3.2 ETAPAS “VOLTA À ORIGEM” E NAVEGAÇÃO DO LABIRINTO ...................... 26 4 TESTES E RESULTADOS ......................................................................................... 29 4.1 TESTES DE DESENVOLVIMENTO ........................................................................... 29 4.2 TESTES E VALIDAÇÃO DO ALGORITMO .............................................................. 32 5 CONCLUSÃO............................................................................................................... 36 REFERÊNCIAS ............................................................................................................ 38 APÊNDICE A – Algoritmo desenvolvido ...................................................................... 39 9 1 INTRODUÇÃO Investigações acerca de métodos para resolução de labirintos com o uso de robôs móveis vêm sendo feitas a mais de 30 anos (MISHRA e BANDE, 2008), mas sua importância para a robótica, e em particular a robótica móvel, continua muito presente nos dias atuais, uma vez que se busca cada vez mais o desenvolvimento de sistemas autônomos inteligentes capazes de interagir com o “mundo real”, e desenvolver tarefas não previstas, algo que simule o comportamento humano. Esta “inteligência” projetada sobre os robôs móveis, e proporcionada pelas novas tecnologias disponíveis no mercado (sensores, microcontroladores, atuadores de precisão, drivers de potência miniaturizados), tem exercido papel fundamental no desenvolvimento de soluções de muita relevância para a sociedade. Por exemplo, pode-se citar a redução das limitações impostas às pessoas portadoras de algum tipo de deficiência física. Pessoas com dificuldades motoras e/ou visuais têm conseguido com a robótica móvel assistiva o auxílio para a realização de tarefas como, por exemplo, andar por pequenos trajetos dentro de suas residências. Pessoas com dificuldades motoras podem precisar de auxílio para a própria locomoção, já pessoas com deficiência visual necessitam de sistemas que lhes proporcionem a visão do ambiente em que se encontram. (MOREIRA, VASCONCELOS e FILHO, 2010). Neste contexto, robôs móveis que tenham a capacidade de guiar o indivíduo por entre obstáculos presentes no percurso são de grande relevância no auxílio às atividades cotidianas deste indivíduo, e consequentemente contribui para o aumento do grau de autonomia diária destas pessoas. A navegação autônoma de robôs móveis, em ambientes com configuração dinâmica e desconhecida, ou seja, ambientes não estruturados, é tratada na literatura como uma caracterização do problema de SLAM (Simultaneous Localization and Mapping - Localização e Mapeamento Simultâneos) (CHANG, LEE, et al., 2007). Neste contexto, os robôs percorrem o ambiente executando um processo de auto-localização e mapeamento do ambiente com o uso dos sensores neles embarcados e algoritmos para a construção topológica do ambiente. Após o mapeamento, os robôs tornam-se capazes de locomoverem-se pelo ambiente realizando trajetórias de interesse, livres de colisões. A estruturação de um ambiente, com sinalização sob a forma de um labirinto, facilita o sensoriamento exigido para que o robô possa “perceber” o ambiente, permitindo assim que os esforços no desenvolvimento da pesquisa estejam focados na implantação da “inteligência” do robô, representada pelos algoritmos de solução dos labirintos. 10 Ao longo dos anos, diversas competições de robótica (Micromouse, Robot Soccer) têm proporcionado a estudantes e pesquisadores a oportunidade de apresentarem seus trabalhos de pesquisa em grandes fóruns e com grande cobertura da mídia (BRAUNL, 1999). Desde 1986 o IEEE (Institute of Electrical and Electronics Engineers – Instituto de Engenheiros Eletricistas e Eletrônicos) formula um conjunto de regras para competições de robóticas, que envolvem o problema de resolução de labirintos por robôs móveis. Estas competições têm também a função de estimular nos participantes a criatividade de cada um, proporcionando o aprendizado no trabalho em equipe. Os projetos desenvolvidos para estas competições oferecem aos participantes o desafio de trabalhar em problemas com solução em aberto, complementando o aprendizado da teoria convencional acadêmica (MISHRA e BANDE, 2008). Robôs de pequeno porte capazes de locomoverem-se no interior de labirintos, de um ponto de partida até outro demarcado com a chegada, são conhecidos como Micromouses. Estes robôs utilizam sistemas de sensoriamento e controle embarcados, e devem ser dotados de “inteligência” que os possibilitem realizar esta tarefa com o menor custo possível. Onde o custo pode estar vinculado ao tempo gasto na etapa de mapeamento, quantidade de movimentos, etc (CAI et al., 2010). Os algoritmos presentes na literatura atual, e que apresentam os melhores resultados na resolução de labirintos, necessitam de alguma informação prévia a respeito dos labirintos (CAI, HUO, et al., 2010). Quando são extrapolados os limites definidos pelos labirintos utilizados nestas competições, e se passa a observar este problema pela ótica do mundo real, não se pode garantir a passagem de informações previas aos robôs, uma vez que a cena na qual ele será inserido tende a ser dinâmica. Neste trabalho é apresentado um estudo de análise e adaptação de algoritmos para a resolução de labirintos aplicados ao controle de locomoção de um robô móvel. Este trabalho tem por objetivo desenvolver um algoritmo para solução de labirintos de modo que não haja a necessidade de conhecimento prévio das dimensões do labirinto onde o robô estiver inserido, e de forma que o robô não se perca em loops que o impossibilitem de encontrar o caminho até o fim do labirinto. 11 1.1 TRABALHOS RELACIONADOS Em busca da melhor forma de se obter o mapeamento de labirintos com o uso de robôs, Mishra and Bande, 2008 discorrem acerca de três algoritmos utilizados na etapa de mapeamento. Os métodos mais simples levam o robô a seguir sempre por uma parede que esteja mais a sua esquerda ou à direita, estes algoritmos são chamados Left Wall Follower (Seguidor de Parede à Esquerda – SPE) e Right Wall Follower (Seguidor de Parede à Direita - SPD), eles são ditos como "ausentes de inteligência", uma vez que não se sabe a posição e direção do robô a cada instante. Outra forma é utilizar uma variação do algoritmo de Dijkstra (Skiena, 1990), para o qual faz-se a identificação dos cruzamentos presentes no caminho para a resolução do labirinto e computa o custo necessário para a locomoção da origem ao destino, com isso pode-se escolher o caminho de menor custo para a solução do labirinto (Mishra and Bande, 2008). Como desvantagem desta solução há a necessidade da locomoção por todo o labirinto, para que todos os cruzamentos possíveis sejam identificados para que se possa definir o caminho de menor custo. A terceira proposta de solução para labirintos, considerada como sendo a melhor dentre as já citadas (Mishra and Bande, 2008), é o Flood Fill Algorithm. Neste método o labirinto tem suas células divididas e enumeradas de acordo com sua distância até a célula destino, com o conhecimento que é adquirido pelo robô na sua navegação ele consegue identificar qual e o número da célula em questão, de forma a evitar navegar por rotas que o leve a células com uma numeração crescente. Ao considerar o tamanho padrão dos labirintos, (Cai et al., 2010) faz a divisão do labirinto em 12 partes ao redor do ponto de chegada, localizado no centro do labirinto. A partir de então, técnicas de locomoção distintas são utilizas pelo robô a medida que sua posição muda de uma partição para a outra. A divisão reduz a possibilidade do afastamento do robô na medida em que se aproxima do ponto de chegada, mas, limita sua utilização a labirintos que tenham suas dimensões conhecidas, assim como apresentado por (Mishra and Bande, 2008). Diversos hardwares de robôs móveis são utilizados no desenvolvimento de soluções para labirintos. Hualong et al., 2011 propõe uma arquitetura composta por cinco elementos principais, a citar: fonte de energia, unidade de detecção de distância, unidade de controle de movimento, unidade de conversão de sinal e uma central de controle. O teste do hardware desenvolvido é feito com base nos algoritmos SPE e SPD, primeiro o robô percorre o labirinto utilizando o SPE e retorna para a origem. Logo após o robô percorre novamente, desta vez 12 utilizando o SPD, e então retorna novamente até a origem, então é feita a comparação dos percursos feitos em busca do menor, o qual será executado como caminho ótimo. Cooperative Labyrinth Discovery (Descoberta Cooperativa de Labirinto) (Rahnama et al., 2013), onde dois ou mais robôs são postos a mapear de forma independente um mesmo labirinto, compartilhando entre si as informações adquiridas individualmente. 13 2 MATERIAIS Tipicamente os labirintos nos quais os robôs são inseridos, são formados por espaços vazios por onde o robô é capaz de navegar - os caminhos - e barreiras intransponíveis, que contornam os caminhos ditando os trajetos que podem ser seguidos pelo robô, Figura 1. Nestes casos, o sistema de sensoriamento do robô deve ser capaz de perceber obstáculos ao seu redor, mensurando as distâncias entre o robô e estes obstáculos, tipicamente são utilizados sensores ultrassônicos ou sensores de reflexão de infravermelho (HUALONG, YONGHONG e HONGQI, 2011). Figura 1 - Exemplo de labirinto tradicional. Fonte: (MISHRA e BANDE, 2008) Para facilitar o desenvolvimento do sistema de sensoriamento do robô neste trabalho, optou-se pelo uso de um labirinto que não contivesse barreiras físicas, e sim trajetos demarcados na superfície de locomoção, Figura 2. 14 Figura 2 – Exemplo de labirinto utilizado. Fonte: Elaborado pelo autor, 2014. A estrutura de hardware utilizada para que o robô possa interagir com o ambiente, é dividida em três partes principais, o conjunto de sensores, o controlador embarcado na plataforma robótica e os atuadores Figura 3. O conjunto de sensores é formado por uma matriz de sensores IR, capaz de identificar os trajetos do labirinto, e um par de encoders utilizados medir a distância percorrida pelo robô. O controlador embarcado é composto por um microcontrolador capaz de armazenar o algoritmo desenvolvido. Os atuadores são os próprios motores da plataforma robótica utilizada. Figura 3 - Estrutura de hardware utilizada. Fonte: Elaborado pelo autor, 2014. 15 Assim como exposto por Hualong et al., 2011, diversas plataformas de robôs móveis são utilizadas no desenvolvimento da tarefa de resolução de labirintos. A plataforma utilizada neste trabalho foi o robô de esteiras Zumo, Figura 4. Projetado para competições de sumô (PASSOLD, 2006), este robô utiliza o sistema de tração diferencial para acionamento das esteiras. O robô Zumo foi desenvolvido para trabalhar em compatibilidade com a placa microcontrolada Arduino Uno, ou outra placa compatível, sendo que, a possibilidade do uso de sensores infravermelhos em sua parte frontal, permite que ele identifique as linhas dos labirintos. Figura 4 - Robô Zumo. a) Vista em perspectiva; b) Principais módulos. Fonte: (POLOLU, 2014). Cada esteira do robô Zumo é movimentada por uma roda dentada acoplada a um motor, possibilitando assim a tração diferencial, o que possibilita a execução de curvas com grandes raios, ou giros em seu próprio eixo, dentre outras manobras. Com o uso de motores com caixa de redução 75:1 HP para se movimentar, pode atingir uma velocidade máxima de 60 cm/s (POLOLU, 2014). Esta plataforma robótica é composta por um shield para Arduino Uno Figura 4 (b), composta por um controlador duplo de motores, um acelerômetro com bússola triaxial, um buzzer (campainha) para emitir sons e um botão para o usuário, através do qual o usuário pode enviar comandos ao robô utilizado, por exemplo, para comando de start ao robô. Como hardware de controle, utiliza-se um Arduino Uno, ou outra plataforma compatível. O acelerômetro e a bússola podem ser utilizados no posicionamento do robô, bem como na detecção de impactos. Apesar de sofrer interferências dos motores, das pilhas e do PCI – (Placa 16 de Circuito Impresso) a bússola, se bem calibrada, pode ser utilizada como indicador de direção em diversos ambientes (POLOLU, 2014). As demarcações são identificadas como trajetos com o auxílio de um sistema de sensoriamento infravermelho, contendo oito pares emissor-receptor de IR (Infra Red – Infravermelho), Figura 5 (POLOLU, 2014). Quando o sensor passa pela superfície que representa o caminho a ser percorrido, linha preta, há o bloqueio do recebimento do reflexo do infravermelho por parte do receptor. A sequência de sensores bloqueados será avaliada pela lógica do sistema, possibilitando a identificação dos vários tipos de bifurcação considerados neste trabalho. Figura 5 - Barra de sensores IR. Fonte: (POLOLU, 2014). Além dos sensores utilizados na identificação do caminho, dois encoders são utilizados para medir a distância percorrida pelo robô no interior do labirinto. Cada encoder, Figura 6, é colocado em uma esteira do robô, a fim de coletar os pulsos produzidos pela roda dentada que causa a tração das esteiras no robô. 17 Figura 6 - Modelo de encoder utilizado. Fonte: (POLOLU, 2014) Para processar as informações oriundas dos sensores IR, encoders e executar todas as rotinas desenvolvidas para o algoritmo, foi utilizada a plataforma de desenvolvimento Arduino Mega 2560, Figura 7. Figura 7 - Plataforma de desenvolvimento Arduino Mega 2560. Fonte: (ARDUINO, 2014). As principais características do Arduino Mega são: Microcontrolador ATmega 2560 – 8 bits; Velocidade de Clock: 16 MHz; Tensão de operação: 5V; Tensões de entrada recomendadas: 7 – 12V; 18 54 entradas e saídas digitais, das quais 15 podem fornecer sinais de PWM (Pulse Width Modulation – Modulação por Largura de Pulso) como saída. 16 Entradas analógicas; 256KB de memória Flash; 8KB de memória SRAM; 4KB de memória EEPROM. 19 3 MÉTODOS O processo de resolução de labirintos, com uso de robôs móveis, exige o cumprimento de, pelo menos, duas etapas, exploração e navegação. A primeira exige que o robô passe pelo labirinto realizando a busca dos caminhos que o levem à saída do mesmo, nesta etapa o robô pode, ou não, passar por todos os caminhos possíveis, durante o desenvolvimento desta etapa o robô precisa obter e armazenar informações que o permita identificar de fato qual é o caminho que o levará à saída do labirinto. Na segunda etapa, o robô irá executar a navegação, com base nas informações coletadas durante a etapa de exploração. No algoritmo desenvolvido neste trabalho, o robô parte de um ponto de origem em busca de um ponto de destino, sem nenhuma informação a respeito do tamanho do labirinto (ambiente). Quando o ponto de destino é encontrado, o robô volta para o ponto de origem fazendo o menor caminho possível daqueles pelo qual ele passou na etapa de mapeamento. Então, para confirmar que ele aprendeu o caminho, ele o executa novamente, até chegar ao ponto de destino, onde ficará parado. As únicas informações do labirinto que são de conhecimento prévio do robô são os tipos de bifurcações que ele poderá encontrar durante sua exploração. A Figura 8 apresenta os tipos de bifurcações que podem ser encontradas pelo robô, e a forma geométrica utilizada para identificar o início e fim do labirinto. Estas bifurcações são baseadas nos modelos formulados pelo IEEE para suas competições (IEEE, 2013), que levam em consideração apenas bifurcações perpendiculares. Figura 8 - Bifurcações possíveis de serem encontradas nos labirintos. Fonte: Elaborado pelo autor, 2014. 20 A diferenciação entre as bifurcações apresentadas na Figura 8, é feita pelo algoritmo de acordo com as informações provenientes da barra de sensores IR, e é feita em dois estágios. No primeiro estágio, durante o seguimento da linha, o robô percebe que há uma bifurcação conforme ilustram as Figuras 8a e 8c, então ele seguirá em linha reta por uma distância que equivale à de metade do comprimento do robô, medida por meio dos encoders. Neste ponto será feita uma nova leitura, como ilustram as Figuras 8b e 8d, neste ponto o algoritmo será capaz de identificar o tipo de bifurcação, considerando as duas leituras. Figura 9 - Percepção e diferenciação de bifurcações. a) e c) Momento em que uma bifurcação é percebida; b) Leitura que caracteriza a bifurcação percebida em a); d) Leitura que caracteriza a bifurcação percebida em c). Fonte: Elaborado pelo autor, 2014. 3.1 ETAPA DE EXPLORAÇÃO Sempre que o robô iniciar a exploração do labirinto, ele deverá reconhecer e diferenciar cada uma das bifurcações mostradas na Figura 8, e será função do algoritmo implementado decidir por qual direção seguir. Este algoritmo foi desenvolvido de forma que possa ser escolhida a “preferência” do robô no momento da gravação do programa no microcontrolador. 21 Esta “preferência” será considerada sempre que ele chegar a uma das bifurcações apresentadas na Figura 8 (e) ou Figura 8 (f). Outra característica é que, sempre que o robô chegar a uma nova bifurcação seja ela (b), (c), (d) ou (g) da Figura 8, o algoritmo levará sempre o robô a seguir pela direção da bifurcação, e não a passar direto. Como mostra a Figura 10, na qual demonstrase o comportamento do robô para o caso da Figura 8 (c). Figura 10 - Comportamento do robô para uma dada situação. a) Robô se aproximando da bifurcação; b) Identifica-se o sentido e segue por ele; c) Não há caminhos para prosseguir nesta direção; d) Segue por um novo caminho. Fonte: Elaborado pelo autor, 2014. A partir no início da exploração, sempre que o robô chegar a uma nova bifurcação, esta será inserida em uma lista de bifurcações. Para o algoritmo, cada bifurcação é tratada como uma estrutura de dados denominada Crossing, composta pelos seguintes parâmetros: indice – Representa a posição de uma dada bifurcação na lista de bifurcações; dir_relativa – Representa a direção para a qual o robô virou em uma dada bifurcação, o valor menos um (-1) representa que o giro do robô foi para a esquerda, mais um (+1) representa que o giro do robô foi para a direita. Trata-se de direção relativa, uma vez que com ela não é possível identificar qual a orientação do robô perante o labirinto. dir_abs – Representa a direção absoluta do robô em relação ao labirinto. Assume-se que a direção de partida do robô seja o norte, durante a navegação, este parâmetro indicará qual a direção do robô em relação ao labirinto em uma dada bifurcação. As direções absolutas são codificadas da seguinte forma, Norte = 1, Leste = 2, Sul = 3 e Oeste = 4. 22 O algoritmo computa uma nova direção absoluta de acordo com a direção absoluta anterior e a direção relativa do giro efetuado para uma dada bifurcação; dir_abs_chegada – Sempre que o robô chegar a uma bifurcação, sendo ela uma nova bifurcação ou não, a direção absoluta atual do robô será armazenada neste parâmetro; custo – Representa o tamanho do percurso feito pelo robô durante o percurso pelo labirinto, é medido em número de pulsos do encoder. Neste valor não são computados os pulsos referentes aos giros feitos pelo robô sempre que precisam mudar de direção, uma vez que sua posição não muda; possibilidades – Para cada tipo de bifurcação existe um número de possibilidades de trajetos a serem seguidos, este parâmetro armazena quantos possíveis trajetos ainda restam para uma dada bifurcação; coordenadaX – Este valor representa a quantos pulsos na direção “x” (horizontal), uma dada bifurcação está do ponto de início do labirinto; coordenadaY – Assim como o parâmetro anterior, este valor armazena o número de pulsos na direção “y” (vertical), na qual dada bifurcação se encontra em relação ao ponto de início do labirinto. Na Figura 11 é apresentada a estrutura crossing definida em linguagem “C”. Figura 11 - Código em "C" que define a estrutura Crossing. Fonte: Elaborado pelo autor, 2014. 23 As listas encadeadas são estruturas flexíveis, pois, para cada elemento inserido na estrutura, um espaço é alocado para o seu armazenamento. Dessa forma, o espaço de memória utilizado será sempre compatível com a quantidade de elementos armazenados (VILLAS, FERREIRA, et al., 1993). A estrutura da lista é composta por uma sequência encadeada de elementos, geralmente denominados nós da lista. Os nós de uma lista simplesmente encadeada possuem dois campos: o dado armazenado e o ponteiro para o próximo elemento da lista, também conhecido como “link”, visto que é responsável por manter a ligação entre os nós (VILLAS, FERREIRA, et al., 1993). Diferentemente de um vetor, não se pode acessar diretamente os elementos da lista encadeada, pois eles não ocupam um espaço de memória contínuo. Portanto, é necessário percorrer todos os elementos da lista, sendo que o deslocamento se faz em apenas um sentido: do primeiro para o último elemento. O último elemento armazena um ponteiro inválido (NULL), sinalizando que não há um próximo elemento (RANGEL NETO, CERQUEIRA e CELES FILHO, 2004). As novas bifurcações são sempre inseridas na “cabeça” da lista. Deste modo, a última bifurcação pela qual o robô passou, sempre será a primeira da lista, Figura 12. Quando uma bifurcação não é nova, o robô já passou por ela, a estrutura crossing que a representa é atualizada com os novos dados. Figura 12 - Inserção de uma nova bifurcação à lista. Fonte: Elaborado pelo autor, 2014. À medida que a exploração ocorre, sempre que todas as possibilidades de uma dada bifurcação são extintas e, percebe-se que a mesma não contribui para a solução do labirinto, esta bifurcação 24 é removida da lista, de forma que apenas as bifurcações que levam o robô ao fim do labirinto, são mantidas na lista. Para o caso da Figura 13, o robô inicia sua navegação pela origem, situada à esquerda, ao chegar à bifurcação 2 ele irá seguir para a direção absoluta “sul” até a bifurcação 3. Nenhuma das direções presentes na bifurcação 3 levam o robô ao destino, então ele retornará para a bifurcação 2. Como foram exploradas todas as possibilidades para a bifurcação 3, e o robô voltou à bifurcação 2 através do mesmo trajeto pelo qual a deixou, o algoritmo irá eliminar a bifurcação 3 de sua lista de bifurcações. Este mesmo processo é válido para seguimentos de caminhos, como os da bifurcação 4. Se por ventura o robô, na etapa de exploração, seguir por um dos dois seguimentos que não o levam ao destino, o seguimento em questão será eliminado da lista. Figura 13 - Etapa de exploração. Eliminando bifurcações que não contribuem para a resolução. Fonte: Elaborado pelo autor, 2014. Pode-se representar o fluxo do processamento executado na etapa de exploração do labirinto, em forma de fluxograma, e este é apresentado na Figura 14. 25 Figura 14 - Fluxograma que representa o funcionamento do algoritmo na fase de exploração. Fonte: Elaborado pelo autor, 2014. Ao iniciar a etapa de exploração o robô considera sua orientação atual como sendo a direção “norte” do seu sistema de coordenadas, daí por diante, sempre que ele se deparar com uma bifurcação, ele deverá armazenar sua orientação atual no parâmetro dir_abs_chegada da estrutura crossing que representa tal bifurcação. Em seguida, é efetuado o giro para a direção pretendida, para então calcular e armazenar a nova direção absoluta no parâmetro dir_abs, da mesma estrutura crossing. 26 3.2 ETAPAS “VOLTA À ORIGEM” E NAVEGAÇÃO DO LABIRINTO Para efetuar a etapa de “volta à origem” o algoritmo se baseia no parâmetro dir_abs_chegada. A partir do ponto de destino, o robô iniciará por seguir a linha. Ao chegar à primeira bifurcação, que foi a última informação acrescentada à lista na etapa de exploração, o algoritmo irá verificar no campo dir_abs_chegada por onde o robô chegou a esta bifurcação durante a exploração, com esta informação é possível computar para qual direção absoluta o robô deverá seguir para encontrar a próxima bifurcação, será efetuado o giro para tal direção, e será observada a posição imediatamente anterior na lista de bifurcações. Este procedimento será repetido até que todos os nós da lista tenham sido explorados, e consequentemente, tenha-se chegado ao ponto de origem do labirinto. Para a etapa de navegação, são levadas em conta as informações presentes no parâmetro dir_abs, presente em cada uma das estruturas crossing que levam o robô da origem ao destino. Da mesma forma como é feita a volta do robô para a origem, na etapa de navegação, sempre que chegar a uma bifurcação o robô irá seguir para a direção da próxima bifurcação que o leva ao destino, sem levar em consideração outras direções. A Figura 15 mostra a composição da lista de bifurcações implementada. Estes resultados foram obtidos a partir da exploração do robô feita no labirinto apresentado, na qual foi escolhida como preferência seguir à esquerda. A direção de partida do robô é tomada como Norte (dir_abs = 1), a partir do giro efetuado para a direita (dir_relativa = 1) na bifurcação de número um, o robô passa então a navegar para a direção absoluta Leste (dir_abs = 2), e a direção Norte, para a qual o robô estava indo ao chegar a esta bifurcação é armazenada, (dir_abs_chegada = 1). 27 Figura 15 – Exemplo de composição da lista de bifurcações. Fonte: Elaborado pelo autor, 2014. Ao chegar à bifurcação dois, como é caracterizado pelo algoritmo, o robô opta por seguir para a direita (dir_relativa = 1), o que resulta em uma modificação na sua direção absoluta (dir_abs = 3) e na sua direção absoluta de chegada (dir_abs_chegada = 2). Mas, este caminho não leva o robô ao seu destino, e o mesmo acaba por voltar à bifurcação de número 2, bifurcação esta já conhecida por ele, nesta etapa o robô irá girar para a direita (dir_relativa = 1) por ser uma possibilidade desta bifurcação ainda não explorada pelo mesmo, modificando assim sua direção absoluta (dir_abs = 2). Na bifurcação três ocorre o mesmo. A terceira bifurcação a ser adicionada à lista terá novamente o parâmetro dir_abs_chegada = 2 e, devido a sua preferência por seguir pela esquerda, o robô seguirá para a direção Norte (dir_abs = 1) a partir de um giro efetuado para a esquerda (dir_relativa = -1), caminho este que também não o leva ao destino e ele então retornará à bifurcação de número três. Desta vez, o giro também será efetuado para a esquerda (dir_relativa = -1) e a direção absoluta voltará a ser Leste (dir_abs = 2). 28 Chegando à bifurcação de número quatro, a estrutura crossing a ser adicionada à lista terá como parâmetro dir_abs_chegada = 2, o robô efetuará um giro para a direita (dir_relativa = 1) que é a única possibilidade que existe, passando o robô a seguir para o Sul (dir_abs = 3). A próxima bifurcação encontrada pelo robô é seu destino, dando fim assim à etapa de exploração. Os parâmetros dir_abs_chegada de todas as estruturas adicionadas à lista precisam ser modificadas de forma que elas passem a representar direções absolutas para as quais o robô deverá seguir na etapa de retorno à origem. Desta forma, os parâmetros dir_abs_chegada para as estruturas 1, 2, 3 e 4, armazenadas na lista, passaram a ser iguais a 3, 4, 4 e 4, respectivamente. 29 4 TESTES E RESULTADOS Os testes foram divididos em cinco etapas durante a fase de desenvolvimento do projeto. Foi realizado o teste do algoritmo para quatro configurações em dois labirintos distintos, sendo um destes o mesmo utilizado durante o desenvolvimento do algoritmo, e o segundo labirinto com o propósito de validar o algoritmo. 4.1 TESTES DE DESENVOLVIMENTO A primeira etapa de testes teve como objetivo o conhecimento do robô e de seus sensores IR e encoders, bem como estudar sua biblioteca de programação para a plataforma Arduino, disponível em GITHUB, 2012. Para estes testes fez-se um traçado fechado (Figura 16), demarcado em uma superfície de locomoção branca, para que o robô executasse a tarefa de “seguir a linha”. Ele passa por cima da linha, de forma a percorrer o trajeto repetidas vezes. Figura 16 - Exemplo de trajeto oval, utilizado na primeira etapa de testes. Fonte: Elaborado pelo autor, 2014. Esta etapa foi importante para o aprendizado sobre como lidar com as particularidades da biblioteca de programação. Uma vez conhecidas as funções da biblioteca de programação do 30 robô, e as particularidades de seus movimentos, pode-se passar aos testes do método para identificação das bifurcações, descritos na seção 3. Nesta etapa pôde-se verificar a efetividade do sistema de sensores IR, na identificação das bifurcações apresentadas na Figura 8. Para se ter um feedback (realimentação) sobre as percepções do robô, utilizou-se um módulo de comunicação bluetooth HC-06 (GUANGZHOU HC INFORMATION TECHNOLOGY CO., LTD, 2011), conectado a uma das portas de comunicação serial do Arduino Mega, e que transmitia os dados para um PC (Personal Computer – Computador Pessoal). Figura 17 - Módulo Bluetooth HC-06 Fonte: (GUANGZHOU HC INFORMATION TECHNOLOGY CO., LTD, 2011). A partir de uma codificação feita para cada uma das bifurcações da Figura 8, durante a segunda etapa de testes, sempre que o robô encontrava uma bifurcação, o mesmo ficava parado e enviava uma mensagem para o PC, com isso tornou-se possível validar o reconhecimento das formas das bifurcações. Uma vez conhecidas as possibilidades de movimento do robô e sendo o algoritmo capaz de identificar toda a lista de bifurcações, apresentada na Figura 8, partiu-se para o desenvolvimento do algoritmo de exploração, responsável por percorrer o labirinto à procura de um caminho que levasse o robô da origem ao destino. Durante o desenvolvimento do algoritmo foi necessário executar uma terceira etapa de testes, para tanto, utilizou-se o labirinto mostrado na Figura 12. Nesta etapa, a cada nova bifurcação uma mensagem era enviada ao PC, na qual era informado se o robô já havia passado naquela bifurcação, ou não, e qual o índice daquela bifurcação na lista de bifurcações. 31 Sempre que o robô identificava um trecho que não contribuía para sua chegada ao destino, todas as bifurcações deste eram removidas da lista e uma mensagem de remoção era enviada ao PC. Ao chegar ao ponto de destino, o robô enviava para o PC uma mensagem contendo a lista de bifurcações responsável por levá-lo da origem ao destino. Para o labirinto de testes, Figura 12, a mensagem representava as bifurcações 1, 2, 4 e 5. Logo, a comunicação bluetooth entre o robô e o PC, tornou possível identificar se o trajeto que levou o robô da origem ao destino havia sido realmente o menor trajeto possível dentre os caminhos por onde o robô passou. Em seguida passou-se aos testes do algoritmo de resolução, quarta etapa de testes, utilizando ainda o labirinto da Figura 12. Nesta etapa, o robô foi posto no ponto de origem do labirinto e à medida que encontrava uma bifurcação ele enviava uma mensagem ao PC com as informações da bifurcação atual, e da bifurcação seguinte, até encontrar o ponto de destino. Este sistema possibilitou validar as informações que o robô havia coletado do labirinto. A quinta etapa de testes foi utilizada para validar o uso dos encoders como forma de localização do robô no interior do labirinto. O robô foi posto a percorrer o mesmo labirinto, mostrado na Figura 18, por diversas vezes, e a cada nova bifurcação uma mensagem era enviada ao PC com o valor das variáveis coordenadaX e coordenadaY para aquela bifurcação, tendo como referencial o sistema de coordenadas na configuração mostrada na Figura 18. Figura 18 - Labirinto de teste do sistema de coordenadas. Fonte: Elaborado pelo autor, 2014. A Tabela 1 demonstra os resultados para 10 voltas dadas pelo robô no labirinto da Figura 18. Em todos os casos o robô partiu do ponto de origem e foi até o ponto de destino, de onde ele 32 era removido manualmente e posto no ponto de partida novamente, para repetição do experimento. Tabela 1 - Testes de localização do robô utilizando encoders. Coordenadas (x,y) Bifurcação Teste 1 Teste 2 Teste 3 Teste 4 Teste 5 Teste 6 Teste 7 Teste 8 Teste 9 Teste 10 1 (0, 10) (0, 10) (0, 9) (0, 8) (0, 10) (1, 10) (0, 10) (0, 10) (0, 10) (0, 11) 2 (10, 10) (9, 10) (10, 10) (11, 9) (10, 10) (8, 10) (12, 10) (10, 10) (10, 10) (10, 12) 3 (10, -4) (10, -4) (11, -3) (10, -4) (10, -4) (10, -4) (9, -3) (10, -4) (10, -4) (9, -4) 4 (20, 10) (19, 9) (20, 11) (20, 10) (20, 10) (21, 10) (21, 11) (20, 9) (20, 10) (19, 12) 5 (30, 10) (30, 10) (31, 10) (28, 11) (30, 10) (30, 10) (32, 10) (30, 9) (30, 10) (31, 11) 6 (30, 0) (30, -1) (30, -2) (30, 01) (30, 0) (30, 0) (30, -2) (29, 1) (30, 0) (32, 0) Fonte: Elaborado pelo autor, 2014. 4.2 TESTES E VALIDAÇÃO DO ALGORITMO Os testes do algoritmo por completo foram executados no mesmo labirinto no qual foram feitos os testes em etapas, a fim de garantir o seu funcionamento. Logo após partiu-se para um labirinto com um maior número de bifurcações, como forma de validação do algoritmo. As configurações dos testes foram: a) Ponto de partida localizado à esquerda, com preferência definida para a esquerda; b) Ponto de partida localizado à esquerda, com preferência definida para a direita; c) Ponto de partida localizado à direita, com preferência definida para a esquerda; d) Ponto de partida localizado à direita, com preferência definida para a direita. O resultado para as configurações de “a” a “d” são mostradas na Figura 19 de “a” a “d” respectivamente. Figura 19 – Trajetos resultantes do labirinto de testes. 33 Fonte: Elaborado pelo autor, 2014. Após as etapas anteriores, para validar o trabalho, foi utilizado um labirinto mais complexo conforme apresenta a Figura 20. O caminho percorrido na etapa de volta à origem e de navegação, foram executadas sempre sem a passagem por caminhos desnecessários. 34 Figura 20 - Trajetos resultantes do labirinto de validação. Fonte: Elaborado pelo autor, 2014. O mapeamento das bifurcações do labirinto, de acordo com o sistema de coordenadas X e Y, feito pelos encoders, foi desenvolvido como pontapé inicial para a resolução do problema de labirintos circulares, exposto na Figura 21. No labirinto apresentado existem dois caminhos que levam o robô a uma mesma bifurcação (bifurcação 1), este problema não foi tratado no algoritmo desenvolvido, mas o mapeamento das coordenadas cartesianas poderá ser utilizado em trabalhos futuros que busquem resolvê-lo. 35 Figura 21 - Problema referente a labirintos circulares. Fonte: Elaborado pelo autor, 2014. Para o labirinto exibido na Figura 21, o problema ficará evidente somente se o robô tiver como origem o lado esquerdo do labirinto, e estiver com sua preferência configurada para a esquerda. 36 5 CONCLUSÃO A busca pelo desenvolvimento de sistemas autônomos continua presente nas pesquisas contemporâneas. Apesar dos mais de 30 anos dedicados à pesquisas sobre o tema, ainda são fortes os impactos que tecnologias capazes de interagir com o mundo real, sem a necessidade de intervenções humanas, ocasionam na sociedade. A robótica móvel assistiva é um exemplo valioso de como a autonomia dada a robôs móveis podem influenciar no bem estar de pessoas com algum tipo de deficiência. O avanço no desenvolvimento de sensores cada vez mais precisos e processadores cada vez mais velozes, com uma grande variedade de periféricos e recursos que possibilitam até o processamento de imagens, permitem ao desenvolvedor que este se dedique exclusivamente ao desenvolvimento da “inteligência” do sistema. A barra de sensores IR utilizada na identificação das demarcações da superfície de locomoção, possibilitou de fato uma boa estruturação do ambiente, uma vez que a lógica implementada no algoritmo para percepção dos trajetos, garantiu que o robô se locomovesse sempre dentro dos caminhos demarcados. O uso de lista simplesmente encadeada mostrou-se uma solução factível para o uso na resolução de labirintos, uma vez que o caminho a ser seguido segue uma ordem (sequência) pode-se implementar o armazenamento das estruturas crossing de forma ordenada sem a necessidade de se preocupar com a alocação de memória, etapa abstraída pela implementação das funções referentes à lista encadeada. A criação da estrutura de dados chamada crossing, possibilitou o armazenamento de todos os dados/informações necessários para a exploração e solução do labirinto, e permitiu também a implementação de variáveis que podem ser utilizadas para o aperfeiçoamento futuro do algoritmos, como é o caso dos parâmetros “custo”, “coordenadasX” e “coordenadasY” O sistema de sensoriamento utilizado, barra de IR, apresenta-se como uma excelente forma de percepção de caminhos, uma vez que não apresentam interferência entre sensores, independem da luminosidade do ambiente e são de baixo custo. O sistema de coordenadas cartesianas desenvolvido para se obter a localização do robô durante a etapa de mapeamento, pode ser utilizada em trabalhos futuros para extrair novas informações a respeito do labirinto como, por exemplo, calcular o caminho que contém o menor comprimento e, na etapa de resolução do labirinto, fazer com que o robô siga por este caminho. 37 Também com base nas coordenadas cartesianas, já é possível que o robô identifique, na etapa de exploração, bifurcações pelas quais ele já passou, uma vez que o robô chegará a uma bifurcação com mesma coordenada que uma pela qual ele já navegou. Com esta informação pode-se, em trabalhos futuros, agregar rotinas a este algoritmo para que o robô tome decisões sobre quais providencias tomar neste caso. 38 REFERÊNCIAS ARDUINO. Arduino - ArduinoBoardMega2560, 2014. Disponivel em: <http://arduino.cc/en/Main/ArduinoBoardMega2560>. Acesso em: 08 out. 2014. BRAUNL, T. Research relevance of mobile robot competitions. IEEE Robotics & Automation Magazine, v. VI, n. 4, p. 32-37, 1999. CAI, J. et al. An algorithm of micromouse maze solving. Computer and Information Technology (CIT), 2010 IEEE 10th International Conference on, 2010. 1995-2000. CHANG, H. J. et al. Simultaneous localization and mapping with environmental-structure prediction. Robotics, IEEE Transactions on, v. 23, n. 2, p. 281-293, 2007. GITHUB. Zumo Shield. GitHub, 2012. Disponivel em: <https://github.com/pololu/zumoshield>. Acesso em: 13 set. 2014. GUANGZHOU HC INFORMATION TECHNOLOGY CO., LTD. Product Data Sheet HC-06. Revisão 2.0. ed. [S.l.]: [s.n.], 2011. HUALONG, J.; YONGHONG, T.; HONGQI, W. Design and Realization of a Maze Robot. Consumer Electronics, Communications and Networks (CECNet), 2011 International Conference on. IEEE, 2011. 201-204. IEEE. Micromouse Competition Rules. 2013 IEEE Region1 Student Conference, Cambridge, 5 - 6 Abril 2013. MISHRA, S.; BANDE, P. Maze Solving Algorithms for Micro Mouse. IEEE International Conference on Signal Image Technology and Internet Based Systems, 2008. 86 - 96. MOREIRA, A.; VASCONCELOS, F.; FILHO, J. Uso de Robótica Assistiva no Auxílio de Pessoas com Deficiências Visuais. V CONNEPI-2010, 2010. PASSOLD, F. Despertando para a Importância das Competições de Robôs. Anais: do XXXIV Congresso Brasileiro de Educação em Engenharia, Passo Fundo, 2006. POLOLU. Pololu - Encoder for Pololu Wheel 42x19mm, 2014. Disponivel em: <https://www.pololu.com/product/1217>. Acesso em: 30 ago. 2014. POLOLU. Zumo Robot for Arduino. Pololu Robotics & Eletronics, 2014. Disponivel em: <https://www.pololu.com/product/2506>. Acesso em: 16 out. 2014. POLOLU, R. Pololu - QTR-8RC Reflectance Sensor Array. Pololu Robotics & Eletronics, 2014. Disponivel em: <https://www.pololu.com/product/961>. Acesso em: 10 ago. 2014. RANGEL NETO, J. L. M.; CERQUEIRA, R. F. D. G.; CELES FILHO, W. Introdução a estrutura de dados: com técnicas de programação em C. 3ª. ed. [S.l.]: Campus, 2004. VILLAS, M. V. et al. Estrutura de Dados: Conceitos e Técnicas de Implementação. 9ª. ed. [S.l.]: [s.n.], 1993. 39 APÊNDICE A - Algoritmo desenvolvido #include <ZumoMotors.h> #include <Pushbutton.h> #include "MyQueueList.h" #include <math.h> #define interrupt 2 #define passa 5 #define primeiro_pino_ir 33 #define mtrapido 270 #define rapido 170 #define lento 120 #define mtlento 80 #define ultrapass 13 #define possib_cruz 2 #define possib_te 1 #define possib_IK 1 #define possib_KI 1 #define direita 1 #define esquerda -1 #define algoritmo 1 struct crossing { int indice; int dir_relativa; int dir_abs; int dir_abs_chegada; int custo; int possibilidades; }; int ir[8]; ZumoMotors motors; Pushbutton button(ZUMO_BUTTON); volatile int pwm_e = 0; volatile int pwm_d = 0; int led = 13; int flag = 0; int n_flag = 0; int cont_passa = 0; int cont_bif = 1; int dir_abs_ant = 1; unsigned long num_pulsos = 0; int habilita_passa; long coordenadas_xy[2] = {0, 0}; int val_incremento[2] = {0, 1}; const int mat_transf[2][2] = {{0, 1}, {-1, 0}}; QueueList <crossing> list_bif; QueueList <crossing> list_bif_volta; QueueList <crossing> list_bif_solve; void myMain(); void inicializaSensor(); 40 byte lerSensores(); void navegaLab(byte ir_array); int identificaBifurcacao(); int explora(int n_flag); void praondeVou(); void setaDirabs (int sentido, int reto); void gira(int sentido, int reto); void addList(int dir_rel_bif, int possib); void calculaIncremento(int sent); void trataListaVolta(crossing noh); void meiaVolta(); int retornaMase(int bifurca); void trataListaSolve(); int solveMase(int n_flag); void piscaLed(int qnt, int vezes_time); void setup() { Serial.begin(9600); Serial1.begin(9600); attachInterrupt(interrupt, pulsosEncoder, RISING); pinMode(led,OUTPUT); digitalWrite(led,LOW); inicializaSensor(); myMain(); } void myMain() { byte ir_array; int bifurca, end_mase = 0; crossing noh; int teste_serial; piscaLed(8, 3); while(end_mase == 0){ cont_passa = num_pulsos + passa; while (num_pulsos <= cont_passa){ ir_array = lerSensores(); navegaLab(ir_array); } habilita_passa = 0; bifurca = identificaBifurcacao(); end_mase = explora(bifurca); flag = 0; } delay(2000); 41 trataListaSolve(); end_mase = 0; meiaVolta(); while(end_mase == 0){ cont_passa = num_pulsos + passa; while (num_pulsos <= cont_passa){ ir_array = lerSensores(); navegaLab(ir_array); } habilita_passa = 0; bifurca = identificaBifurcacao(); end_mase = retornaMase(bifurca); flag = 0; } delay(2000); end_mase = 0; meiaVolta(); while(end_mase == 0){ cont_passa = num_pulsos + passa; while (num_pulsos <= cont_passa){ ir_array = lerSensores(); navegaLab(ir_array); } habilita_passa = 0; bifurca = identificaBifurcacao(); end_mase = solveMase(bifurca); flag = 0; } piscaLed(10,3); } void loop(){ } void inicializaSensor() { int i; for(i=0;i<8;i++) { ir[i] = primeiro_pino_ir + (i*2); pinMode(ir[i], INPUT); } 42 } byte lerSensores() { int i, ir_val, ir_array = 0; for(i=7;i>=0;i--) { ir_val = digitalRead(ir[i]); ir_val = ir_val << i; ir_array += ir_val; delay(5); } return ir_array; } void navegaLab(byte ir_array) { byte sens = ir_array & B10111101; if((sens == 1)||(sens == 5)||(sens == 9)||(sens == 13)||(sens == 17)||(sens == 21)||(sens == 25)||(sens == 29)||(sens == 33)||(sens == 37)||(sens == 41)||(sens == 45)||(sens == 49)||(sens == 53)||(sens == 57)||(sens == 61)) { if(flag != 3) flag = 1; } else if((sens == 4)||(sens == 8)||(sens == 12)) { pwm_e = rapido; pwm_d = mtlento; } else if(sens == 24) { pwm_e = lento; pwm_d = lento; } else if((sens == 16)||(sens == 32)||(sens == 48)) { pwm_e = mtlento; pwm_d = rapido; } else if((sens == 128)||(sens == 132)||(sens == 136)||(sens == 140)||(sens == 144)||(sens == 148)||(sens == 152)||(sens == 156)||(sens == 160)||(sens == 164)||(sens == 168)||(sens == 172)||(sens == 176)||(sens == 180)||(sens == 184)||(sens == 188)) { if(flag != 3) flag = 2; } else if((sens == 189)) { flag = 3; } else if(sens == 0) 43 { if(flag == 0) flag = 4; } if(flag == 0) { motors.setSpeeds(pwm_e, pwm_d); } else { habilita_passa = 1; motors.setSpeeds(lento, lento); } } int identificaBifurcacao(){ int n_flag = 0; if((flag == 3) && (lerSensores() == 0)) n_flag = 1; else if((flag == 3) && (lerSensores() == B11111111)) n_flag = 2; else if((flag == 1) && (lerSensores() != 0)) n_flag = 3; else if((flag == 2) && (lerSensores() != 0)) n_flag = 4; else if(flag == 1) n_flag = 5; else if (flag == 2) n_flag = 6; else if (flag == 3) n_flag = 7; else if(flag == 4) n_flag = 8; return n_flag; } int explora (int bifurca){ int fim_lab = 0; int dir_giro, reto = 1, n_possibilidades, chegada; crossing noh; chegada = dir_abs_ant; switch (bifurca){ case 1: if(cont_bif != list_bif.count()){ dir_giro = algoritmo; setaDirabs(dir_giro, reto); 44 addList(dir_giro,possib_te,chegada); } else{ noh = list_bif.pop(); dir_giro = noh.dir_relativa; setaDirabs(dir_giro, reto); if(noh.possibilidades > 0){ n_possibilidades = noh.possibilidades - 1; addList(dir_giro, n_possibilidades, noh.dir_abs_chegada); } } cont_bif++; gira(dir_giro, 1); break; case 2: fim_lab = 1; gira(0,1); break; case 3: if(cont_bif != list_bif.count()){ dir_giro = direita; setaDirabs(dir_giro, reto); addList(dir_giro,possib_IK,chegada); reto = 1; } else{ noh = list_bif.pop(); reto = 2; if(noh.possibilidades > 0){ n_possibilidades = noh.possibilidades - 1; addList(dir_giro, n_possibilidades, noh.dir_abs_chegada); } else{ cont_bif--; cont_bif--; } } cont_bif++; gira(dir_giro, reto); break; case 4: if(cont_bif != list_bif.count()){ dir_giro = esquerda; setaDirabs(dir_giro, reto); addList(dir_giro,possib_KI,chegada); reto = 1; } else{ noh = list_bif.pop(); 45 reto = 2; if(noh.possibilidades > 0){ n_possibilidades = noh.possibilidades - 1; addList(dir_giro, n_possibilidades, noh.dir_abs_chegada); } else{ cont_bif--; cont_bif--; } } cont_bif++; gira(dir_giro, reto); break; case 5: dir_giro = 1; gira(dir_giro, 1); setaDirabs (dir_giro, reto); break; case 6: dir_giro = -1; gira(dir_giro, 1); setaDirabs (dir_giro, reto); break; case 7: if(cont_bif != list_bif.count()){ dir_giro = algoritmo; setaDirabs(dir_giro, reto); addList(dir_giro,possib_cruz,chegada); } else{ noh = list_bif.pop(); dir_giro = algoritmo; setaDirabs(dir_giro, reto); if(noh.possibilidades > 0){ n_possibilidades = noh.possibilidades - 1; addList(dir_giro, n_possibilidades, noh.dir_abs_chegada); } else cont_bif--; } cont_bif++; gira(dir_giro, 1); break; case 8: gira(esquerda, 1); setaDirabs(esquerda, reto); setaDirabs(esquerda, reto); cont_bif--; break; } 46 return fim_lab; } void setaDirabs (int sentido, int reto){ int nova_dir_abs; if(reto != 2){ calculaIncremento(sentido); switch (sentido){ case (-1): nova_dir_abs = dir_abs_ant + 3; break; case (1): nova_dir_abs = dir_abs_ant + 1; break; } ((nova_dir_abs > 4) ? (dir_abs_ant = (nova_dir_abs - 4)) : (dir_abs_ant = nova_dir_abs)); } } void gira(int sentido, int reto){ byte sens_sinal_e = B10000000; byte sens_sinal_d = B00000001; byte sens_centro = B00010000; int pwm_e, pwm_d; int val_incremento_aux[2] = {val_incremento[0], val_incremento[1]}; val_incremento[0] = 0; val_incremento[1] = 0; pwm_e = pow(sentido,reto); pwm_d = pow(-sentido,reto); motors.setSpeeds((pwm_e * lento), (pwm_d * lento)); while (!((sens_sinal_e & lerSensores()) || (sens_sinal_d & lerSensores()) || (reto == 2))); while (!((sens_centro & lerSensores()) || (reto == 2))); val_incremento[0] = val_incremento_aux[0]; val_incremento[1] = val_incremento_aux[1]; } void addList(int dir_rel_bif, int possib, int dir_chegada_abs){ int custo_lab = 0; int index = list_bif.count()+1; crossing noh; noh = (crossing){index, dir_rel_bif, dir_abs_ant, dir_chegada_abs, custo_lab, possib}; list_bif.myPush(noh); } void praondeVou(){ } void piscaLed(int qnt, int vezes_time){ for(int x = 0; x < 2*qnt; x++){ digitalWrite(led, !digitalRead(led)); 47 for(int j = 0; j < vezes_time; j++) delay(100); } } void pulsosEncoder(){ num_pulsos++; num_pulsos *= habilita_passa; coordenadas_xy[0] = coordenadas_xy[0] + 1 * val_incremento[0]; coordenadas_xy[1] = coordenadas_xy[1] + 1 * val_incremento[1]; } void trataListaVolta(crossing noh){ int dir_abs_volta; dir_abs_volta = noh.dir_abs_chegada; if(dir_abs_volta > 2) dir_abs_volta = dir_abs_volta - 2; else dir_abs_volta = dir_abs_volta + 2; noh.dir_abs_chegada = dir_abs_volta; list_bif_volta.push(noh); } void trataListaSolve(){ crossing noh; while(list_bif.count() > 0){ noh = list_bif.pop(); trataListaVolta(noh); list_bif_solve.myPush(noh); } } int solveMase(int bifurca){ crossing noh; int dir_giro = 1, fim_lab = 0, dif_dir, reto = 1; switch (bifurca){ case 2: fim_lab = 1; dir_giro = 0; break; case 5: dir_giro = 1; reto = 1; break; case 6: dir_giro = -1; reto = 1; break; 48 default: noh = list_bif_solve.pop(); if(noh.dir_abs == dir_abs_ant) reto = 2; else{ dif_dir = dir_abs_ant - noh.dir_abs; if((dif_dir == -3) || (dif_dir == 1)) dir_giro = -1; else dir_giro = 1; reto = 1; } break; } gira(dir_giro, reto); if(dir_giro != 0) setaDirabs (dir_giro, reto); return fim_lab; } int retornaMase(int bifurca){ crossing noh; int dir_giro = 1, fim_lab = 0, dif_dir, reto = 1; switch (bifurca){ case 2: fim_lab = 1; dir_giro = 0; break; case 5: dir_giro = 1; reto = 1; break; case 6: dir_giro = -1; reto = 1; break; default: noh = list_bif_volta.pop(); if(noh.dir_abs_chegada == dir_abs_ant) reto = 2; else{ dif_dir = dir_abs_ant - noh.dir_abs_chegada; if((dif_dir == -3) || (dif_dir == 1)) dir_giro = -1; else dir_giro = 1; reto = 1; } break; } gira(dir_giro, reto); if(dir_giro != 0) setaDirabs (dir_giro, reto); 49 return fim_lab; } void meiaVolta(){ motors.setSpeeds(-lento, -lento); delay(200); motors.setSpeeds(0, 0); delay(200); motors.setSpeeds(-lento, lento); while(lerSensores() != 0B00010000); motors.setSpeeds(0, 0); setaDirabs (1, 1); setaDirabs (1, 1); } void calculaIncremento(int sent){ int aux; aux = sent * (mat_transf[0][0] * val_incremento[0] + mat_transf[0][1] * val_incremento[1]); val_incremento[1] = sent * (mat_transf[1][0] * val_incremento[0] + mat_transf[1][1] * val_incremento[1]); val_incremento[0] = aux; }