Universidade do Minho Conselho de Cursos de Engenharia Licenciatura em Engenharia Informática 3ºAno Disciplina de Laboratórios de Informática IV Ano Lectivo de 2007/2008 Exploração da plataforma de programação leJOS para robôs Lego MindStorms: Uma Abordagem à Robótica Evolucionária 47109 – Tiago Costa Oliveira 47119 – Nélson Manuel Almeida Gonçalves 47131 – João Manuel Fernandes da Silva Ribeiro Julho, 2008 i Data de Recepção Responsável Avaliação Observações Exploração da plataforma de programação leJOS para robôs Lego MindStorms: Uma Abordagem à Robótica Evolucionária 47109 – Tiago Costa Oliveira 47119 – Nélson Manuel Almeida Gonçalves 47131 – João Manuel Fernandes da Silva Ribeiro Julho, 2008 ii Resumo O objectivo deste trabalho foi a exploração da plataforma leJOS que permite a programação dos robôs LEGO MindStorms em JAVA (mais exactamente, num pequeno subconjunto de JAVA), assim como o uso da mesma numa abordagem à robótica evolucionária, contudo acabamos também por testar a linguagem NXT-G e fizemos uma pequena comparação entre ambas, comparação essa onde concluímos que ambas as linguagens têm tanto pontos fortes como pontos fracos.. Quanto à abordagem à robótica evolucionária, usamos um modelo baseado em programação por comportamentos, no qual o robô deveria percorrer um circuito e no fim do percurso calcular o seu desempenho através de uma função de fitness que tem em conta o tempo e a distância gastos a percorrer esse mesmo circuito. Concluindo conseguimos implementar, embora de forma algo rudimentar, um processo evolucionário de aprendizagem para satisfazer o objectivo pretendido. Área de Aplicação: Plataformas de Programação NXT-G e leJOS. Robótica Evolucionária. Palavras-Chave: Lego MindStorm, NXT-G, leJOS, JAVA, robótica evolucionária, genótipo, programação baseada em comportamentos, cromossomas. iii Índice Índice iv 1. Introdução 1 1.1. Contextualização 1 1.2. Apresentação do Caso de Estudo 3 1.3. Motivação e Objectivos 5 2. Implementação da Solução 6 3. Conclusões e Trabalho Futuro 8 Anexos 11 I. Programa Foward em Código NXT-G 12 II. Programa Foward em Código JAVA 13 III. Programa Rotate em Código NXT-G 14 IV. Programa Rotate em Código JAVA 15 V. Programa RandomMove em Código NXT-G 16 VI. Programa RandomMove em Código JAVA 17 VII. Programa KeepDistance em Código NXT-G 18 VIII. Programa KeepDistance em Código JAVA 19 IX. Programa LineFollow em Código NXT-G 21 X. Programa LineFollow em Código JAVA 22 XI. Classe FowardBehavior em Código JAVA 24 XII. Classe FindBestDirBehavior em Código JAVA 25 XIII. Classe EndDriveBehavior em Código JAVA 27 XIV. Classe Arbitrator3 em Código JAVA 28 XV. Classe RobotDrive em Código JAVA 30 XVI. Controlador do Robô a Partir do PC 33 iv 1. Introdução 1.1. Contextualização Como base para a elaboração deste trabalho usamos as plataformas de programação leJOS e NXT-G, ambas orientadas à programação dos robôs LEGO Mindstorms. Lego MindStorms é o resultado de uma parceria de mais de uma década entre o Media LAB do M.I.T e a LEGO e consiste num conjunto de peças lego tradicionais, sensores de toque, intensidade luminosa, som, distancia entre outros e um bloco programável onde se encontra o processador. O nome MindStorms foi inspirado no título do livroMindStorms: Children, Computers, andPowerfullIdeas escrito porSeymourPapert, que foi um dos fundadores do M.I.T. A primeira versão lego MindStorms foi lançada em 1998 e era conhecida por Robot InventionSystem(RIS), a versão actual chama-se MindStorms NXT (sucessora do MindStormsRCX) e foi lançada em 2006. Os robôs LEGO MindStorms podem ser usados tanto para fins lúdicos como para fins educacionais como por exemplo introdução à robótica, automação, física, programação, etc. leJOS é um de vários firmwares alternativos desenvolvidos pela comunidade entusiasta dos robôs LEGO MindStorms para tirar proveito das capacidades oferecidas pelos mesmos e teve como principais contribuidores BrianBagnall, JurgenStuber, Paul Andrews e José Solórzano. O leJOS surgiu como uma ramificação do TinyVM, e consiste num firmware que permite correr uma maquina virtual de JAVA nos blocos RCX e NXT, ou seja, vai permitir o uso da linguagem JAVA no desenvolvimento de programas para robôs. O leJOS põe ao dispor do utilizador várias 1 bibliotecas que permitem o controlo de todos os sensores e motores do robô, assim como a programação baseada em comportamentos, entre outras funções de alto nível. NXT-G é a linguagem visual de programação que vem por predefinição com os robôs LEGO e é muito simples e intuitiva para uso das funções básicas do robô como o controlo dos motores ou leitura dos valores sensores, tornando-se por isso adequada para quem está a ter contacto pela primeira vez com os robôs MindStorms e quer ver quais as suas potencialidades. É fácil de usar devido ao seu interface gráfico com menus que são bastante esclarecedores quanto às várias opções disponíveis, no entanto toda esta facilidade não impede a existência de aspectos mais avançadas como o uso de variáveis, implementação de ciclos com as respectivas condições de paragem, o uso de valores lógicos, a possibilidade do encadeamento de blocos de código mais simples para obter blocos mais complexos, etc. É portanto uma linguagem bastante completa que permite desenvolver tanto programas básicos, como programas mais complexos. Finda que está a contextualização relativamente às plataformas usadas neste trabalho podemos passar a uma breve explicação acerca da Robótica Evolucionária, o que trata e em que consiste. A possibilidade da evolução de robôs inteligentes através de processos evolucionários surgiu pela primeira vez em 1984 pelo neurofisiologista Valentino Braitenberg quando este falou da possibilidade da criação de robôs inteligentes a partir de processos evolucionários no livro Vehicles: Experiments in Synthetic Psychology. O conceito de robótica evolucionária apareceu em 1993 por CliffHarvey e Husbands na Universidade de Sussex. Em 1992/1993, duas equipas uma composta por Floreano e Mondada, a outra constituída por um grupo de investigadores da universidade de Sussex anunciaram as primeiras experiências de evolução artificial com robôs. O sucesso desta pesquisa gerou uma enorme série de actividades pelo mundo fora na tentativa de explorar todo potencial deste novo conceito. A ideia básica por trás da robótica evolucionária é a de aplicar o conceito de evolução natural de Darwin aos robôs, conceito esse no qual existe uma reprodução selectiva na qual apenas participam os seres mais aptos. Neste conceito de robótica evolucionária os robôs são vistos como organismos artificiais e autónomos que desenvolvem as duas aptidões apenas através 2 da interacção com o meio que os rodeia, sem qualquer tipo intervenção humana. Da mesma maneira que nos seres vivos a informação genética está codificada nos cromossomas, nos robôs essa informação está codificada também sob a forma de cromossomas, no caso dos robôs, designamos por cromossomas o conjunto de parâmetros que controlam o comportamento do robô. Depois de termos uma população de robôs com diferentes cromossomas, a cada robô (físico ou simulado) é lhe permitido agir livremente, mas as suas acções são monitorizadas automaticamente por um mecanismo de controlo específico que avalia a sua performance tendo em conta os critérios definidos pelo responsável da experiência. Aos robôs que obterem melhores performances é-lhes permitido reproduzirem-se (sexuada/assexuadamente) através da geração de copias dos seus genótipos com a adição de modificações introduzidas por mutações, combinações ou duplicações dos valores seus parâmetros(ou operadores genéticos). Este processo é depois repetido durante várias gerações até aparecer um indivíduo que satisfaça os critérios de performance previamente considerados como aceitáveis. 1.2. Apresentação do Caso de Estudo Exploração da plataforma de programação leJOS para robôs Lego MindStorms: uma abordagem à Robótica Revolucionária. No âmbito de projectos de investigação em curso existem disponíveis robôs Lego MindStorms NXT. Pretende-se neste projecto explorar a plataforma Lejos que permite programar estes robôs utilizando a linguagem Java. O objectivo final é a construção de uma aplicação, onde o robô seja capaz de evoluir o seu comportamento numa dada tarefa ao longo do tempo, apenas fornecendo feedback pelo seu desempenho e não programando explicitamente a sua resolução. Pretende-se neste trabalho a análise da plataforma leJOS assim como implementação de conceitos de robótica evolucionária usando esta mesma plataforma como base. A plataforma leJOS surge como ferramenta de trabalho no âmbito deste projecto, tendo dois objectivos em vista, sendo o primeiro chegar à conclusão se vale a pena usar a plataforma leJOS em detrimento da linguagem NXT-G que é a linguagem que vem por predefinição, o 3 segundo dos objectivos é servir de suporte à utilização de conceitos tanto de robótica evolucionária como de programação baseada em comportamentos. Para a resolução do primeiro objectivo, foi necessária a criação de alguns programas de diversos níveis de complexidade, uns mais simples, outros mais complexos, os programas foram desenvolvidos em cada uma das plataformas para depois podermos proceder à comparação da complexidade obtida na criação dos mesmos. A conclusão foi então que para projectos de pequena dimensão e baixo nível de complexidade a linguagem NXT-G é mais simples de usar que a linguagem JAVA, embora sejam ambas fáceis de utilizar, contudo no caso de um projecto mais complexo acaba por ser mais fácil programar usando Java, isto porque a linguagem visual desenvolvida pela LEGO se torna demasiado complexa, em suma podemos concluir que a linguagem NXT-G é a mais adequada à resolução de problemas simples, enquanto que JAVA é mais indicada para a resolução de problemas mais complexos. (O código dos programas criados tendo em vista a comparação entre as plataformas pode ser visto nos anexos.) A abordagem à robótica evolucionária está presente neste trabalho na medida em que tanto conceitos de robótica evolucionária como conceitos de programação baseada em comportamentos foram utilizados na programação do robô. Apesar da programação baseada em comportamentos não ser exactamente o mesmo que robótica evolucionária, ambas têm pontos em comum, tais como a importância desempenhada pelo ambiente no qual decorrem as experiências. Já o principal ponto de divergência entre ambas é que enquanto que na programação baseada em comportamentos a resolução do problema é obtida através de um processo de tentativa e erro no qual o operador modifica os comportamentos actuais do robô enquanto vê a repercussão destas alterações no comportamento global do mesmo, na programação baseada em robótica evolucionária o processo de tentativa e erro é feito automaticamente através de um algoritmo de avaliação de resultados obtidos que funciona automaticamente, esse algoritmo faz uso de uma função que mede o desempenho do robô tendo em conta os resultados pretendidos, função essa a que iremos chamar função de desempenho mas que também pode ser chamada de fitnessfunction. Outra das diferenças entre ambos os processos é que enquanto que na aproximação à robótica baseada no uso de comportamentos, a divisão de um comportamento do robô em comportamentos mais simples é desempenhada de forma intuitiva pelo operador, na robótica evolucionária esta divisão não éexecutada pelo operador, é sim resultado de um processo de auto organização. A programação baseada em comportamentos baseia-se num pressuposto no qual os robôs são munidos de um conjunto de comportamentos básicos. À reacção resultante da interacção desses comportamentos básicos com o ambiente da experiência dá-se o nome de comportamento global, o que nós fizemos foi então usar esta característica, ou seja, a existência de comportamentos básicos, e depois aplicamos um algoritmo de avaliação de 4 resultados (como o que existe em robótica evolucionária), em vez de fazermos a avaliação de resultados obtidos manualmente. É por isto que no nosso trabalho se verifica o uso tanto de conceitos de robótica evolucionária como de conceitos de programação baseada em comportamentos. 1.3. Motivação e Objectivos Sabemos que hoje em dia os robôs e a inteligência artificial são temas muito discutidos e o seu desenvolvimento e utilização está a ganhar terreno rumo ao futuro e sendo a robótica evolucionária uma técnica para automatizar a criação de robôs autónomos, achamos que era bastante interessante descobrirmos um pouco mais acerca deste tema. Quando se houve falar em Legos, somos levados ao nosso tempo de crianças em que juntávamos blocos para construir o que nos passava pela imaginação. Explorar o modelo mais avançado de robô programável desta marca internacional, juntamente com a possibilidade de trabalhar aplicações e programas relativos à nossa área de estudo tais como programação lejos baseada em Java é uma oportunidade única. Explorar e descobrir muitos conceitos da robótica revolucionária e inteligência artificial são também desafios que nos movem na realização deste projecto. Como base para a elaboração deste trabalho iremos explorar as plataformas de programação leJOS e NXT-G, ambas orientadas à programação dos robôs LEGO Mindstorms, utilizando exemplos e tratando problemas e tarefas iguais para ambos os tipos de programação. 5 2. Implementação da Solução Na implementação deste projecto foram usadas as ferramentas Lego MindStorms NXT, o IDE Eplipse com um plugin específico para leJOS e o IDE NetBeans para criação de um ambiente em SWING para a aplicação. Tal como já foi dito previamente, um dos objectivos do trabalho foi comparar as plataformas leJOS e LEGO MindStorms NXT-G. Para tal foram concebidos cinco programas na linguagem gráfica da Lego, usando a ferramenta Lego MindStorms NXT e outros cinco desenvolvidos em java para correrem na máquina virtual disponibilizada pelo firmware leJOS, programas esses que são por ordem crescente de complexidade: Forward que é programa que apenas consiste em fazer o robô andar em frente até encontrar um obstáculo, Rotate que é um programa que consiste em fazer o robô rodar sobre o seu próprio eixo até captar um ruído acima de um determinado nível, Random_Move que consiste em fazer com que o robô tenha movimentos aleatórios até se deparar com um obstáculo, Keep_Distance que faz com que o robô mantenha uma certa distância (neste caso 35cm) de um objecto qualquer, isto é, caso o objecto ande na direcção oposta ao robot, este avança de modo a encurtar a distancia até 35cm, caso o objecto se mova na direcção do robô este recua até atingir a distancia de 35cm do objecto, por último temos o programa mais complexo que se chama Line_Follow e consiste em fazer com que o robô siga uma determinada linha preta no chão. Depois de termos implementado todos estes programas, através da análise do código (presente na secção anexos do relatório) é-nos possível verificar que à medida que aumenta a complexidade dos programas, a interpretação do código dos programas em Java não se torna tão complicada como a interpretação do código dos mesmos programas em NXT-G, ou seja, JAVA é a linguagem mais indicada para a programação destes robôs, uma vez que para programas simples, é fácil de usar (embora não tanto como a NXT-G), e para programas mais complexos não se torna muito confusa tal como a sua rival, a linguagem gráfica desenvolvida pela LEGO. A segunda parte do projecto foi implementada usando alguns conceitos de robótica evolucionária e a programação do robô foi feita segundo um modelo baseado em comportamentos. O modelo baseado em comportamentos que nós criamos para este caso em específico, baseia-se em 3 comportamentos básicos sendo eles: 6 Forwardbehavior (Anexo XI) que é o comportamento permite andar em frente; EndDriveBehavior (Anexo XIII) que é o comportamento que permite identificar o final de percurso e calcular o desempenho obtido pelo robô, tendo em conta o tempo demorado e a distância percorrida; FindBestDirBehavior (Anexo XII) que é o comportamento que permite identificar qual a melhor direcção a tomar. Estes três comportamentos são depois codificados através do uso de quatrovariáveis Drive Speed que controla a velocidade do robô em linha recta, RotatitionSpeed que controla a velocidade de rotação do robot, RotationAngle que controla o ângulo de rotação do robô em graus e Stop Margin que codifica a distância de paragem perante um obstáculo. O envio destas quatro variáveis é efectuado via bluetooth através de um PC com um programa também por nós desenvolvido (ver anexo XVI). Por uma questão de simplicidade o algoritmo evolucionário (implementado do lado do PC) procede à optimização de cada um destes parâmetros de cada vez até alcançarem o seu valor óptimo. Depois de tomadas todas estas decisões quanto à maneira como iríamos implementar os conceitos de robótica evolucionária, partimos para a produção de código em JAVA (ver anexo XI). 7 3. Conclusões e Trabalho Futuro Neste relatório encontra-se a maior parte da pesquisa efectuada por nós para uma melhor elaboração deste projecto de grupo, pesquisa essa que cobre vários assuntos, desde a origem dos robôs LEGO MindStorms passando pela historia de como surgiu o leJOS, até finalmente fazermos uma breve introdução à Robótica Evolucionária e a programação baseada em comportamentos. Relativamente ao que nos foi pedido, pensamos ter alcançado de forma satisfatória os objectivos a que nos propusemos de início, contudo outro tipo de abordagem poderia ter sido utilizada, nomeadamente um tipo de evolução mais sofisticado o que é possível alcançar sem alterar o software desenvolvido para o robô dado que este apenas recebe parâmetros e devolve um valor relativo ao desempenho, ficando a evolução dos parâmetros a cargo de um qualquer software que possa efectuar uma ligação bluetooth ao robô. 8 Bibliografia Bagnall, Brian “Building Robots with Java Brains” Variant Press, Canada, 2007 Floreano, Dario Nolfi, Stefano “Evolutionary Robotics” MIT Press, EUA, 2000 9 Referências WWW [01] http://mindstorms.lego.com Página do fabricante do robô MindStorm da Lego. Aqui podemos encontrar informação referente ao robô assim como projectos já realizados. [02] http://en.wikipedia.org/wiki/Lego_Mindstorms Página da conhecida Wikipédia com conceitos interessantes sobre os robôs da Lego, MindStorms. [03] http://lejos.sourceforge.net/ Página principal do firmware leJOS que nos permite introduzir a programação JAVA para controlar o robot. [04] http://en.wikipedia.org/wiki/Evolutionary_robotics Página da Wikipédia que aborda o tema da Robótica Evolucionária. [05] http://lis.epfl.ch/index.html?content=resources/documentation/EvolutionaryRobo tics/index.php Website sobre robótica revolucionária. [06] http://www.bartneck.de/2008/03/04/java-lego-nxt-eclipse-tutorial/ Página com Tutoriais de programação NXT-G. [07] http://www.ortop.org/NXT_Tutorial/ Página com Tutoriais de programação NXT-G. [08] http://lejos.sourceforge.net/tutorial/index.html Página com Tutoriais de programação lejos. 10 Anexos 11 I. Programa Foward em Código NXT-G Figura 1 - Ilustração do Programa Foward em Código NXT-G 12 II. Programa Foward em Código JAVA import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; import lejos.nxt.UltrasonicSensor; public class Forward { public static void main(String[] args) throws Exception { UltrasonicSensor us = new UltrasonicSensor(SensorPort.S3); for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } Motor.A.setPower(75); Motor.C.setPower(75); while(us.getDistance() > 50){ Motor.A.forward(); Motor.C.forward(); } Motor.A.stop(); Motor.C.stop(); } 13 III. Programa Rotate em Código NXT-G Figura 2 - Ilustração do Programa Foward em Código NXT-G 14 IV. Programa Rotate em Código JAVA import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; import lejos.nxt.SoundSensor; public class Rotate { public static void main(String[] args) throws Exception { SoundSensor ss = new SoundSensor(SensorPort.S4); for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } Motor.A.setPower(75); Motor.C.setPower(75); while(ss.readValue() < 50){ Motor.A.forward(); Motor.C.backward(); } Motor.A.stop(); Motor.C.stop(); } 15 V. Programa RandomMove em Código NXT-G Figura 3 - Ilustração do Programa Foward em Código NXT-G 16 VI. Programa RandomMove em Código JAVA import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; import lejos.nxt.UltrasonicSensor; public class RandomMove { public static void main(String[] args) throws Exception { UltrasonicSensor us = new UltrasonicSensor(SensorPort.S3); for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } Motor.A.setSpeed(0); Motor.C.setSpeed(0); Motor.A.forward(); Motor.C.forward(); while(us.getDistance() > 50){ Motor.A.setSpeed(200 + (int) (Math.random()*400)); Motor.C.setSpeed(200 + (int) (Math.random()*400)); Thread.sleep(500); } Motor.A.flt(); Motor.C.flt(); } 17 VII. Programa KeepDistance em Código NXT-G Figura 4 - Ilustração do Programa Foward em Código NXT-G 18 VIII. Programa KeepDistance em Código JAVA import lejos.nxt.Button; import lejos.nxt.LCD; import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; import lejos.nxt.UltrasonicSensor; public class keepDistance { public static void main(String[] args) throws Exception { UltrasonicSensor us = new UltrasonicSensor(SensorPort.S3); int distance; for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } Motor.A.setSpeed(500); Motor.C.setSpeed(500); while(Button.readButtons() == 0){ us.ping(); Thread.sleep(20); distance = us.getDistance(); LCD.clear(); LCD.drawInt(Motor.A.getActualSpeed(), 0, 0); LCD.drawInt(distance, 0, 1); LCD.refresh(); (continua na página seguinte) 19 if(40 < distance && distance < 80){ while(35 < distance && distance < 85){ Motor.A.forward(); Motor.C.forward(); LCD.clear(); LCD.drawInt(Motor.A.getActualSpeed(), 0, 0); LCD.drawInt(distance, 0, 1); us.ping(); Thread.sleep(20); distance = us.getDistance(); LCD.refresh(); } Motor.A.stop(); Motor.C.stop(); } us.ping(); Thread.sleep(20); distance = us.getDistance(); if(distance < 30){ while(distance < 35){ Motor.A.backward(); Motor.C.backward(); LCD.clear(); LCD.drawInt(Motor.A.getActualSpeed(), 0, 0); LCD.drawInt(distance, 0, 1); LCD.refresh(); us.ping(); Thread.sleep(20); distance = us.getDistance(); } Motor.A.stop(); Motor.C.stop(); } } } } 20 IX. Programa LineFollow em Código NXT-G Figura 5 - Ilustração do Programa Foward em Código NXT-G 21 X. Programa LineFollow em Código JAVA import lejos.nxt.Button; import lejos.nxt.LightSensor; import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; public class LineFollow { public static void main(String[] args) throws Exception { LightSensor ls = new LightSensor(SensorPort.S1); for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } while(Button.readButtons() == 0){ Motor.A.setPower(50); Motor.C.setPower(50); while(ls.readValue() < 35){ Motor.A.forward(); Motor.C.forward(); } Motor.A.stop(); Motor.C.stop(); if(ls.readValue() > 35){ Motor.A.setPower(20); Motor.C.setPower(20); 22 Motor.A.resetTachoCount(); Motor.C.resetTachoCount() Thread.sleep(200); while(Motor.C.getTachoCount() < 90 && ls.readValue() > 35){ Motor.A.backward(); Motor.C.forward(); } Motor.A.stop(); Motor.C.stop(); } if(ls.readValue() > 35){ Motor.A.setPower(20); Motor.C.setPower(20); Motor.A.resetTachoCount(); Motor.C.resetTachoCount(); Thread.sleep(200); while(Motor.A.getTachoCount() < 180 && ls.readValue() > 35){ Motor.A.forward(); Motor.C.backward(); } Motor.A.stop(); Motor.C.stop(); } if(ls.readValue() > 35){ Motor.A.setPower(20); Motor.C.setPower(20); Motor.A.resetTachoCount(); Motor.C.resetTachoCount(); Thread.sleep(200); while(Motor.C.getTachoCount() < 90 && ls.readValue() > 35){ Motor.A.backward(); Motor.C.forward(); } Motor.A.stop(); Motor.C.stop(); } } } } 23 XI. Classe FowardBehavior em Código JAVA package li4v4; import lejos.navigation.Pilot; import lejos.subsumption.Behavior; public class ForwardBehavior implements Behavior { private Pilot pilot; int driveSpeed; public ForwardBehavior(Pilot pilot, int driveSpeed){ this.pilot = pilot; this.driveSpeed = driveSpeed; } public boolean takeControl() { return this.pilot.getSpeed() > 0; } public void suppress() { this.pilot.stop(); } public void action() { this.pilot.setSpeed(this.driveSpeed); this.pilot.forward(); } 24 XII. Classe FindBestDirBehavior em Código JAVA package li4v4; import lejos.navigation.Pilot; import lejos.nxt.UltrasonicSensor; import lejos.subsumption.Behavior; public class FindBestDirBehavior implements Behavior { private Pilot pilot; private UltrasonicSensor ultrasonicSensor; private int stopMargin; private int rotationSpeed; private int rotationAngle; public FindBestDirBehavior(Pilot pilot, UltrasonicSensor stopMargin, int rotationSpeed, int rotationAngle){ this.pilot = pilot; this.ultrasonicSensor = ultrasonicSensor; this.stopMargin = stopMargin; this.rotationSpeed = rotationSpeed; this.rotationAngle = rotationAngle; } 25 ultrasonicSensor, int private int getDistance(){ this.ultrasonicSensor.ping(); try{ Thread.sleep(20); }catch(Exception e){ /*nothing to do*/ } return this.ultrasonicSensor.getDistance(); } public boolean takeControl() { return this.getDistance() < this.stopMargin && this.pilot.getSpeed() > 0; } public void suppress() { this.pilot.stop(); } public void action() { int bestAngle = -Math.round(this.rotationAngle/2); int bestDistance = 0; int distance; int initRotationCount; this.pilot.setSpeed(this.rotationSpeed); this.pilot.rotate(-Math.round(this.rotationAngle/2)); //wait until rotation is complete initRotationCount = this.pilot.getAngle(); this.pilot.rotate(this.rotationAngle, true); //return immediately while(this.pilot.isMoving()){ //rotation monitoring distance = this.getDistance(); if(distance > bestDistance && distance < 255){ bestAngle = initRotationCount - this.pilot.getAngle(); bestDistance = distance; } } this.pilot.rotate(-this.rotationAngle - bestAngle); } } 26 XIII. Classe EndDriveBehavior em Código JAVA package li4v4; import lejos.navigation.Pilot; import lejos.nxt.LightSensor; import lejos.subsumption.Behavior; public class EndDriveBehavior implements Behavior { Pilot pilot; LightSensor lightSensor; float startTime; public EndDriveBehavior(Pilot pilot, LightSensor lightSensor, float startTime){ this.pilot = pilot; this.lightSensor = lightSensor; this.startTime = startTime; } public boolean takeControl() { return (lightSensor.readValue() < 28 && this.pilot.getSpeed() > 0) || (System.currentTimeMillis() - startTime > 120000); } public void suppress() { /*nothing to do*/ } public void action() { this.pilot.setSpeed(0); } } 27 XIV. Classe Arbitrator3 em Código JAVA package li4v4; import lejos.subsumption.Behavior; /** * @see Behavior * @author <a href="mailto:[email protected]">Tiago Oliveira</a> * @version 1 01-06-2008 */ public class Arbitrator3 { private final int NONE = -1; private Behavior[] behaviorList; private boolean returnWhenInactive; /** * @param behaviorList an array of Behavior objects. * @param returnWhenInactive if <B>true</B>, the <B>start()</B> method return when no Behavior is active. */ public Arbitrator3(Behavior[] behaviorList, boolean returnWhenInactive){ this.behaviorList = behaviorList; this.returnWhenInactive = returnWhenInactive; } 28 /** * Same as Arbitrator3(behaviorList, true). * @param behaviorList An array of Behavior objects. */ public Arbitrator3(Behavior[] behaviorList){ this(behaviorList, true); } public void start(){ int currentBehavior = this.NONE; int maxPriority = this.behaviorList.length - 1; int highestActive; do{ highestActive = this.NONE; /*FIND HIGHEST PRIORITY ACTIVE BEHAVIOR*/ for(int i = maxPriority; i >= 0; i--){ if(behaviorList[i].takeControl()){ highestActive = i; break; } } if(currentBehavior != highestActive && currentBehavior != this.NONE){ /*SUPRESS CURRENT BEHAVIOR*/ behaviorList[currentBehavior].suppress(); } if(highestActive != this.NONE){ /*EXECUTE HIGHEST PRIORITY ACTIVE BEHAVIOR*/ behaviorList[highestActive].action(); } /*UPDATE CURRENT BEHAVIOR*/ currentBehavior = highestActive; } while(currentBehavior != this.NONE || !returnWhenInactive); } } 29 XV. Classe RobotDrive em Código JAVA package li4v4; import java.io.DataInputStream; import java.io.DataOutputStream; import lejos.navigation.Pilot; import lejos.nxt.LCD; import lejos.nxt.LightSensor; import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.Sound; import lejos.nxt.UltrasonicSensor; import lejos.nxt.comm.BTConnection; import lejos.nxt.comm.Bluetooth; import lejos.subsumption.Behavior; public class RobotDrive { private static final float WHEEL_DIAMETER = 5.5f; private static final float TRACK_WIDTH = 11.1f; private static final Motor LEFT_MOTOR = Motor.C; private static final Motor RIGHT_MOTOR = Motor.A; public static void main(String[] args) throws Exception { int stopMargin = 0; //stop margin int rotationAngle = 0; //rotation angle, for best direction search int rotationSpeed = 0; //rotational speed, when searching int driveSpeed = 0; //forward drive speed float startTime; //timer, for fitness calculation boolean btError = false; boolean endEvolution = false; 30 /*bluetooth connection*/ BTConnection btc; /*data input stream for bluetooth*/ DataInputStream is; /*data output stream for bluetooth*/ DataOutputStream os; /*drive control*/ Pilot pilot = new Pilot(WHEEL_DIAMETER, TRACK_WIDTH, LEFT_MOTOR, RIGHT_MOTOR); /*distance reading*/ UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S3); /*end-line detection*/ LightSensor lightSensor = new LightSensor(SensorPort.S1); Behavior forwardBehavior; Behavior shortDistanceBehavior; Behavior endDriveBehavior; Behavior[] behaviorList = new Behavior[3]; Arbitrator3 arbitrator; try{ Thread.sleep(20); }catch(Exception e){ /*nothing to do*/ } LCD.clear(); LCD.drawString("waiting", 0, 0); LCD.drawString("BT connection..", 0, 1); LCD.refresh(); /*wait for bluetooth connection*/ btc = Bluetooth.waitForConnection(); LCD.clear(); is = btc.openDataInputStream(); os = btc.openDataOutputStream(); while(!btError && ! endEvolution){ LCD.clear(); LCD.drawString("waiting values..", 0, 0); LCD.refresh(); if(is.available() >= 16){ 31 try{ driveSpeed = is.readInt(); rotationSpeed = is.readInt(); rotationAngle = is.readInt(); stopMargin = is.readInt(); LCD.clear(); }catch(Exception e){ btError = true; } if(!btError){ for(int i = 0; i < 3; i++){ Sound.beep(); Thread.sleep(700); } startTime = (float) System.currentTimeMillis(); forwardBehavior = new ForwardBehavior(pilot, driveSpeed); shortDistanceBehavior = new FindBestDirBehavior(pilot, ultrasonicSensor, stopMargin, rotationSpeed, rotationAngle); endDriveBehavior = new EndDriveBehavior(pilot, lightSensor, startTime); behaviorList[0] = forwardBehavior; behaviorList[1] = shortDistanceBehavior; behaviorList[2] = endDriveBehavior; arbitrator = new Arbitrator3(behaviorList); pilot.resetTachoCount(); arbitrator.start(); /*wait arbitrator to return*/ float distance = pilot.getTravelDistance(); float driveTime = ((float) System.currentTimeMillis() startTime)/1000; float fitness = 1000/(distance + driveTime); os.writeFloat(fitness); os.flush(); } } else if(is.available() == 1){ Sound.buzz(); endEvolution = true; } } btc.close(); } } 32 - XVI. Controlador do Robô a Partir do PC 33 34