You are here

Aula 7 - SOAR: Controlando o WorldServer3D

Atividade 1: DemoSOAR

    Depois de fazer o dowload do código fonte dos projetos e abrir no Netbeans, começamos a analisar o código do DemoSOAR através da classe SimulationSOAR.java.

Clique no thumbnail para ver em tamanho real.

   A classe NativeUtils, utilizada pela classe SimulationSOAR faz o gerencimento do carregamento do código nativo implementado em bibliotecas específicas para cada plataforma. Inicialmente, o classpath do java é apontado para a pasta atual da aplicação, então pegam-se as propriedades de sistema, como o nome do sistema operacional e a arquitetura do mesmo através do método System.getProperty(...). As bibliotecas nativas estão dentro do JAR, separadas em pastas relativas aos sitemas operacionais e arquitetura e são então copiadas de acordo com o SO/Arqutitetura atual, forma temporária para a pasta atual do projento, através do método NativeUtils.loadFileFromJar(...). O mesmo tipo de operação é feito para o carregamento de regras do SOAR. 

    Em seguida, uma instancia da classe SimulationTask é criada e configurada com os parametros relativos às regras do SOAR e do soarDebbuger. O loop principal da aplicação então é atingido, onde a cada 100 ms o método runSimulation() da instancia da classe SimulationTask é executado até que algum criterio de parada seja atingido.

SimulationTask

    Esta classe faz uso do WS3DProxy assim como fizemos na Atividade 4 da Aula 1. O WS3DProxy é instanciado no construtor da classe SimulationTask, e quando o método initializeCreatureAndSOAR(...) é chamado, uma criatura é criada no WorldServer3D e tem seu motor inicializado, sendo a instancia da criatura guardada no membro "c". Referências para o proxy e o mundo também são guardadas. Em outros métodos estas referências são utilizadas para submeter comandos para o WorldServer3D e para a criatura. Além dessas referências, outra classes que compõe o pacote WS3DProxy são utilizadas, como a classe CommandUtility. Lembrando que o WS3DProxy implementa uma conexão com o WorldServer3D através de sockets, que funcionam como canais de transmissão de dados entre as aplicações e permitem que uma terceira aplicação como o DemoSOAR possa interagir com os dados gerados e enviar comando a partir de decisões tomadas pelas regras no SOAR.

 Para completar a comunicação entre os aplicativos, a classe SimulationTask faz uso do SoarBridge, que também é inicializado no método initializeCreatureAndSOAR(...). O SoarBridge é responsável pela comunicação com o SOAR, em analogia ao WS3DProxy com o WorldServer3D. 

   Para entendermos como funciona a troca de dados entre o WorldServer3D e o SOAR através dos proxys decritos, devemos voltar ao loop principal da classe SimulationSOAR, onde vimos que o método runSimulaton() de SimulationTask é executado a cada 100ms. Analisando o método runSimulation, podemos ver que a cada iteração temos:

 

  • c.updateState(); O dados de estado como velocidade, rotação, posição da criatura são atualizados no proxy, através de informações requeridas ao WorldServer3D pelo proxy.
  •  List<Thing> v = c.getThingsInVision();  São obtidas os "objetos" que estão no campo de visão da criatura.
  • prepareAndSetupCreatureToSimulation(c, v); Neste método, as informações sensoriais obtidas anteriormente são carregadas em dois sensores, um de combustível e outro visual. Estes sensores por sua vez, são carregados em uma instancia da classe SimulationRobot que é por fim passada ao soarBridge através do método soarBridge.setupStackHolder(StakeholderType.CREATURE,simulationCreature);. Este último método então traduz os valores sensoriais vindos do WorldServer 3D para o formato esperado pelo SOAR.
  • soarBridge.runSimulation(); Executa uma rodada de simulação no SOAR, fornecendo como input ao SOAR os dados sensorias traduzidos anteriormente, disparando a execução do ciclo de proposição, seleção e aplicação de operadores até que a quiescencia seja atingida e comandos sejam então retornados para a aplicação na criatura em resposta a este processo.  
  • processResponseCommands(); Este método então executa o processamento da resposta enviada pelo SOAR no passo anterior através do SoarBridge e envia o comando para o WorldServer3D (e a criatura lá contida). Neste demo, os comando pode ser de MOVE, GET e EAT. 
   Portanto podemos dizer que a leitura de estado e ambiente do WorldServer3D é feita pelos dois primeiros métodos desta lista. O terceiro método faz a tradução para o formato dado pelo SOAR. O quarto método faz o envio e execução do ciclo básico de decisão do SOAR e por fim o quinto método pega as respostas do processo de decisão e aplica novamente sobre o WorldServer3D.
 
Funcionamento lógico do arquivo "soar-rules.soar":

   O arquivo contém as regras de decisão que quando selecionadas, geram os controles comandam o agente durante a simulação. São definidos os operadores:

  • WANDER - Quando selecionado faz com que o agente ande pelo ambiente, gerando um comando de MOVE no output-link, especificamente rotacionando a esquerda (com velocidade de rotação 2 na roda direita e 0 na roda esquerda).
  • SEE ENTITY WITH MEMORY COUNT / WITHOUT MEMORY COUNT - Armazena na memória objetos (entidades) detectados pelo sensor do agente, para os casos em que já há entidades na memória e quando a memoria está vazia.
  • MOVE FOOD - Quando selecionado (em condições em que há uma entidade de "food" na memória) gera um comando de MOVE para o ponto onde há a comida no output-link. Nesse caso há também um operador movefood*remove*food que remove o elemento da memória quando o mesmo já foi consumido.
  • EAT FOOD - Quando selecionado (em condições em que a entidade comida está próxima -- <30) gera um comando de EAT.
  • MOVE JEWEL - Semelhante ao MOVE FOOD, mas para entidades do tipo JEWEL.
  • GET JEWEL - Semelhante ao EAT FOOD, mas para entidades do tipo JEWEL.
  • AVOID BRICK - Quando selecionado (em condições em que há uma entidade BRICK na memória e com distancia pequena) gera um comando de move que tenta rotacionar o agente e evitar a barreira.

   São definidas as preferências para os operadores que competem entre si, levando em conta os diversos casos de entidades e impasses. Por exemplo, dá-se preferência ao operador see*entity ante os operadores de move*food e move*jewel. Em casos de impasse entre dois operadores iguais de movimento, como o move*jewel vs move*jewel, dá-se preferencia ao que tem a entidade mais próxima. Por fim, o operador de menor preferência é o WANDER.

   A partir dos operadores descritos, a operação lógica durante a simulação se dá da seguinte forma:

  1. Enquanto não há entidades na memória, o operador de WANDER é selecionado e atua girando o robo, para que o mesmo possa identificar possíveis identidades através de seu sensor visual.
  2. Quando uma entidade é captada pelos sensores, a mesma é adicionada à memória através da seleção dos operadores SEE ENTITY.
  3. Uma vez com entidades na memória os operadores de MOVE FOOD/EAT FOOD, MOVE JEWEL/EAT JEWEL passam a se selecionados e atuam sobre o agente, sempre respeitando as preferências por exemplo de buscando entidades mais próximos primeiro.
  4. Quando não há mais entidades na memória, volta-se ao primeiro item, repetindo este ciclo continuamente.

Atividade 2: Leaflet

   Para esta atividade foi necessário alterar o código fonte do DEMOSoar e do soar-rules.soar. O código fonte completo dos projetos pode ser encontrado aqui. 

   As principais alterações estão nas classes:

   SimulationRobot.java - Nesta classe foi adicionada a referência para a lista de LeaLefts da criatura. Assim, toda vez que o SimulationRobot é creado, a lista de lealefts é referenciada a partir da Creature original.

   SimulationTask.java - Nesta classe, o método runSimulation() foi alterado para atualizar a "Bag" que contem todas as informações sobre os elementos coletados pela criatura. Com esta atualização é possivel então atualizar as informações de itens coletados de cada um dos Leaflets da criatura. Este trabalho é feito entre a atualização de estado e a preparação da criatura para o próximo ciclo de simulação.

   SoarBridge.java - Nesta classe a alteração foi no método setupStackHolder(..) que passou então a incluir um elemento no working memory do soar, chamado LEAFLET para os elementos do tipo JEWEL e que estão ainda faltantes naquele momento em algum dos leaflets daquela criatura.

   soar-rules.soar - Por fim, o arquivo de regras foi alterado para levar em conta o elemento leaflet na memória e uma regra de preferencia foi adiconada para dar preferencia a movimentos em direção a joias que estejam marcadas com LEAFLET 1 quando comparados com joias marcadas com LEAFLET 0 (ou seja não estão em nenhum dos leaflets daquela criatura).

    Para testar o funcionamento, basta executar os programas, e para ajudar na visualização do objetivo, foi adicionado um critério de parada (em SimulationTask) quando todas as joias desejadas são coletadas. Uma exceção genéria é lançada apenas para interromper o simulador, além disso, pode-se acompanhar também os logs no console do java. 

Os arquivos do java webstart podem ser acessados por aqui:

DemoSOAR / WorldServer3D 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer