You are here

Aula 7 - Controlando o WorldServer3D com o SOAR

 

Controlando o WorldServer3D com o SOAR

 

    - ATIVIDADE 1 -

    Foram disponibilizados os arquivos do WorldServer3D (jnlp e código fonte), DemoSoar (jnlp e código fonte) e WS3DProxy (código fonte).

    O WorldServer3D já havia sido estudado e uma primeira experiência feita através do desenvolvimento do controlador manual deste ambiente logo na primeira aula. Neste desenvolvimento podemos estudar como funciona a biblioteca WS3DProxy que permitiu a comunicação via Sockets do Controlador Manual e da Criatura no ambiente WS3D.

    Aqui como primeira atividade sugerida pelo Prof.Ricardo Gudwin está o estudo do DemoSoar e logo de imediato nos é feita a seguinte pergunta: "Como o carregamento de arquivos com código SOAR é implementado no DemoSoar?".

    As regras SOAR (ou arquivos com extensão SOAR) estão enpacotadas dentro do arquivo DemoSoar.jar e são carregadas utilizando o método estático loadFileFromJar da classe NativeUtils. Este trecho é facilmente encontrado nas linhas 71 e 72 do arquivo SimulationSOAR.java.

    Outro ponto que o Prof.Ricardo Gudwin pede que seja explicado refere-se ao looping principal de simulação da DemoSOAR.

    O próprio código fonte nos dá uma excelente pista sobre esta pergunta, pois este laço encontra-se entre as linhas 79 a 81 do arquivo SimulationSOAR.java. A Classe SimulationTask implementa a simulação e é onde as "SOAR Productions" são carregadas, enquanto que o método runSimulation() executa a simulação. A cada 100 milisegundos um novo ciclo se inicia, estando esta instrução dentro do while principal. Vale lembrar que este looping está dentro de uma estrutura try-catch, logo, caso algo de errado ocorra, uma mensagem "Error in soar bridge" é exibida.

    Um estudo mais detalhado na classe SimulationTask nos mostra que nela o ambiente do WorldServer3D é inicializado, a criatura é inicializada no ambiente e as regras SOAR são carregadas. Durante a execução da simulação em si, as informações na mente da criatura virtual são atualizadas e decisões são tomadas pelo SOAR, tomando por base dados sensoriados pelo agente, fazendo com que o este atue efetivamente no mundo virtual.

    A classe WS3DProxy já foi estudada anteriormente, sendo ela a responsável pela comunicação, via Sockets, com o ambiente do WorldServer3D.

    No tocante a classe SoarBridge, logo no seu construtor são passadas as informações relevantes para estabelecer a comunicação com o depurador, bem como da instância do SOAR a ser configurada.

    O controle da criatura no mundo virtual é feito basicamente por 2 métodos, ambos na classe SimulationTask : o método prepareAndSetupCreaturaToSimulation() implementa a atualização do ambiente e o método processResponseCommands() executa as ações no mundo virtual.Cabe salientar que a execução da simulação pelo SOAR é feita pelo método runSimulation() da classe SoarBridge.

    Explicar:Acesse o conteúdo do arquivo de regras SOAR: soar-rules.soar e tente entender seu funcionamento. Explique o princípio lógico de seu funcionamento

    Em relação ao conteúdo do soar-rules.soar cabe destacar as seguintes produções ( - Soar Productions):

      Passear pelo ambiente:
    • propose*wander
    • apply*wander
    • apply*wander*remove*move
      Atualização do campo de visão:
    • propose*see*entity*with*memory*count
    • apply*see*entity*with*memory*count
    • propose*see*entity*without*memory*count
    • apply*see*entity*without*memory*count
      Movimentação para a comida:
    • propose*move*food
    • apply*move*food
    • apply*moveFood*remove-move
    • apply*moveFood*remove*food
      Comer a comida:
    • propose*eat*food
    • apply*eat*food
    • apply*eatFood*remove-eat
      Movimentação para a jóia:
    • propose*move*jewel
    • apply*move*jewel
    • apply*moveJewel*remove-move
    • apply*moveJewel*remove*jewel
      Pegar a jóia:
    • propose*get*jewel
    • apply*get*jewel
    • apply*getJewel*remove-get
      Desviar dos bricks:
    • propose*avoidBrick
    • apply*avoidBrick
    • apply*avoidBrick*remove*entity*memory
    • apply*avoidBrick*remove-move
      Preferências:
    • moveJewel*seeEntity*preferences
    • avoidBrick*seeEntityWithMemory*preferences
    • seeEntity*without*entity*preferences
    • moveJewels*getJewel*preference
    • getJewel*avoidBrick*preference
    • moveJewel*moveJewel*less*distance
    • getJewel*getJewel*preferences
    • moveFood*eatFood*preferences
    • eatFood*avoidBrick*preferences
    • moveFood*moveFood*preferences
    • eatFood*eatFood*preferences
    • moveFood*moveJewel*preferences*moveFoodWins
    • moveFood*moveJewel*preferences*moveJewelWins
    • avoidBrick*avoidBrick*without*move*jewel*preferences
    • avoidBrick*moveJewel*moveFood*preferences
    • wander*preferences

    Olhando a simulação que o Professor Ricardo disponibilizou via webstart, analisando os códigos do SOAR e java do DemoSoar, podemos facilmente notar que a lógica da criatura é sempre pegar joias, alimentando-se quando seu nivel de energia está abaixo de um determinado patamar. Então, pela lógica, o primeiro operador que é proposto e aplicado é o "wander" para que a criatura fique vagando pelo ambiente. Através do sensor de visão, quando novos objetos são detectados, novos operadores são propostos. Se forem jóias, operadores relativos à jóias são aplicados; se for comida, os operadores relativos a comidas são propostos. Como são muitos objetos diferentes sendo constantemente apresentados, impasses são criados e resolvidos através das preferencias que foram pré-estabelecidas. O SOAR toma a decisão e escolhe o operador mais adequado àquela situação. O nível da comida é que irá fazer toda diferença, porque entre pegar uma jóia e comer quando o nível de energia estiver baixo, a criatura irá sempre preferir comer.

    --------------

    - ATIVIDADE 2 - Inclusão dos leaflets no controle da criatura

    A primeira dúvida que vem à mente é: o que são leaflets? Onde esses leaflets são encontrados ?

    A tradução do termo em inglês "leaf" significa folha. A tradução de "leaflet" significa folheto. Computacionalmente a definição de Leaflet está na classe CommandUtility do WS3DProxy. Lá temos que "Leaflets is a list of crystals to be collected and delivered at the DeliverySpot", ou seja, um folheto contendo a lista de cristais que a criatura tem que coletar e entregar no "DeliverySpot". Em síntese: uma meta a ser cumprida! Cada cristal é recolhido dentro de um saco e cada entrega no DeliverySpot faz com que a criatura receba um pagamento

    Como pista oferecida pelo looping principal da DemoSOAR, temos as instruções InitializeEnviroment e InitializeCreatureAndSoar da classe SimulationTask. Analisando o código desta classe logo chama a atenção o método processReponseCommands, pois lá temos as ações que a criatura pode acionar, sendo caracterizada pelos tipos MOVE, GET, EAT.... aqui foi criado o tipo DELIVER (ou seja, agora a criatura terá uma ação própria para entregar) e, também seguindo o modelo oferecido pelo próprio código da classe, foi criado o método processDeliverCommand. Depois, ainda analisando o looping principal do DemoSOAR, temos como instrução principal simulationTask.runSimulation() que, por sua vez, também nos remete a classe SimulationTask. Tendo em vista a relevância logo inicialmente apontada desta classe, uma analise mais detalhada foi feita.

    Logo no construtor da classe tive que alterar o comando que faz a conexão com o WorldServer3D, na linha 43, para proxy = new WS3DProxy("localhost",4011) para fazer corretamente a conexão. Depois no método prepareAndSetupCreatureToSimulation (pois este é o método responsável por ajustar todos os parametros funcionais da criatura) foram introduzidos códigos para criar a lista de Leaflets e também para ajustar o DeliverySpot da criatura, sendo respectivamente os seguintes comandos adicionados: simulationCreature.setLeafletList(creature.getLeaflets()) e simulationCreature.setDSpot(w.getDeliverySpot()) nas linhas 145 e 146 respectivamente, fechando assim as alterações nesta classe. Para fechar as observações relativas a esta classe, cabe salientar que seguindo o próprio modelo do código base, foi criada a classe SoarBridge.SoarCommandDeliver contendo todo código para tratar este novo comando. Ainda nesta classe, é fácil notar que a classe SoarBridge e a classe WS3DProxy são fundamentais, sendo para lá direcionados os esforços de análise.

    Na classe SoarBridge, por sugestão do Prof.Ricardo, imediatamente foi feita uma alteração no construtor da classe na linha de onde o Debugger Soar é chamado (linha 95) passando a ser escrita assim: agent.SpawnDebugger(soarDebuggerPort, "lib/debugger-linux64/SoarJavaDebugger.jar"). Aqui também foi logo destacado o tratamento para as ações possíveis do agente. Seguinte o modelo adotado na classe SimulationTask, foi feita a alteração no método getReceivedCommands() incluindo o case DELIVER no switch principal do método. O código foi criado segundo o padrão adotado nos outros cases.

    Também foi fácil notar nesta classe que o método setUpStackHolder é o responsável por criar uma nova criatura no WorldServer3D, sendo aqui todos os parâmetros da criatura ajustados. Restava-me saber onde e quando ele era chamado. Fazendo a devida análise, de novo, retornamos a classe SimulationTask no método prepareAndSetupCreatureToSimulation, retorno este que confirmou a importância deste método na criação de uma nova criatura no mundo virtual. Neste método anteriormente já havia feito alterações para criação da Leaflet e do DeliverSpot, cabendo agora a devida alteração no código do SetupStackHolder() para tratar as Leaflets, alteração esta feita na linha 177 e depois nas linhas 267 até 317 da classe SoarBridge. Na declaração de variáveis globais da classe, foram criados os identificadores creatureLeaflets e DSpot nas linhas 48 e 49, respectivamente, pois lá estavam declaradas as "Entity Variables".

    Um outro método que sofreu alterações na classe SoarBridge foi o clearEntitiesToNextSimulation(), pois foi fácil notar seu papel. Aqui instruções para destruir os Leaflets, o DeliverySpot e demais variáveis.

    Como consequência também da alteração na classe SimulationTask a classe SimulationRobot também foi alterada, sempre seguindo um padrão de código sugerido pelo próprio software original. Nesta classe foram adicionados os métodos setLeafletList(), getLeafletList(), setDSpot(), getDSpot() pois nesta classe estavam sendo ajustados o posicionamento da criatura e, curiosamente, havia uma variável do tipo Vector (que foi descontinuado, por isso substituí para List) chamada LeafletList que não estava sendo usada.

    Alterações no arquivo soar-rules.soar

    Confesso que aqui foi a parte mais difícil para mim e uma boa parte do atraso na entrega da tarefa deveu-se a isto. Coube, logo inicialmente, a análise no código do DemoSOAR dos comandos importados da classe sml.java, pois nesta classe estão todos os comandas da "Soar Markup Language" responsável pela integração java-soar. Para facilitar também incluí mensagens no arquivo soar usando o comando write (crlf) como nos ensinou o tutorial 1 do Soar na página 38. Uma outra boa fonte de consulta foi o "SML Quick Start Guide" no site do próprio SOAR. Os exemplos foram bem ilustrativos e ajudaram muito a entender o código java da aplicação DemoSOAR.

    "WME" é a abreviatura para "Working Memory Element". A Working Memory no SOAR é o local onde estruturas que armazenam valores temporários estão alocadas. No código java da classe SoarBridge identificamos facilmente os comandos CreateIdWME, CreateIntWME, CreateFloatWME, CreateStringWME, DestroyWME, todos para criar e destruir elementos na memória de trabalho do SOAR. As variáveis que estes comandos usam são todas do tipo Identifier e são declaradas logo no construtor da classe. Essas variáveis do tipo Identifier são a tradução no código java daquilo que o SOAR Manual nos ensina na página 33 e 34 onde o capítulo 3.1 intitulado "Working Memory".

    Esse entendimento da interação com a memória de trabalho do SOAR via SML é importante pois é a partir dela que todo resto acontece, como tivemos a oportunidade de aprender estudando os tutorais do SOAR.

    Aqui também cabe a observação no tocante à carga das bibliotecas SOAR pelo programa DemoSOAR. Na classe SimulationSoar, do pacote Simulation do DemoSOAR logo de cara observamos o teste que identifica em qual sistema operacional o programa está rodando. Aqui através do comando loadFileFromJar() da classe NativeUtils (pacote SoarBridge) as bibliotecas típicas para cada SO são carregadas. É também através deste mesmo comando que o arquivo "soar-rules.soar" é carregado.

    Feitas essas considerações e estudos iniciais, parti então para as modificações do arquivo soar-rules.soar. Vale a seguinte observação em relação às Soar Productions elencadas na atividade 1:

    • Conjunto "Wander" - faz com que a criatura atualize seu campo de visão, passeie pelo ambiente, tendo por fim seu respectivo "destrutor".(Propose*wander; Apply*wander; apply*wander*remove*move);
    • Conjunto "See*entity" - faz com que a criatura armazene, com ou sem contador, na sua memória algumas entidades (vide definição acima). (Propose*see*entity*with*memory*count; apply*see*entity*with*memory*count; Propose*see*entity*without*memory*count; apply*see*entity*without*memory*count);
    • Conjunto "Move ... (food / jewel)" - faz com que a criatura movimente-se para a comida/jóia, contendo seus respectivos destrutores.(Propose*move*food; Apply*move*food; Apply*moveFood*remove-move; apply*moveFood*remove*food; Propose*move*jewel; apply*move*jewel; apply*moveJewel*remove-move; apply*moveJewel*remove*jewel);
    • Conjunto "Eat/Get ... (food/jewel) - leva a criatura a alimentar-se ou pegar uma jóia, tendo seus respectivos destrutores após a ação ter sido executada.(Propose*eat*food; Apply*eat*food; Apply*eat*remove-move; Propose*get*jewel; Apply*get*jewel; Apply*get*remove-move;);
    • Conjunto "Brick" - são Soar Productions que fazem a criatura não se chocar contra obstáculos. (Propose*avoid*brick; Apply*avoidBrick; apply*avoidBrick*remove*entity*memory; apply*avoidBrick*remove-move);
    • Conjunto de Preferências e Impasses - são Soar Productions que resolvem impasses (para uma maior leitura acerca de impasses vide "SoarManual.pdf capítulo 2.6")
    Preferi organizar o entendimento assim pois fica mais fácil para identificar qual modelo seguir a fim de, primeiro, informar a existência de Leaflets ao SOAR; segundo, contabilizar as jóias; terceiro, entregar a Leaflet no DeliverySpot.

    A primeira modificação feita foi a inclusão das ações da criatura nas Soar Productions onde só constava a ação padrão anteriores (EAT, MOVE e GET), a saber : apply*wander*remove*move, Apply*moveFood*remove-move, Apply*eat*remove-move, Apply*get*remove-move, Apply*avoidBrick*remove-move . Outra modificação foi tirar o delimitador "< 7" da "Propose*see*entity*with*memory*count".

    De resto, dentro do arquivo soar-rules.soar, tomando por base os códigos das outras regras e exemplos disponíveis, regras para contar as jóias (decrementando e incrementando o contador geral), para entregar os Leaflets e as regras de preferência e solução de impasses foram criadas, sempre tomando por base o código existente no próprio código original do "soar-rules.soar", bem como exemplos de outros colegas e exemplos nos tutorias do SOAR.

    Alterações no WorldServer3D e WS3DProxy

    Não houveram alterações no código destes programas.

    WebStarts e códigos fonte

    Seguem abaixo os links para os WebStarts do WorldServer3D (é o mesmo arquivo jnlp disponibilizado pelo Prof.Ricardo> e do DemoSOAR, bem como o link para o arquivo compactado dos source codes java alterados no DemoSOAR:

  • Arquivo WebStart do WorldServer3D. Link aqui
  • Arquivo WebStart do DemoSOAR (java 7). Link aqui
  • Source code DemoSOAR (java 7). Link aqui

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer