You are here

Relatório Aula 10 - Arquitetura Clarion com WorldServer3D

1) Teste inicial do ClarionDEMO em comunicação com o ambiente WorldServer3D.

 

                Inicialmente, é necessário fazer o download do assembly da library do Clarion na página da disciplina sob o link: ClarionLibrary. O arquivo deve ser descompactado em alguma pasta. O Clarion é uma biblioteca em C# e não possui um compilador por si, então a descompactação da biblioteca já constitui a instalação do Clarion.

                Depois de realizada a descompactação, deve-se executar o Monodevelop no Linux e abrir o projeto ClarionDEMO.csproj, que se encontra dentro do diretório SimulationCLARION>ClarionDEMO, que pode ser baixado da página da disciplina: SimulationClarion (tentei executar o exemplo no compilador do Windows, mas o programa faz referência à biblioteca 'Monodevelop.core', o que impediu a compilação).

                Depois de aberto o projeto no Monodevelop, deve-se importar as bibliotecas para o projeto, de tal modo que ele possa encontrar as referências feitas na classe MainClass. Isto pode ser feito ao se clicar com o botão direito no diretório Referências>editar referências (na área Solução, em ClarionDEMO>ClarionDEMO>Referências, no Monodevelop).

                Normalmente, as bibliotecas a serem importadas são: ClarionLibrary.dll, ClarionAgent.dll, WorldServerLibrary.dll (que se encontram dentro do diretório SimulationCLARION>ClarionDEMO>bin>Debug, na aba .NET assembly). Caso exista necessidade, também se pode importar a biblioteca System.

                Agora, ao tentar executar o código (botão play no canto superior esquerdo do MonoDevelop), o código deve ser executado e um terminal Konsole deve ser aberto. Neste terminal uma mensagem de erro aparecerá, por não termos ainda iniciado o ambiente World Server 3D.

                Sabendo disso, agora abrimos o NetBeans, com o projeto WorldServer3D (disponível em: <http://faculty.dca.fee.unicamp.br/gudwin/sites/faculty.dca.fee.unicamp.b...) e o executamos para iniciar o ambiente.

                Tendo iniciado o ambiente, basta executar novamente o ClarionDEMO no MonoDevelop e o exemplo fornecido pelo professor será executado. Na execução, num ambiente cercado por quatro paredes, a criatura virtual se desloca até encontrar uma parede e se vira para a direita para desviar dela, seguindo a andar até que encontre outra parede e repita o processo.

 

2) Modificações implementadas:

 

                - Popular o ambiente com objetos do tipo food e jewel;

                Inicialmente, para que o agente possa interagir de forma mais complexa sobre o ambiente, devem ser colocados objetos do tipo food e jewel. Para isto foi criada uma função no arquivo Main.cs para popular o ambiente virtual aleatoriamente com estes objetos. Tanto os tipos dos itens quanto as suas posições são geradas aleatoriamente, dentro do range adequado (dois tipos de food, seis tipos de jewel, distribuidos no espaço contido dentro do tabuleiro). Segundo esta função, são gerados de 1 a 10 objetos do tipo food e de 30 a 40 objetos do tipo jewel (foram colocados mais jewels para possibilitar a completude da leaflet).

             void populate_Environment() // Enche o tabuleiro de comida e jewels

             {

                    Random randomTypeXY = new Random();

                    int typeThing = new int();

                    int xThing = new int();

                    int yThing = new int();

                    int numberOfThings = randomTypeXY.Next(1,10);

 

                    for (int count = 0; count<numberOfThings; count ++)

                    {

                           typeThing = randomTypeXY.Next(0,3);

                           xThing = randomTypeXY.Next(100,700);

                           yThing = randomTypeXY.Next(100,500);

 

                           worldServer.NewFood(typeThing,xThing,yThing);

                    }

 

                    numberOfThings = randomTypeXY.Next(30,40);

 

                    for (int count = 0; count<numberOfThings; count ++)

                    {

                           typeThing = randomTypeXY.Next(0,6);

                           xThing = randomTypeXY.Next(100,700);

                           yThing = randomTypeXY.Next(100,500);

 

                           worldServer.NewJewel(typeThing,xThing,yThing);

                    }

             }

 

                - Identificação de objeto encontrado (comida, jewel, bricks);

                Uma vez populado o ambiente com os objetos para captura, são implementados meios para o agente virtual reconhecer estes objetos e ativar decisões diferentes. Inicialmente, sem estes recursos, o agente simplesmente para de se mover ao encontrar um destes objetos (deixa de se mover por não conseguir passar, porém continua enviando a instrução move para a criatura).

                A identificação de objeto encontrado foi feita em duas formas dentro do ClarionAgent: o reconhecimento da classe e o reconhecimento do nome da instância daquilo que a criatura vê:

                O reconhecimento da classe do objeto foi implementado de forma análoga à diferenciação entre uma parede e um espaço aberto, já implementada no exemplo fornecido pelo professor. A função MakePerceptionFromSensorialInput foi atualizada para identificar a CategoryId dos objetos encontrados, a partir da qual são configurados os parâmetros de ativação wallAhad, foodAhead ou jewelAhead (MAX_ACTIVATION ou MIN_ACTIVATION), dependendo do que está sendo visto pela criatura. Por meio de fixed rules e por meio de uma modificação em SetupACS, o agente passa levar em conta os parâmetros de ativação anteriormente citados e gera comandos de ROTATE_CLOCKWISE, GO_AHEAD, EAT_IT ou SACK_IT, que serão recebidos pela função Main;

             private SensoryInformation MakePerceptionFromSensorialInput(IList<Thing> sensorialInformation)

        {

                    // String contendo o nome do que está sendo visto.

       //           string whatISee = null;

 

            // New sensory information

            SensoryInformation si = World.NewSensoryInformation(CurrentAgent);

 

            // Detect if we have a wall ahead

            Boolean wallAhead = sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_BRICK && item.DistanceToCreature <= 61)).Any();

            double wallAheadActivationValue = wallAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION;

                 si.Add(InputWallAhead, wallAheadActivationValue);

 

                    // Minhas modificações no código:

                    // Detect if we have food ahead

                    Boolean foodAhead = sensorialInformation.Where(item => ((item.CategoryId == Thing.CATEGORY_NPFOOD || item.CategoryId == Thing.categoryPFOOD) && item.DistanceToCreature <= 61)).Any();

                    double foodAheadActivationValue = foodAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION;

                    si.Add(InputFoodAhead, foodAheadActivationValue);

 

                    // Detect if we have a jewel ahead

                    Boolean jewelAhead = sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_JEWEL && item.DistanceToCreature <= 61)).Any();

                    double jewelAheadActivationValue = jewelAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION;

                    si.Add(InputJewelAhead, jewelAheadActivationValue);

 

///////////////////////////////////////////////////////////////////////////////

 

        private void SetupACS()

        {

            // Create Colission Wall Rule

            SupportCalculator avoidCollisionWallSupportCalculator = FixedRuleDelegateToAvoidColissionWall;

            FixedRule ruleAvoidCollisionWall = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, OutputRotateClockwise, avoidCollisionWallSupportCalculator);

 

            // Commit this rule to Agent (in the ACS)

            CurrentAgent.Commit(ruleAvoidCollisionWall);

 

                    // Create Colission To Go Ahead

                    SupportCalculator goAheadSupportCalculator = FixedRuleDelegateToGoAhead;

                    FixedRule ruleGoAhead = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, OutputGoAhead, goAheadSupportCalculator);

 

                    // Commit this rule to Agent (in the ACS)

                    CurrentAgent.Commit(ruleGoAhead);

 

                    // Minhas modificações no código:

                    // Create Eat Food Rule

                    SupportCalculator eatFoodSupportCalculator = FixedRuleDelegateToEatFood;

                    FixedRule ruleDelegateToEatFood = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, OutputEatIt, eatFoodSupportCalculator);

 

                    // Commit this rule to Agent (in the ACS)

                    CurrentAgent.Commit(ruleDelegateToEatFood);

 

                    // Create Get Jewel

                    SupportCalculator getJewelSupportCalculator = FixedRuleDelegateToGetJewel;

                    FixedRule ruleDelegateToGetJewel = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, OutputSackIt, getJewelSupportCalculator);

 

                    // Commit this rule to Agent (in the ACS)

                    CurrentAgent.Commit(ruleDelegateToGetJewel);

 

 

                    // Minhas modificações no código:

 

            // Disable Rule Refinement

            CurrentAgent.ACS.Parameters.PERFORM_RER_REFINEMENT = false;

 

            // The selectio type will be probabilistic

            CurrentAgent.ACS.Parameters.LEVEL_SELECTION_METHOD = ActionCenteredSubsystem.LevelSelectionMethods.STOCHASTIC;

 

            // The selection of the action will be fixed (not variable) i.e. only the statement defined above.

            CurrentAgent.ACS.Parameters.LEVEL_SELECTION_OPTION = ActionCenteredSubsystem.LevelSelectionOptions.FIXED;

 

            // Define Probabilistic values

            CurrentAgent.ACS.Parameters.FIXED_FR_LEVEL_SELECTION_MEASURE = 1;

            CurrentAgent.ACS.Parameters.FIXED_IRL_LEVEL_SELECTION_MEASURE = 0;

            CurrentAgent.ACS.Parameters.FIXED_BL_LEVEL_SELECTION_MEASURE = 0;

            CurrentAgent.ACS.Parameters.FIXED_RER_LEVEL_SELECTION_MEASURE = 0;

        }

 

                O reconhecimento do nome do objeto foi realizado por meio da função public ISeeThat que, ao ser chamada pela função main, retorna uma string com o nome do objeto visto, bem como imprime este nome na tela. Esta função é necessária para a utilização do comando de captura da criatura (função SendSackIt), que exige o nome do objeto a ser capturado.

 

             public string ISeeThat(IList<Thing> sensorialInformation)

             {

                    // String contendo o nome do que está sendo visto.

                    string whatISee = null;

                    foreach (Thing item in sensorialInformation) {

                           if (((item.CategoryId == Thing.CATEGORY_NPFOOD) || (item.CategoryId == Thing.categoryPFOOD) || (item.CategoryId == Thing.CATEGORY_JEWEL)) && item.DistanceToCreature <= 61) {

                                  whatISee = item.Name;

                                 break;

                           }

                    }

                    Console.Write("        I see item: " + whatISee + ". ");

                    return whatISee;

             }

 

 

                - Sack de food e de jewel;

                A captura de objetos do tipo food e jewel ocorre por meio da função main, que se utiliza da percepção (implementada no agente) para saber que tipo de objeto foi encontrado e qual o seu nome. Estes métodos estão descritos acima e foram implementados no arquivo ClarionAgent.

 

                             void agent_OnNewExternalActionSelected(ClarionAgentActionType externalAction )

             {   Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

                    if (worldServer != null && worldServer.IsConnected)

                    {

                           switch (externalAction)

                           {

                                  case ClarionAgentActionType.DO_NOTHING:

                                  // Do nothing as the own value says

                           //     Console.Out.WriteLine("doing nothing! \n");

                                  break;

                                  case ClarionAgentActionType.ROTATE_CLOCKWISE:

                                  double newprad = prad + Math.PI/1000;

                                  while (newprad > Math.PI) newprad -= 2 * Math.PI;

                                  while (newprad < - Math.PI) newprad += 2 * Math.PI;

                                  worldServer.SendSetAngle(creatureId, 0, 0, newprad);

                           //     Console.Out.WriteLine("rotating! \n");

                                  break;

                                  case ClarionAgentActionType.GO_AHEAD:

                                  worldServer.SendSetAngle(creatureId, 1, 1, prad);

                           //     Console.Out.WriteLine("walking! \n");

                                  break;

                                  case ClarionAgentActionType.EAT_IT:

                                  IWantIt = agent.ISeeThat(agent_OnNewVisualSensorialInformation());

                                  worldServer.SendSackIt(creatureId,IWantIt);

                           //     worldServer.SendEatIt(creatureId,IWantIt);

                                  Console.Out.WriteLine("Gona sack this to eat later! \n");

                                  break;

                           case ClarionAgentActionType.SACK_IT:

                                  IWantIt = agent.ISeeThat (agent_OnNewVisualSensorialInformation ());

                                  worldServer.SendSackIt (creatureId, agent.ISeeThat (agent_OnNewVisualSensorialInformation ()));

                                  Console.Out.WriteLine ("Gona sack this jewel!\n");

                                  Sack s = worldServer.SendGetSack ("0");

                                  int isDone = agent.upDateLeaflet (agent_OnNewVisualSensorialInformation (), s);

                                  if (isDone == 1) {

                                        Console.Out.WriteLine ("Leaflet completed!!! \nNow I can rest in peace!!! \n\n(*dies*)\n\n\n   x_x   \n\n\n");

                                        agent.Abort(true);

                                  }

                                  break;

 

                                  default:

                                  break;

                           }

                    }

             }

 

                - Acesso ao Leaflet e atualização de itens requeridos: Modificação na função printLeaflet, gerando um vetor com números;

                O acesso ao Leaflet (gerado automaticamente no exemplo fornecido pelo professor) foi realizado pela função printLeaflet, dentro do arquivo Creature.cs. Esta função foi modificada de modo a criar um vetor de inteiros com seis posições, cada uma contendo o número de jewels da leaflet subtraídos do número de jewels já obtidas em cada cor. Este vetor é também impresso na tela. Toda vez que a função printLeaflet é chamada, este vetor é atualizado e uma nova lista de requisitos é impressa na tela. Também é implementada uma rotina de verificação de lista completa. Se a soma de todas as jewels faltantes for zero, ele retorna um valor inteiro igual a 1, caso a soma seja diferente de zero, retorna 0.

 

             public int PrintLeaflet(Sack s) {

                    Dictionary<string,LeafletItem> l = getConsolidatedLeaflet();

                    //     Console.Write("--> ");

             //     WorldServer worldServer = null;

             //     worldServer = new WorldServer("localhost", 4011);

             //     Sack s = World.SendGetSack ("0");

             //     s.print ();

                    foreach(var pair in l) {

                           //Console.Write(pair.Key+" "+pair.Value.totalNumber+" "+pair.Value.collected+" ");

                           switch(pair.Key){

                           case "Red":

                                  leafletList [0] = pair.Value.totalNumber - s.red_crystal;

                                  break;

 

                           case "Green":

                                  leafletList [1] = pair.Value.totalNumber - s.green_crystal;

                                  break;

 

                           case "Blue":

                                  leafletList [2] = pair.Value.totalNumber - s.blue_crystal;

                                  break;

 

                           case "Yellow":

                                  leafletList [3] = pair.Value.totalNumber - s.yellow_crystal;

                                  break;

 

                           case "Magenta":

                                  leafletList [4] = pair.Value.totalNumber - s.magenta_crystal;

                                  break;

 

                           case "White":

                                  leafletList [5] = pair.Value.totalNumber - s.white_crystal;

                                  break;

                           }

 

                           for (int i = 0; i<6; i++) {  // evita contagens negativas na checklist do leaflet.

                                  if (leafletList [i] < 0)

                                        leafletList [i] = 0;

                           }

 

                    }

                    //Console.WriteLine("\n\n ");

 

                    Console.Write("I still need:" + leafletList[0] + " Red Jewel, " + leafletList[1] + " Green Jewel, " + leafletList[2] + " Blue Jewel, " +  leafletList[3] + " Yellow Jewel, " + leafletList[4] + " Magenta Jewel and " + leafletList[5] + " White Jewel. \n\n");

 

                    if ((leafletList [0] + leafletList [1] + leafletList [2] + leafletList [3] + leafletList [4] + leafletList [5]) == 0) {

                           return (1);

                    } else {

                           return (0);

                    }

             }

 

                - Identificação do fim da missão e suicidio do agente.

                A partir da função printLeaflet acima, é possível identificar quando a criatura completou a sua leaflet. Esta completude é verificada na função main toda vez em que a criatura realiza a captura (sack) de algum objeto do tipo jewel. Caso a leaflet esteja completa, o agente envia uma mensagem de finalização da tarefa e morre (agent.abort)

 

3) Resultados: Arquivos para download e Fotos da execuçao do programa final (Clarion).

 

               Os arquivos fonte modificados da pasta SimulationClarion se encontram neste link <link>.

               Os arquivos executáveis se encontram neste link <link>. Basta executar o start.sh e digitar, no konsole:

                            mono ClarionDEMO.exe

               A seguir, estão detalhes da execução dos ciclos cognitivos e atualização da lista de jewels requeridas:

 

 

              Com a leaflet do ambiente para comparação:

 

 

              Finalização da tarefa e eliminação do agente:

 

 

4) Comparação Soar vs Clarion.

 

               Não foi realizada uma comparação entre os agentes do Clarion e do Soar, porém é provável que o agente Soar obtenha melhor desempenho que o agente Clarion pois o segundo anda em linha reta coletando os objetos que ocasionalmente aparecem em seu caminho, enquanto que o primeiro modifica a direção de seu movimento, buscando os itens que ele vê. Assim, o agente Soar (que deliberadamente se move em direção aos itens) provavelmente completaria a Leaflet mais depressa do que o agente Clarion (que captura os itens que ocasionalmente estão em seu caminho em uma linha reta).

 

 

 

 

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer