Atividade 1
O código do WorldServer3D modificado e o DemoSOAR foram
executados pelo Webstart na máquina local:
A clicar no link é feita a escolha de como o webstart será
executado, a figura 1 apresente esse processo.
Figura 1
Para executar os programas é necessário confirmar a definição
de segurança conforme figura 2.
Figura2
A figura 3 o print do WorldServer3D e do DEMOsoar já conectados
Figura
3
Depois que os arquivos-fonte dos dois programas e
da biblioteca WS3DProxy (lib de apoio para conectar o SOAR ao
WorldServer3D) foram baixados para a máquina local o código foi
compilado e executado no Netbeans.
A figura 4 demonstra o Netbeans com o código
fonte dos programas apresentados acima:
WorldServer3D
DemoSOAR
WS3DProxy
Figura
4
A figura 5 ilustra a explicação a seguir.
Figura 5
A
seguir foi feita leitura da classe SimulationSOAR e o método main,
a
primeira
tarefa
do programa é descobrir a pasta
atual
na classe NativeUtils
e
depois são utilizados os seguintes métodos:
System.getProperties().getProperty("os.name")
System.getProperties().getProperty("os.arch")
O primeiro método é usado para descobrir o sistema operacional que
está em uso. Já o segundo comando obtém o tipo de arquitetura do
computador.
Nesse teste obtivemos
os seguintes valores:
OS:Linux e Arquitetura:
amd64
Esses valores são
armazenadas em duas variáveis: String osName e String
osArch. As duas variáveis serão usadas para se obter as
bibliotecas que correspondem ao sistema operacional e a respctiva
arquitetura de hardware, e assim é utilizada a estrutura condicional
para determinar que arquivos irão ser carregados.
No meu caso, o meu
sistema operacional utilizado foi o Linux com arquitetura amd64, por
conta disso serão carregados os arquivos: /linux64/libSoar.so e
/linux64/libJava_sml_ClientInterface.so
Somente a partir desse ponto será carregado o
arquivo /soar-rules.soar que contem as regras do Soar. Em seguida é
definida a variável String soarRulesPath = "soar-rules.soar"
e depois a porta para o Debugger do soar: Integer
soarDebuggerPort = 12121; A
figura 6 ilustra esse pedaço do código-fonte.
Figura
6
Após carregar os arquivos e inicializar algumas
variáveis o programa entra no loop principal:
//Start enviroment data
SimulationTask simulationTask = new SimulationTask();
simulationTask.initializeEnviroment(Boolean.FALSE);
simulationTask.initializeCreatureAndSOAR(soarRulesPath,true,soarDebuggerPath,soarDebuggerPort);
// Run Simulation until some criteria was reached
Thread.sleep(3000);
while(true)
{
simulationTask.runSimulation();
Thread.sleep(100);
}
O método runSimulation() da classe simulationTask é
executado indefinidamente enquanto o programa está sendo executado.
Toda vez que é executado o método
runSimulation() serão realizadas as seguintes tarefas:
Atualizar o estado da criatura;
Obter os objetos “vistos” pela
criatura;
As informações: posição, pitch e
outras, da criatura e os objetos que ela capta pelos sensores são
traduzidos na linguagem do SOAR criando Working Memory Elements
(WME)
Assim será enviada essa estrutura de
informação gerada para o SOAR. No SOAR serão executadas as regras
do arquivo soar-rules.soar e a patir daí será obtida uma
resposta, em forma de comando de saída que será enviada novamente
ao programa cliente.
O programa cliente recebe a saída do SOAR
e processa a informação executando os comandos de resposta do SOAR
na criatura, este processo de executar os comandos muda o estado
atual da criatura e o processa começa de novo.
Em suma, a criatura
obtêm informação da sua localização e dos objetos que ela
consegue ver, organiza as informações em uma estrutura de dados que
o SOAR consegue entender e são enviados para seu processamento.
No SOAR as regras do
arquivo soar-rules.soar são executadas, sempre será
escolhido um operador e a regra de aplicação desse operador, os
comandos serão criados no elemento output-link do estado.
Após a seleção dos comandos a serem enviados ao cliente, o
programa cliente recebe os comandos de saída, provenientes do SOAR,
e executa as ações modificando o estado da criatura.
Método usado para
preparar a informação a ser enviada ao SOAR:
prepareAndSetupCreatureToSimulation()
Nesse passo é criado o
sensor visual e o sensor de constituível.
Após obter do objeto
simulationCreature os sensores disponíveis.
Após isso será
chamado o método setupStackHolder() da classe soarBridge
que é o incubido de criar a estrutura de dados para o SOAR a
partir da informação da criatura e os arredores.
No método setupStackHolder() é verificado se o tipo de
entidade é uma criatura e se for gera a seguinte estrutura de
Working Memory Elements, a figura 7 ilustra esses elementos.
Figura 7
Podemos concluir que existem tantos valores “ENTITY” quantos
elementos que possam ser vistos pela criatura.
Uma lista dos sensores
disponíveis pode ser obtida a partir de seguinte função:
creatureParameter.getSensorsEnabled()
A posição da criatura
pode ser obtida a partir das duas funções a seguir:
creatureParameter.getPosition().getX()
creatureParameter.getPosition().getY()
Para se obter o valor
do combustível e os elementos que podem ser vistos pela criatura no
mundo virtual é usada a função:
creatureParameter.getSensorHandler(<param>).getSensorReadings();
O parâmetro: <param> pode ser
SensorType.VISUAL ou SensorType.FUEL, no primeiro caso
será obtida uma lista com os objetos vistos pela criatura, e no
segundo caso o valor atual do combustível.
Existem três tipos de elementos no mundo virtual:
jewel (jóias) , food (comida) e brick (tijolos).
A execução da
simulação é feita através do método runSimulation() da
classe soarBridge.
Após a execução das
regras no SOAR é completada, o método processResponseCommands()
obtêm e processa a informação enviada desde SOAR.
A resposta do SOAR está
constituída por uma lista de comandos a serem executados no robô.
Existem três tipos de comandos: move (mover), get (obter)
e eat (comer). Os comandos são processados pelas funções:
processMoveCommand()
processGetCommand()
processEatCommand()
cada comando leva os argumentos necessários para
processar a instrução, tais como: direção de movimento,
velocidade, etc.
Programa
de regras de SOAR
No programa de regras
do SOAR o primeiro operador a ser proposto é chamado de WANDER
Este operador permite à
criatura se movimentar ao redor com uma velocidade VelR igual
a 2
Proposição:
# This operator will make the agent to walk ahead at the enviroment
# Propose*wander:
sp {propose*wander
(state <s> ^attribute state
^impasse no-change
^superstate <ss>)
(<ss> ^io.input-link <il>)
(<ss> ^superstate nil)
(<il> ^CREATURE <creature>)
(<creature> ^SENSOR.VISUAL <visual>)
-->
(<ss> ^operator <o> +)
(<o> ^name wander)}
Aplicação:
# Apply*wander:
# If the wander operator is selected, then generate an output command to it
sp {apply*wander
(state <s> ^operator <o>
^io <io>)
(<io> ^output-link <ol>)
(<o> ^name wander)
-->
(<ol> ^MOVE <command>)
(<command> ^Vel 0)
(<command> ^VelR 2)
(<command> ^VelL 0)}
Regra que elimina o comando caso ele esteja
concluído
# If the wander operator is selected,
# and there is a completed move command on the output link,
# then remove that command.
sp {apply*wander*remove*move
(state <s> ^operator.name wander
^io.output-link <out>)
(<out> ^MOVE <move>)
(<move> ^status complete)
-->
(<out> ^MOVE <move> -)}
O operador seeEntityWithMemoryCount
possibilita guardar na memória as entidades que a criatura pode ver
no mundo virtual, este operador é proposto se o agente já possui
alguma entidade na memória.
O operador
seeEntityWithoutMemoryCount realiza
o mesmo trabalho do operador seeEntityWithMemoryCount mas é
aplicado quando ainda não existe nenhuma entidade no agente.
Depois são declarados
os operadores de movimento em direção na comida (moveFood),
o operador de comer a comida (eatFood), o operador de ir em
direção as joias (moveJewel), o operador de pegar as joias
(getJewel) e o operador de evitar os tijolos (avoidBrick).
Após isso são criadas
as regras de controle e de preferência e as regras que resolverão
os conflitos.