You are here

c) Aula 7 - SOAR: Controlando o WorldServer3D

Aula 7 - SOAR: Controlando o WorldServer3D.

 

Objetivo:

Utilizar o Soar para controlar uma aplicação externa por meio da interface SML (SOAR Markup Language).
O sistema a ser desenvolvido será a mente artificial de um agente capaz de controlar o robô no ambiente WorldServer3D. O comportamento do robô será determinado pela estratégia e heurística adotada e implementada através da plataforma SOAR.

 

Relatório de Atividades:

 

 

Atividade 1:


Para esta atividade foi necessário baixar o novo projeto WordServer3D, atualizado para esta atividade, e os projetos DemoSOAR e WS3dProxy. O WS3DProxy é uma library de apoio, responsável pela comunicação com o WorldServer3D, enviando e recebendo comandos em objetos de alto nível. A atualização no WorldServer3D foi justamente a integração com esta interface de comunicação.
Os projetos foram abertos na IDE Netbeans:


O objetivo inicial era executar o DemoSOAR e verificar seu funcionamento. Mas aconteceu uma pequena confusão que seria interessante relatar:

1- Executando o DemoSoar: em "Propriedades" do projeto, ajustei a configuração para executar no modo "default", ou seja, através do código e sem o "Web Start". Executei o programa, porém, nada apareceu.


Não imaginei que o problema era portabilidade do projeto. Estava rodando na plataforma Windows e o projeto não tinha em sua biblioteca o arquivo sml.jar para a plataforma Windows, somente para LINUX. Fato que será mencionado novamente quando falarmos sobre o funcionamento da classe SimulationSOAR.java que sugere justamente esta portabilidade.

2- Executando o DemoSoar - Web Start: Tentei então executar com Web Start. Para tanto, configurei em "Propriedades" do projeto para executar com o Web Start. Na configuração da aplicação Web Start foi necessário ajustar a "Base de Código" para "Execução Local" e assinar a aplicação com uma "Keystore.key" gerada através do seguinte linha de comando no MSDOS: keytool -genkeypair -v -dname "cn=Seu Nome Completo, c=BR" -alias seualiassemespaco -validity 10000 -keystore ./keystore.key.

 
Aconteceu também um erro de compilação, mesmo antes destes ajustes, devido à existência do parâmetro "excludeFromCopy="${copylibs.excludes}"", no arquivo build-impl.xml, tag copylibs. A causa principal, provavelmente foi a versão utilizada no Netbeans, 7.4, conforme sugere esta página: https://netbeans.org/bugzilla/show_bug.cgi?id=231468 Este parâmetro foi retirado.
Então, o Web Start também não funcionou.

3- Trocando os arquivos sml.jar (LINUX -> WINDOWS): Com a orientação do professor, o principal problema foi então identificado e solucionado. O projeto do WordServer3D tinha o arquivo sml.jar para Window. O arquivo foi copiado para o DemoSOAR. Confusão desfeita, o projeto DemoSOAR passou a executar das duas formas.
 

Análise do Código DemoSOAR

Diagrama de Classe dos pacotes Simulation e SOARBridge - Projeto DemoSOAR:

javadoc do projeto DemoSOAR: index.html


Classe SimulationSOAR.java:

A classe SimulationSOAR.java pertence ao pacote SIMULATION e é a classe principal do projeto DemoSOAR, ou seja, é a classe que possui o método main e inicia toda a aplicação. Como classe principal executa as seguintes tarefas, pela ordem:
 

  • Inicializa o log da aplicação: atribui à variável "logger" a classe estática org.apache.log4j.Logger. A partir deste ponto, o log da aplicação pode ser alimentado através deste identificador.
  • Trata a portabilidade da aplicação: gerencia os recursos não puramente Java e dependentes de Sistema Operacional, para que sejam carregados em memória os mais adequados para o sistema corrente. Para tanto, utiliza a classe NativeUtils, definida pelo padrão Java Native Interface (JNI), e implementada no pacote SOARBridge, definindo uma série de métodos estáticos que dão suporte à identificação e localização de recursos em bibliotecas especificas da aplicação e ao carregamento em memória de arquivos e bibliotecas .jar.
    • SoarBridge.NativeUtils - static methods:
    • public static void setLibraryPath(String path)
    • public static void loadFileFromJar(String path).
    • public static void loadLibraryFromJar(String path)

    A classe SimulationSOAR utiliza a classe NativeUtils dentro do método main, antes de qualquer inicialização, no estabelecimento das condições de carregamento das bibliotecas. Através da classe System, o sistema operacional e sua arquitetura são identificados e atribuídos às variáveis osName e osArch que serão utilizados nas clausulas condicionais para carregamento dos arquivos e bibliotecas, como segue:
    • Simulation.SimulationSOAR - O.S. identification:
    • String osName = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
    • String osArch = System.getProperty("os.arch").toLowerCase(Locale.ENGLISH);

    Java Native Interface(JNI) é um padrão de programação que permite que código Java executando em uma máquina virtual Java (JVM) chame ou seja chamado por aplicações nativas (programas específicos para uma plataforma de hardware e sistema operacional) e bibliotecas escritas em outras linguagens, tais como C, C++ e assembler. O JNI habilita programadores a escrever métodos nativos para tratar situações em que uma aplicação não pode ser escrita inteiramente na linguagem Java, isto é, quando a biblioteca padrão de classes Java não suporta bibliotecas ou características específicas da plataforma. A ideia é que toda classe ou recurso não puramente JAVA e que dependa de características específicas do Sistema Operacional utilizado, seja selecionada e carregada a partir da classe NativeUtils.
    Portanto, a classe SimulationSOAR.java utiliza NativeUtils para selecionar as bibliotecas mais adequadas dependendo do Sistema Operacional, e faz isto de forma clara e eficiente. Porém, comprovado por experiência própria, como já mencionado no início deste relatório, esta seleção acabou não considerando a lib SML.jar como dependente de sistemas operacionais. Portanto, o projeto DemoSOAR, até o momento, acaba falhando em sua portabilidade por causa deste detalhe. Como "workaround" podemos simplesmente substituir o arquivo sml.jar (para LINUX) pelo dedicado ao sistema WINDOWS. Provavelmente trata-se de algo que possa ser solucionado rapidamente, adicionando os arquivos sml.jar nas pastas dos respectivos sistemas operacionais e a condição de utilização a partir de NativeUtils na classe SimulationSOAR.java.

  • Carrega soar-rules.soar: a classe NativeUtils é utilizada para carregar o arquivo que contêm as regras SOAR que controlam o comportamento do robô do WorldServer3D, ou seja, a "mente" do nosso agente.
    NativeUtils.loadFileFromJar("/soar-rules.soar");
  • Cria instância da classe SimulationTask e inicializa parâmetros SOAR (regras e debugger): A classe SimulationTask é responsável por criar a instância da interface de comunicação WS3DProxy, inicializar a criatura e o SOAR, de acordo com o arquivo de regras (soar-rules.soar) e com a localização do SoarDebugger e porta de comunicação.

  • Loop de Execução até que o objetivo final seja alcançado: Após as inicializações, a classe SimulationSOAR inicia o "looping" de execução,através do método runSimulation() da classe SimulationTask, que é executado até que os critérios de sucesso sejam satisfeitos. Nesse método é feita uma comunicação com o SOAR e, por isso, para que haja tempo suficiente para a troca de informações, usou-se o código Thread.sleep(100); para retardar o início da próxima iteração do loop.


Classe SimulationTask.java:
A figura abaixo ilustra a relação entre a classe SimulationTask, a interface de comunicação SOARBridge com a plataforma SOAR e a interface de comunicação WS3DProxy com o ambiente WorldServer3D.


Entre as inicializações da classe SimulationTask é criada uma nova criatura e um novo ambiente WorldServer3D. Isto é feito através de comandos enviados para o WorldServer3D através do proxy. Dentro do método runSimulation, o status da criatura (c) é atualizado e estas informações são passadas para a plataforma SOAR através da interface BridgeSOAR. Como mostra o método abaixo:


Existe uma coordenação entre os ambientes SOAR e WorldServer3D, promovida pela aplicação DemoSOAR.
As duas interfaces de comunicação, WS3Dproxy e SOARBridge utilizam objetos de classes específicas para transitar suas informações, do mundo "real", WorldServer, para a mente, SOAR:

A interface WS3Dproxy é utilizada pelas classes do pacote Simulation para as criações iniciais e atualização dos status do ambiente e da criatura em objetos de informação que serão passados para a plataforma SOAR através do SOARBridge (método soarBridge.runSimulation() em SimulationTask.runSimulation). Por sua vez, a plataforma SOAR processa os novos status do ambiente e da criatura e determina a próxima ação/comando. Esta ação chega como informação à classe SimulationTask, dentro do looping, através do método processResponseCommands().
O processamento destes comandos são executados no ambiente WorldServer3D através a classe ws3dproxy.CommandUtility.

 

 

 

Atividade 2:


Cada criatura no WorldServer3D possui um "leaflet", ou seja, uma meta na obtenção de jóias. Modifique o programa DemoSOAR (e também o soar-rules.soar), de tal forma que ele leve em consideração o leaflet de cada criatura para o controle da criatura.

O Projeto completo, com os códigos e modificações mencionadas pode ser encontrado aqui:
Proj. DemoSOAR jrborelli
O executável em WebStart: SOAR_launch.jnlp
O executável do WS3D:WS3D launch

 

Regras SOAR:

Como mostrado acima, o método SoarBridge.setupStackHolder() envia para a plataforma SOAR dados obtidos do "WorldServer3D", utilizando métodos da interface "sml", criando e atualizando elementos da memória de trabalho do agente.

A classe sml.Agent é declarada como: public static interface OutputEventInterface, e possui métodos que adotam o seguinte “template”:

Agent.CreateIdWME(<elemento-pai>, <"nome-novo-elemento">): cria um novo elemento ID na memória de trabalho

Agent.CreateFloatWME(<elemento-pai>, <"nome-novo-elemento">, <valor-novo-element>): cria um novo elemento FLOAT na memória de trabalho

Dentro do método SoarBridge.setupStackHolder() estes métodos da classe Agent que constroem a “work memory” são utilizados segundo os parâmetros extraídos do objeto de informação recebido. A figura abaixo ilustra um trecho deste código:

Desta forma, a seguinte estrutura de dados é criada na Memória de Trabalho SOAR:

<s> ^input-link <il>
          <il> ^CREATURE <c>
                     <c> ^MEMORY <cm>
                            ^PARAMETERS <cp>
                            ^POSITION <cpos>
                            ^SENSOR <csens>
                                                      <cp> ^MINFUEL 400
                                                              ^TIMESTAMP CURRENT-TIME
                                                      <cpos> ^X X
                                                                  ^Y Y
                                                      <csens> ^FUEL FUEL-LEVEL
                                                                    ^VISUAL <csvisual>
                                                                                    <csvisual> ^ENTITY <entity-1> ... <entity-n>
                                                                                      <entity-*> ^DISTANCE GEOMETRIC-DISTANCE
                                                                                                                       ^X X1
                                                                                                                       ^Y Y1
                                                                                                                       ^X2 X2
                                                                                                                       ^Y2 Y2
                                                                                                                       ^TYPE CATEGORY
                                                                                                                       ^NAME NAME
                                                                                                                       ^COLOR COLOR
 

As regras SOAR estão descritas em um arquivo com extensão “.soar”, dentro do pacote default do projeto DemoSOAR, como mostra a figura a baixo:

 

 

Na versão original, o arquivo de regras SOAR propõe 3 tipos de operadores:

 

Para os casos de conflito entre as ações, o arquivo soar-rules.soar vem originalmente com as atribuições de preferência descrita abaixo. Os termos entre chaves são os de maior preferência, conforme programado no arquivo. Estas clausulas de atribuições de preferência são interessantes caso se deseje modificar o comportamento do agente. 

##################  OPERATORS PREFERENCES AND IMPASSE SOLVE  ###################
 
##### SEE AND PROCESS ENTITY:
 
# Move Jewel or Move Food vs [See Entity]
 
# See Entity With Memory vs [Avoid Brick]
 
# See Ententy Without Memory Preferences - indiferente
 
 
##### JEWEL:
 
# [Move Jewel] vs Get Jewel
(<o2> ^name << moveJewel moveFood >>)
 
# Get Jewel vs [Avoid Brick]
 
# Move Jewel vs Move Jewel Preferences
menor distância
 
# Get Jewel vs Get Jewel Preferences
menor distância
 
 
##### FOOD:
 
# Move Food vs [Eat Food]
 
 
# [Eat Food] vs Avoid Brick
 
 
# Move Food vs Move Food Preferences
menor distância
 
# Eat Food vs Eat Food Preferences
menor distância
 
 
##### FOOD vs JEWEL:
 
# [Move Food] vs Move Jewel Preferences - Move Food Wins
CREATURE.SENSOR.FUEL baixo
 
# Move Food vs [Move Jewel] Preferences - Move Jewel Wins
CREATURE.SENSOR.FUEL nível a cima de baixo. 
 
 
##### BRICK:  
 
# Avoid Brick vs Avoid Brick Preferences
menor distância
 
# [Avoid Brick] vs Move Jewel vs [Move Food Preferences with element in memory]
evitar colisão com a parede a mover-se em direção a um objeto armazenado na memória 
 
 
##### WANDER:
 
# Wander Preferences
evita andar pela arena na falta de um objetivo
 
As regras não serão colocadas neste relatório, mas podem ser verificadas no arquivo soar-rules.soar.
 
 
Leaflets:
Os leaflets são gerados randomicamente no WS3D. Talvez fosse mais interessante externalizar uma interface que permitisse determinar leaflets específicos para cada criatura. Cada leaflet define uma coleção de jóias, de diferentes cores, que devem ser capturadas e entregues no "delivery point".
A figura abaixo mostra a janela "Knapsack and Score" da criatura 0.
 
 
 
Como já mencionado, o pacote SoarBridge tem as classes responsáveis por traduzir informações do mundo WS3D para o simulador SOAR.
Com o estabelecimento de novos parâmetros para determinação de novos objetivos e regras de comportamento, originados dos leaflets de cada criatura, vamos ter que:
 
- editar o arquivo de regras soar, soar-rules.soar, criando novas regras de comportamento que possibilitem ao atendimento dos objetivos relacionados ao leaflets.
- editar especialmente a classe SoarBridge.java, no método "setupStackHolder" que cria a estrutura de dados na memória de trabalho "WME" do SOAR, acrescentando estruturas referentes ao leaflets para cada criatura.  

A classe SimulationTask.java, da mesma forma como fez para a criatura e sensores, deve ser modificada para extrair do WS3D informações sobre os Leaflets, como ilustra a figura:

 

Na classe SoarBridge.java, o método “setupStackHolder” se encarrega de criar a estrutura de dados referentes aos Leaflets na memória de trabalho (WME) do SOAR, conforme ilustrado abaixo:

 

Cenário de Aplicação - Memória Episódica:

É interessante notar a possibilidade de construção de Memória Episódica em todas as arquiteturas de sistemas cognitivos que veremos na disciplina IA006.

O que se pretende é a construção simplificada de relatos indexados no tempo que permitam a um dos agentes a reanálise destes dados e estimar uma situação que possa completar estes relatos de forma lógica, segundo seu próprio ponto de vista, ou seja, sua Memória Episódica.

No caso da arquitetura SOAR, o artigo “Extending the Soar Cognitive Architecture”, escrito por John Laird em 2008, pode ser considerado uma importante referência, conforme comprova a figura: 

Neste ponto, decido que pretendo perseguir os mesmos objetivos para todas as arquiteturas a serem experimentadas nesta disciplina: criar a estrutura básica de Memória Episódica e viabilizar sua utilização para tomada de decisões – no caso de nosso contexto, a ser explicado a seguir, viabilizar ao agente estimar a situação mais provável que completa seu conhecimento “histórico” dos eventos na arena de forma lógica e aceitável.

 

Nosso cenário:

Vamos implementar a arena de forma a permitir a presença de pelo menos três robôs. Estes robôs terão o papel clássico proposto no WS3D de caminhar pela arena e recolher alimentos e objetos desejados, segundo seus “leaflets”.

A figura nova na arena, que utilizará a memória episódica, é um robô investigador, que chamaremos “Detetive”.

O Detetive, em sua primeira versão, ficará posicionado no centro da arena, girando sempre no mesmo sentido e velocidade. Sua visão atuará como um “scanner”, ou radar, e irá construir sua memória epsódica com relatos de objetos e alimentos existentes, suas posições e a localização de cada robô, naquele instante.

O “instante”, ou “timestamp”, nesta implementação torna-se um artefato, na verdade um conceito, extremamente importante. Todos os relatos na memória episódica serão indexados através do “timestamp”, adaptado para esta funcionalidade.

O objetivo inicial do Detetive será estimar qual dos robôs capturou um objeto específico, localizado em uma posição especifica. Baseado em sua memória episódica, que traz dados sobre a localização de cada robô, o Detetive analisará no timestamp anterior e mais próximo do instante da captura do objeto qual robô se encontrava mais próximo e, portanto, teria maior probabilidade de ter atuado no evento.

Em uma versão mais avançada, o Detetive terá como objetivo estimar o “leaflet” de cada robô na arena e o jogo, na verdade, torna-se um desafio de qual arquitetura/estudante é capaz de proporcionar os melhores resultados neste sentido.

Caso a configuração de Detetive localizado no centro da arena não seja uma opção que proporcione a visão necessária para se implementar o cenário, pretende-se alterar esta proposta colocando um Detetive no centro de cada quadrante, compartilhando a mesma memória episódica.

 

 

 

Alguns Conceitos [http://www.human-memory.net/types_episodic.html]:

Memória Episódica é relacionada a eventos (tempo, lugares, emoções associadas, e elementos contextuais, como: quem, o quê, quando, onde, “porque) que pode ser explicitamente declarada. É a coleção de experiências pessoais passadas que ocorreram em um determinado tempo e lugar. Permite “voltar” no tempo, ato de  lembrar, e reanalisar o evento ocorrido com objetivos diversos como: emocionais, de aprendizado, tomada de decisão futura e julgamento.

A Memória Semântica, por outro lado, é um registro mais estruturado de fatos, significados, conceitos e conhecimento sobre o mundo externo que adquirimos. Refere-se ao conhecimento geral, partilhada com outros e independente de experiências pessoais e do contexto temporal/espacial em que foi adquirida. Inclui coisas como: tipos de alimentos, capitais, costumes sociais, funções de objetos, vocabulário, compreensão da matemática, etc. Grande parte da memória semântica é abstrata e relacional, associada com o significado de símbolos verbais.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer