Automated Agent-Oriented Real-Time Skidding Controller

Marco Carlo Cavalazzi  •  Mattia Castrichino
sommario

The system, to be implemented in a JADE  environment, has the purpose to move forward a remotely controlled rover,remaining transparent to the human control of the robot and allowing, at the same time, the maximum yield of the wheels during the movement. To do this an autonomous agent will be given to each wheel, in turn controlled by a central agent, who will be responsible to communicate with the user and the wheels to give effect to the commands "STOP" and "GO".

Stato del progetto

This section will explain the advancements done to achieve the goal of the project.

  1. Analisi del potenziale degli agenti in Jade e studio della fattibilità del sistema

  1. Analysis of the potential of Jade's agents and study of the feasibility of the system
To be aware of the potential of Jade's agents and to be sure of the possibility to take advantage of this technology to realize the project it has been necessary to study all the papers about Jade clear and well-written enough to get a better understanding of the Framework. During this process it has been useful to read the slides of the course from professor Omicini Andrea and the slides of the laboratory tutor Mariani Stefano. Furthermore it has been helpful to read the examples written on the site of the University of Montreal known as "Jade Primer" as well as the "Jade's official documentation". Studying the examples and running some tests has made possible to understand the power of Jade and, most important, its limits. The results led to the conclusion that it is possible to exploit this technology for the development of the project under consideration.

2. Analisi dei requisiti e definizione degli elementi di base necessari

This chapter will discuss the basic needs to develop and execute the software.

Development environment

Since the software is thought to be run on a rover, which is a single structure with multiple key elements, it will be executed in a local environment. The Jade platform will support the developers simulating the environment, providing access to Java language definitions for agents and behaviours, the "Agent Management System" (AMS) and the "Directory Facilitator" (DF).
Agents
The number of Jade agents required for this project is 9:
  • Central Agent
  • Ground Agent
  • Battery Agent
  • 6 Wheel Agents
In addition to this the User will launch the Dummy Agent (tool foundable in Jade's GUI) to control the rover. That will enable the User to send the commands "GO" and "STOP". Every agent will have its own task to accomplish and behaviours to follow:
  • Central Agent This agent will have to read the ACL messages sent by the User. It will have to propagate the content of the message to every other agent in the system. It will even control the speed and position of every Wheel and take decisions, according to the values received, to avoid the vehicle to skid.
  • Ground Agent This agent will have to simulate the ground in the system. Using a random function it will communicate to the wheels if they are skidding or not. It will communicate with the central agent too, to be able to stop if the battery level is low.
  • Battery Agent This agent will have to calculate the energy spent from the system and, in case of low remaining power, stop the system. This will be done with a STOP message to the Central Agent. During this time the user cannot make the rover move. When a certain amount of time has passed the battery will send a GO message to the Central Agent, that will tell the system that the battery is fully charged.
  • 6 Wheel Agents Every wheel agent will have the job of communicating with the Central Agent and the Ground Agent. They will tell cyclically the Central Agent their position relatively to their starting position. The communication with the Ground Agent will be necessary first to know if they have to slow down or not and second to communicate to the agent if they are slowing, because that would increase the chances to avoid the skidding.

Communication methods

To provide a good level of portability and extensibility the agents will use ACL Messages to communicate. About the portability it is important to notice that this kind of messages is FIPA compliant, which means that it meets a standard recognized by the IEEE. On the subject of extensibility we can see that the amount of parameters in every message will make possible to specify or categorize any type of message.

Stating assumptions

From now on it will be assumed the knowledge of the Java programming language and the Jade (Java Agent DEvelopment Framework) environment, together with the FIPA ACLMessages.

3. Esecuzione del progetto

In this section it will be addressed the topic of project development. This phase was carried out simultaneously to the "Monitoring and Controlling" phase.
3.1 Agente Batteria
This is the simplest agent of the system. Its duty is to simulate the supply of energy stored on the rover. If the energy supply is low the system is stopped until the battery is fully recharged.The Battery Agent listens to the Central Agent to know if the rover is "running" or not and setting the global boolean variable 'goStateFlag' accordingly. At the same time, during the "running" session (if the goStateFlag is set as true), it calculates the consumption of energy.Some important parts of the Battery Agent's code are displayed below:

//If the state of the system is set as 'GO'...
if(goStateFlag){
    chargeLevel--;
}
/* LOW BATTERY condition control */
if(chargeLevel<5){
  log("LOW BATTERY LEVEL REGISTERED");
  goStateFlag = false;   // will block the next operation of subtraction from the 'chargeLevel' variable
  // Setting the content of the message
  consumptionMsg.setContent("STOP");
  // Sending the STOP message to Central Agent to let it know that the system has "low battery level".
  myAgent.send(consumptionMsg);  log("  RECHARGING BATTERY...n");
  while(chargeLevel<999){
     chargeLevel++;
  }
  log("BATTERY RECHARGED");
  // Sending the GO message to Central Agent to let it know that the system has now enough energy to run again.
  consumptionMsg.setContent("GO");
  myAgent.send(consumptionMsg);
}
3.2 Agente Terreno
This agent's duty is to simulate the ground beneath the wheels. It listens to the Central Agent to know when the rover is moving and when it is not. If it is the global boolean variable 'goStateFlag' is set as true. Only when that variable is set as true the agent sends messages to the wheels to let them know if they have enough friction or not. If a wheel is skidding it will slow down and communicate this to the Ground Agent. This will grant the wheel a bonus in the next calculation of the friction situation (it will have an higher chance to have friction). Every wheel is handled separately, providing the best simulation of possibles rough terrains. Some important parts of the Ground Agent's code are displayed below:

if(goStateFlag){
   // The behaviour sends the message to the wheel to let it know if it has friction or not
   reply.setSender(myAgent.getAID());
   reply.addReceiver(wheel1AgentAID);
   myAgent.send(reply);
   reply.removeReceiver(wheel1AgentAID);   // Trying to receive a message from the Wheel Agent
   msg = myAgent.receive(wheelTemplate);   // If a message from the wheel has been received...
   if(msg!=null){
     if(msg.getContent().equals("decelerating")){
     // the friction bonus is increased
  wheelBonus++;
 }else{}
  if(msg.getContent().equals("accelerating")){
   // the friction bonus is decreased
   wheelBonus--;
  }
 }
   // consistency checks for 'wheelBonus'
   wheelBonus = wheelBonusCheck(wheelBonus);
   }
}
3.3 Agente Ruota
This agent's duty is to move at the highest possible speed, accordingly to:
  • the input of the user
  • the limits of the vehicle
  • the situation of the other wheels
In addition to the 'goStateFlag' global boolean variable, this agents uses the 'slowDownFlag' global boolean variable to model a situation in which one wheel is so slow or skidding so much that the other wheels have to slow down and wait until that wheel gain friction and speed. The slow down situation is managed by the Central Agent, that knows the position of every wheel and, thus, knows when it is necessary to apply the deceleration and what wheel will be involved. The coordination with the Ground Agent is realized using another boolean global variable: 'wheelFlag'. This variable is used to determine the reactions of the wheel accordingly to its speed and the situation of the ground communicated from the Ground Agent. It will determine the behaviour of the wheel switching between:
  • acceleration
  • deceleration
  • steadiness
An important part of the Wheel Agent's behaviour that reads the ACL messages coming from the Ground Agent are displayed below:

if(goStateFlag){
 // Attempting to receive a message from the Ground Agent
 msg = myAgent.receive(groundTemplate);//If a message from the Ground Agent is found... if(msg!=null)
 {
  if("SKID".equals(msg.getContent()))
  {
   log("Received message from Ground Agent. message content = " + msg.getContent());
   wheelFlag = WheelFlagEnum.DECELERATION;
  }
  else
  {
   if("FRICTION".equals(msg.getContent()))
   {
    log("Received message from Ground Agent. message content = " + msg.getContent());
    if(position<0)
    {
     if(speed<11){
      // trying to reach speed 11, so the wheel can return to the right position
      wheelFlag = WheelFlagEnum.ACCELERATION;
     }
     else
     {
      if(speed==11)
      {
       // the wheel has to keep that speed until it reaches position=0.
       wheelFlag = WheelFlagEnum.STEADY;
      }
     }
    }
    else
    {
     // Defensive programming: 
     // although it should be 0, the position is checked. 
     if(position==0)
     {
      if(speed>10)
      {
       wheelFlag = WheelFlagEnum.DECELERATION;
      }
      else
      {
       if(speed == 10)
        wheelFlag = WheelFlagEnum.STEADY;
       else
        wheelFlag = WheelFlagEnum.ACCELERATION;
      }
     }
    }
   }
  }
 }
}
The most important part of the Wheel Agent's code is displayed below:

// If a GO message from the Central Agent arrived...
   if(goStateFlag){
    // Setting the properties of the messages for the Ground and the Central Agent 
    groundMsg.setSender(myAgent.getAID());
    groundMsg.addReceiver(groundAgentAID);    centralMsg.setSender(myAgent.getAID());
    centralMsg.addReceiver(centralAgentAID);    // If the slowDownFlag is set as 'false'...
    if(!slowDownFlag){
     if(wheelFlag == WheelFlagEnum.ACCELERATION)
     {
      log("position = "+position);
      if(position == 0)
      {
       log("speed = "+speed);
       if(speed < 10){
        speed = speed + 0.5;
        groundMsg.setContent("accelerating");
        myAgent.send(groundMsg);
        log("increased speed = " + speed);
       }
      }
      else
      {
       // position<0 so the wheel has to reach 11 to gain a better position.
       if(speed < 11){
        speed += 0.5;
        log("increased speed = " + speed);
        groundMsg.setContent("accelerating");
        myAgent.send(groundMsg);
       }
       else
       {
        // The wheel is not in position and the speed is 11. The wheel moves forward (relatively to the body of the vehicol)
        position += 0.5;
       }
      }
     }
     else
     {
      if(wheelFlag == WheelFlagEnum.DECELERATION)
      {
       // if the wheel needs only to slow from 11 to 10 because it reached its position
       if(speed == 11 || speed == 10.5)
       {
        speed -= 0.5;
        // no position changes
        log("decreased speed = " + speed);
        groundMsg.setContent("decelerating");
        myAgent.send(groundMsg);
       }
       else
       {
        if(speed > 1)
        {
         speed -= 0.5;
         //the wheel lose his position
         if(position > -20)
         {
          position -= 0.5;
         }
         log("decreased speed = " + speed);
         groundMsg.setContent("decelerating");
         myAgent.send(groundMsg);
        }
        //else: do nothing
       }
      }
      else
      {
       if(wheelFlag == WheelFlagEnum.STEADY)
       {
        if(position < 0 && speed == 11)
        {
         position += 0.5;
        }
        // else: doNothing
       }
      }
     }
    }
    else
    {
     // If the program enters here, the 'slowDownFlag' is set as 'true'.
     // The wheel has to slow down until a new GO message arrives from the Central Agent.
     if(speed > 1)
     {
      speed -= 0.5;
      groundMsg.setContent("decelerating");
      myAgent.send(groundMsg);
      // the position remains the same beacuse every wheel is slowing down
     }
    }
    // Sending the actual position to the Central Agent
    centralMsg.setContent(Double.toString(position));
    myAgent.send(centralMsg);
    //  Removing the receivers from the messages. 
    // This has to be done to avoid adding the same agents as receivers many times. 
    groundMsg.removeReceiver(groundAgentAID);
    centralMsg.removeReceiver(centralAgentAID);
   }
   else
   {
    // goStateFlag = false -> Stopping the vehicol
    speed = 0;
   }
3.4 Agente Centrale
The Central Agent is the only one that interacts with the User, reading the GO and STOP messages and sending the same messages back to the user as acknowlodgements. The main duty of this agent is to propagate the orders received from the User to the other agents, but it performs other important tasks, like:
  • stopping the system if the battery level is low
  • keeping track of the position of the wheels
  • slowing down the wheels if one or more of them are too slow or don't have enough friction to keep up with the others (if the position of one wheel differs too much from its original position because of the skidding)
Some important parts of the Central Agent's code are displayed below:
  • Behaviour that takes care of the battery level:
if(goStateFlag) { // Trying to receive a message from the Battery Agent. msg = myAgent.receive(batteryTemplate); // If a message from the Battery is found... if(msg!=null) { // log("Received message from '" + msg.getSender().getName() + "'."); if("STOP".equals(msg.getContent())) { // log("message content = " + msg.getContent()); // Setting 'goStateFlag' to "false" to stop the reading of messages from the other behaviours of this agent. goStateFlag = false; // Creating the reply reply.setPerformative(ACLMessage.REQUEST); reply.setOntology("central agent"); // Setting the Sender reply.setSender(myAgent.getAID()); // Setting the Content of the message reply.setContent("STOP"); addReceiversToMessage(reply, groundAgentAID, wheel1AgentAID, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); // The agent forwards the "STOP" message to all the agents of the system except itself and the Battery Agent myAgent.send(reply); // It is necessary to remove the receivers to avoid adding every time new receivers equal to the first ones (sending too many messages, e.g.: two GO messages instead of one). removeReceiversFromMessage(reply, groundAgentAID, wheel1AgentAID, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); // Resetting msg for the 'while' section msg=null; while(msg==null)\ { // Trying to receive a GO message from the Bsttery Agent. msg = myAgent.receive(batteryGoTemplate); } // Setting the Content of the message reply.setContent("GO");// The agent forwards the "GO" message to all the agents of the system except itself addReceiversToMessage(reply, groundAgentAID, batteryAgentAID, wheel1AgentAID, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); // Sending the 'reply' message myAgent.send(reply); // It is necessary to remove the receivers to avoid adding every time new receivers equal to the first ones (sending too many messages). removeReceiversFromMessage(reply, groundAgentAID, batteryAgentAID, wheel1AgentAID, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); // Defining the state flag as 'true' goStateFlag = true; } } }
  • Behaviour that takes care of the wheel:
if(goStateFlag) { // Attempting to receive a message from the Wheel msg = myAgent.receive(wheelTemplate); // If a message from the Wheel is found... if(msg!=null) { if(lowPositionFlag == false) { // Storing the position of the wheel in a local variable wheelPosition = Double.parseDouble(msg.getContent()); // If a wheel is too slow... if(wheelPosition < -19.5) { // Setting the flag that says that it is too slow to 'true' lowPositionFlag = true; // The behaviour sends "SLOW DOWN" to every other wheel to allow this wheel to recover from the excessive skidding addReceiversToMessage(reply, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); reply.setSender(myAgent.getAID()); reply.setContent("SLOW DOWN"); myAgent.send(reply); removeReceiversFromMessage(reply, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); } } else { // If the wheel went too low and the new position is higher than the previous one (the wheel had friction and accelerated to 11 Km/h) if(lowPositionFlag == true && (Double.parseDouble(msg.getContent()) > -20.0) ){ // Setting the flag back to 'false' lowPositionFlag = false; // The behaviour sends "GO" to every other wheel restoring the GO state in the whole system addReceiversToMessage(reply, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); reply.setSender(myAgent.getAID()); reply.setContent("GO"); myAgent.send(reply); removeReceiversFromMessage(reply, wheel2AgentAID, wheel3AgentAID, wheel4AgentAID, wheel5AgentAID, wheel6AgentAID); } } } }

4. Monitoraggio e Controllo

During the development process it has become necessary to use the Jade's visual tools like:
  • the "Sniffer Agent", that allows the developer to monitor every message exchanged between the agents during the execution of the program, and
  • the "Introspector Agent", that allows the developer to monitor every agent, every behaviour and every message exchanged. Moreover, it made easy to pause the execution of a behaviour or an agent for control and debug purpose. Once determined the expected behaviour of the system, these tools were used to detect differences from the expected results and the given ones. In addition, the System.out.println Java function was used for debug purpose.

5. Resistenza ai guasti

This section describes the ability of the system to keep running correctly if any of the agents, for any reason, stops working or doesn't work at all.

What happens if some connection is lost?

  • Regarding to the wheels, any misbehavior of the agents will not affect the movements of the rover.
If one of them fails to run the others will compensate the friction generated from the unexpected burden.
  • Regarding to the battery, if its agent fails to run the rover will not be affected.
Although the battery levels will not be checked and kept under control, the system will simply run until the battery levels will be high enough to sustain the movements. After that the wheels will stop and wait until the energy supply is restored. That is because they will simply not be able to move.
  • Regarding to the ground, the failure of the agent would not allow the system to move forward.
This is not considered a huge problem, since this agent is meant to be a simulation of the real terrains on which the rover will run. If this software will be used in a real environment there will be mechanical sensors to detect the status of the ground.
  • Regarding to the central agent, that is the most complex agent in the system, there are many possible kind of misbehavior : - if the communication with a wheel is misbehaving the movements of that wheel could be unexpected. Nevertheless, the other wheels would compensate, thus eliminating the issue. This is true if at most two wheels of both sides are misbehaving. - if the communication with the battery is compromised the agent will perform its duties using the energy of the system since the level of energy is high enough. - even tough, if the communication with the user is compromised the agent will follow the last given instruction. This would definitely be a problem for the rover, since it could not stop itself from going on indefinitely. This could be solved installing an emergency receiver on the rover to allow the user to regain control on it.

Note

  • PROBLEM during the code creation The definition of an ACLMessage, like : ACLMessage reply = new ACLMessage(); gives as a result null, so that after the execution of that line of code reply will be equal to null. On the other hand, using the following constructor ACLMessage reply = new ACLMessage(ACLMessage.REQUEST); allows to obtain a well formed ACLMessage, with its performative attribute set, in this case, to REQUEST.
Both of these versions seem to be well written during the compilation of the code. However, the first one creates many troubles during the execution of the program. It would be an advancement finding a solution to this kind of problem. In my personal opinion, it is possible to:
  • allow the creation of a blank message with every field empty or
  • forbid the use of the function “new ACLMessage()” with no input values.

Documentazione