You are here

Aula 10 e Aula 11

Aula 10 - Clarion 3: Controlando o WorldServer3D

 

Objetivo

O objetivo da aula de hoje é utilizar a arquitetura cognitiva Clarion para controlar uma criatura artificial no WorldServer3D, de modo análogo ao que foi feito com o SOAR. Para tanto, é necessário que entendamos o funcionamento do Clarion, e desenvolvamos uma instância da arquitetura Clarion para controlar a criatura.

Atividade

A proposta desta atividade é desenvolver um sistema de controle (uma mente artificial) para a criatura do WorldServer3D, utilizando o Clarion. Nosso desafio será semelhante ao desafio que foi proposto na implementação com o SOAR. A criatura deve obter sua meta de aquisição de jóias a partir de seu "leaflet", e buscar de maneira mais rápida possível cumprir a busca de jóias que lhe foi delegada. Para testar a capacidade da criatura, dois testes são propostos:

  • Teste 1: A criatura deve buscar todas as jóias designadas em seu leaflet e deve parar depois disso.
  • Teste 2: Duas criaturas devem competir para buscaras jóias que lhes foram delegadas. A primeira delas será a criatura com o controlador desenvolvido em SOAR na aula 7. A segunda será a criatura com o controlador usando o Clarion.

Para que eu possa fazer os testes do sistema de vocês de maneira rápida e eficiente, peço que me disponibilizem on-line dois arquivos ZIP diferentes:

  • Um arquivo com os executáveis do controlador, de tal forma que eu apenas desempacote a aplicação utilizando o mono. O teste será realizado em ambiente Linux 64 bits, como no laboratório.
  • Um arquivo com toda a árvore de código fonte necessária à recompilação do controlador, caso seja necessário.

Além disso, no relatório da atividade deve ser descrita a lógica da solução, para que eu compreenda seu funcionamento.

Dicas para a Implementação

Antes de mais nada, é preciso dizer que vocês têm toda a liberdade para utilizar quaisquer estruturas disponíveis no Clarion para concluir a atividade. Para começar a pensar em uma solução, vamos relembrar algumas questões importantes sobre o Clarion. Em primeiro lugar, observemos a figura abaixo, que mostra como uma aplicação típica do Clarion funciona.

Observem que o "sensory input" corresponde a um ou mais DimensionValuePair, que podem conter informações genéricas. Existe no framework do Clarion, a classe SensoryInput, que deve ser utilizada para criar-se um objeto que funcionará como "sensory input". Essa classe possui o método Add, por meio do qual diversos DimensionValuePair podem ser inseridos, compondo a informação sensorial.

Na saída, devem ser criados diversos objetos da classe ExternalActionChunk, um para cada possível ação de saída que o Clarion pode gerar, controlando a criatura.

O ciclo cognitivo básico do Clarion, envolve a seguinte sequência:

Agent.Perceive(si);
ExternalActionChunk chosen = Agent.GetChosenExternalAction(si);

onde si é um objeto do tipo SensoryInput, devidamente preenchido com a informação sensorial.

Depois que as entradas do controlador foram definidas, e também as ações possíveis, é necessário agora criar as estruturas internas do ACS, que podem ser tanto no bottom-level (uma rede neural), como no top-level (regras).

Um exemplo (demo) bastante singelo de como usar o Clarion para controlar uma criatura no WorldServer3D pode ser visto aqui. Neste demo, duas regras fixas são utilizadas pelo Clarion para fazer a criatura desviar de obstáculos, virando à direita.

 

Relatório

Para a execução dessa atividade, foi necessário fazer a implementação do Parser das informações do Leaflets para serem trabalhadas no CLARION.

Foram necessárias algumas criações:

  • Classe para definição de um Item de leaflet chamada LeafItem

using System;
using WorldServerLibrary.Model;

namespace WorldServerLibrary
{
    public class LeafItem
    {
        public string Color {get; set;}
        public int NumLet {get; set;}
        public int NumSack {get; set;}
    }
}

 

  • Classe com a lista de items de leaflets (cada leaflet pode ter varios itens) chamada LeafLet

using System;
using WorldServerLibrary.Model;
using System.Collections.Generic;

namespace WorldServerLibrary
{
    public class Leaflet
    {
        public Leaflet (){ LeafList = new List<LeafItem>(); }
        public int NumLeafs {get; set;}
        public List<LeafItem> LeafList;
    }
}

Além disso foi necessário modificar o codigo existente da seguinte forma:

  • a classe da criatura para conter a lista de LeafLets.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WorldServerLibrary.Model
{
    public enum MotorSystemType
    {
        CAR,
        TWO_WHEEL
    }

    public class Creature:Thing
    {
        public Int32 index { get; set; }
        public MotorSystemType MotorSystem { get; set; }
        public double Wheel { get; set; }
        public double Speed { get; set; }
        public double Fuel { get; set; }
        public Boolean HasLeaflet { get; set; }
        public Int32 NumberOfLeaflets { get; set; }
        public List<Leaflet> LeafletList = new List<Leaflet>();
    }
}

  • a classe do WorldServer para fazer o parser própriamente dito da resposta do comando getcreaturestate

                       // It is missing the parser of leaflet!
                        if (creature.HasLeaflet)
                        {
                            int numLeaflet = creature.NumberOfLeaflets;
                            
                            for(int i=0; i<numLeaflet; i++)
                            {
                                enumerator.MoveNext();
                                Leaflet leaf = new Leaflet();
                                SetAttribute(leaf,"NumLeafs",enumerator);
                                
                                for (int j=0; j<leaf.NumLeafs; j++)
                                {
                                    LeafItem leafinfo = new LeafItem();
                                    SetAttribute(leafinfo,"Color",enumerator);
                                    SetAttribute(leafinfo,"NumLet",enumerator);
                                    SetAttribute(leafinfo,"NumSack",enumerator);

                                    leaf.LeafList.Add(leafinfo);
                                }
                                enumerator.MoveNext();
                                creature.LeafletList.Add(leaf);
                            }
                        }

Implementado isso, podemos passar para a implementação no Clarion. Para a resolução desse problema, podemos abordar várias soluçoes. A forma mais simples, devido a simplicidade do problema é via Fixed Rules. A proposta é mapear as joias na visão, fornecendo informações sensoriais ao Clarion, e baseado nisso, decidir as ações de saída. As ações de saída mapeadas farão o robo girar, seguir adiante, ir até uma joia, ir até uma comida, e pegar um item.

  • OutputRotateClockwise = World.NewExternalActionChunk(ClarionAgentActionType.ROTATE_CLOCKWISE.ToString());
  • OutputGoAhead = World.NewExternalActionChunk(ClarionAgentActionType.GO_AHEAD.ToString());
  • OutputGoFood = World.NewExternalActionChunk(ClarionAgentActionType.GO_FOOD.ToString());
  • OutputGoJewel = World.NewExternalActionChunk(ClarionAgentActionType.GO_JEWEL.ToString());
  • OutputSackIt = World.NewExternalActionChunk(ClarionAgentActionType.SACK_IT.ToString());

As informações de entrada são relacionados a presenca de joias, comidas, muros, e em caso de itens proximos, pegar.

  • InputWallAhead = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, DIMENSION_WALL_AHEAD);
  • InputFood = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, DIMENSION_FOOD);
  • InputJewel = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, DIMENSION_JEWEL);
  • InputSackIt = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, DIMENSION_SACK_IT);

Os tipos de ações gerados que nosso programa deverá tratar são:

  • DO_NOTHING,
  • ROTATE_CLOCKWISE,
  • GO_AHEAD,
  • GO_FOOD,
  • GO_JEWEL,
  • SACK_IT,

As regras implementadas são de forma simples:

  • Caso tenha muro, ou não tenha uma informação sensorial de ir até um item, ativar rotação
        private double FixedRuleDelegateToAvoidColissionWall(ActivationCollection currentInput, Rule target)
        {
            // quando nao tiver nada pra fazer, girar ou andar pra frente pra procurar algo
            if (currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION) ||
                (!currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION) &&
                 !currentInput.Contains(InputJewel, CurrentAgent.Parameters.MAX_ACTIVATION) &&
                 !currentInput.Contains(InputFood, CurrentAgent.Parameters.MAX_ACTIVATION))
                )
                return 1.0;
            else
                return 0.0;
            //return ((currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
        }
 
  • Caso não tenha uma informação sensorial de ir até um item, ativar movimentaçao para frente

  •         private double FixedRuleDelegateToGoAhead(ActivationCollection currentInput, Rule target)
            {
                // quando nao tiver nada pra fazer, girar ou andar pra frente pra procurar algo
                if (!currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION) &&
                     !currentInput.Contains(InputJewel, CurrentAgent.Parameters.MAX_ACTIVATION) &&
                     !currentInput.Contains(InputFood, CurrentAgent.Parameters.MAX_ACTIVATION))
                    return 1.0;
                else
                    return 0.0;
                //return ((currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MIN_ACTIVATION))) ? 1.0 : 0.0;
            }
     
  • Caso tenha uma comida, ir até posição da comida
  • private double FixedRuleDelegateToFood(ActivationCollection currentInput, Rule target)
            {
                // se tiver comida a frente, ativar o sensor indicando presenca de comida
               return ((currentInput.Contains(InputFood, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
            }
     
  • Caso tenha uma jóia, ir até a posição da jóia
  • private double FixedRuleDelegateToJewel(ActivationCollection currentInput, Rule target)
            {
                // se tiver joia a frente, ativar o sensor indicando presenca de joia
               return ((currentInput.Contains(InputJewel, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
     
            }
     
  • Caso tenha algo a pegar, pegue
  • private double FixedRuleDelegateSackIt(ActivationCollection currentInput, Rule target)
       {
            // se tiver algo a coletar, ativar o sensor indicando presenca de algo a coletar
           return ((currentInput.Contains(InputSackIt, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
       }

A condição de parada é baseada nos itens do leaflet e nos itens coletados. Quando forem coletados itens suficientes baseados na soma dos leaflets de uma mesma cor, para todos os leaflets, o agente morre.

                        if (worldServer.GoalCompleted)
                        {
                            Console.WriteLine("DIEDIEDIE");
                            agent.Abort(true);
                        }
 
 O Código referente a essa implementação pode ser conferido aqui.
O binário pode ser baixado aqui.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer