Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

ai_scheduler

Pierre Laclau edited this page Feb 13, 2018 · 13 revisions

Description

The scheduler is the AI's heart. It's role is to manage a tree of possible actions during a match, while dynamically adapting the current strategy when problems are encountered (e.g. navigation plan blocked by an enemy, door locked, servo or internal component not responding...). The tree is defined in an XML file; the scheduler then explores it by sending the corresponding request to the inferior nodes, while adapting the following requests based on the received answers.

Therefore, the idea is to define a "possibilities tree" of a match in the XML files for a certain robot. It is possible to give dependencies between tasks, execution orders, simultaneous requests, etc.

Authors and versions

  • v0.1 (A17) : @MadeInPierre
    • General parsing and decision structure
    • ActionLists supporting order and execution modes
    • Support order requests for services only
  • v0.2 (A17) : @Milesial
    • Supporting parameter entries in the XML file for the order requests (topic sending, services and actions).
  • v1.0 (fin A17) : @MadeInPierre
    • Supporting topic and (blocking for now) action request types
    • ActionLists now support while and for loops
    • Strategy start with HMI arm event and end with game_status HALT event.

Installation

The node doesn't require any particular dependency, aside from rospy (ROS python library for communication) and the existence of the nodes where requests are sent to.

Configuration

Two main elements need to be configured in order to have a working strategy : a python dictionary located inside ai_scheduler/src/scheduler_communication.py, which gives the proper ROS classes to the scheduler corresponding to the given server destination name; as well as the files 1_strategies.xml, 2_actions.xml and 3_orders.xml located at memory_definitions/def/robots/<robot_name>/ai/*.xml

Creating the robot's strategies, actions and orders (XML files)

The structure the scheduler follows for managing the actions tree relies on 4 main concepts:

  • Orders, defined in the file 3_ordres.xml : they are the scheduler soul 🙏. They represent the real ROS messages (topics pub and sub, service calls, action requests) that will be sent to the inferior nodes.
  • Actions, defined in the file 2_actions.xml : they are a list of Orders or other Actions defined in the file. They are a way of declaring a set of orders that are independent from the possible strategies the robot could follow. For isntance, an action called go_fire_balls can be used in many different strategies; it is better to define this associated set of actions once (in an action) in order to reference it in all the strategies that needed (no copy&paste allowed, ever 🚫).
  • Action Lists, that can be included inside Actions or Strategies: they are the scheduler's intelligence 💪, or a list of actions and orders with many optional execution orders and modes. This is where we can define conditions, number of executions, and dependencies or the descending tasks. This is is the tool that lets the scheduler adapt itself and be "intelligent". Note that Actions are in reality nothing more than ActionLists that can reference themselves; you can then also define execution modes in Actions.
  • Strategies, defined in the file 1_strategies.xml : a strategy represents a specific tree of actions in a game. This file lets you create several alternate trees for a same robot: this is lets the user choose a specific strategy to apply at the robot startup according to the team we are against with! Can also be useful to create small action trees for testing purposes without deleting the main game tree. A strategy can have actionref, orderref or actionlist elements.

Order definitions

The orders are defined in the file 3_orders.xml. The <order> node has to have a ref attribute, in order for it to be referenced from the outside. It can take an optional duration attribute, which is a manual estimation. This node must have a <message> child node, with a dest attributes, representing the service or action the message will be sent to. A message node holds multiple <param>, mirroring the structure of the ROS request message sent. Each <param> has a name, matching the name of the parameter in the ROS message, and a type, used to parse the parameter. A parameter can be optional, which means it doesn't have to be filled when the order is called (the default value will be put in by ROS). It can be preset : in that case, the parameter cannot be set when the order is called, the value is constant and cannot be changed. To finish, default values can be set in the order definition. Note that a param with a default value is therefore optional, and a param cannot be preset and optional.

Example

Let's assume we want to send a request to /asserv/goto, with the following ROS definition :

geometry_msgs/Pose2D position
float64 number
uint8 command
string message

Here is a valid example of the order definition, with all the elements seen above :

<order ref="goto" duration="1">
  <message dest="/asserv/goto">
    <param name="position" type="pose2d" />                   <!-- regular parameter, required -->
    <param name="number" type="float">42.8</param>            <!-- parameter with a default value -->
    <param name="command" type="int" preset="true">5</param>  <!-- preset parameter -->
    <param name="message" type="string" optional="true"/>     <!-- optional parameter -->
  </message>
</order>

Order references

The orders can be referenced from the actions or strategies definition files. To reference an order, a node <orderref> has to have its ref attribute matching the ref attribute of the referenced order. As childs of the node, the parameters (non-preset) are set, with the tag of the child matching the name of the parameter.

Example

Let's continue with our defined order from above. Suppose we want to reference it, here is a valid way to do it :

<orderref ref="goto">
  <position>
    <x>55.2</x>
    <y>57.1</y>
    <theta>3.14159</theta>
  </position>
  <message>hello world!</message> <!-- this node is optional -->
</orderref>

Action definitions

The actions are defined in the file 2_actions.xml. The <action> node has to have a ref attribute, in order for it to be referenced from the outside. This node has three children :

  • The <conditions> node is yet to be implemented.
  • The <params> node holds all the parameters used when calling this action. They are defined identically to the parameters in the message of an order, seen above, with the name, type, preset and optional attributes. For them to be useful, the parameters given to an action have to be passed to the orders or the actions that are called from this action. This will be discussed in the next part.
  • The <action> node doc is TODO

Action parameters binding

An action has a bunch of children (orderref and/or actionref). The parameters of the parent action can be passed to these children for them to use them. To do that, we use the bind attributes on the children's parameters like so :

<action ref="goto_spawn">
  <params>
    <param name="speed"/>
  </params>
  <actions exec="all" order="linear">
    <orderref ref="wheels_goto">
      <target_pos>
        <x>6.5</x>
        <y>7.5</y>
        <theta>7</theta>
      </target_pos>
      <speed bind="speed"/>
    </orderref>
  </actions>
</action>

Here, the order wheels_goto requires two parameters. The target_pos one is given directly in the orderref. However, no value is passed for the speed one. Instead, it is binded to the parameter named speed of the parent action. The speed parameter of this action is defined in the params node. When the goto_spawn action will be referenced, the speed parameter given to it will be passed to the order reference of wheels_goto. Note that the names for the parent parameter and the binded parameter do not have to match.

Action references

The call of an action works the same as the order reference, replacing orderref by actionref.

Adding new parameter types

In order to parse correctly all wanted type, one has to add a parser class, child of the Param class, for each type of parameter. Check out ai_params.py for more details.

Giving the scheduler the ability to speak

All server destinations written in the Orders' XML definitions must be be added in the python dictionary in ai_scheduler/src/scheduler_communication.py. This lets ai/scheduler send the Order requests to the ROS nodes, and know what each destination represent (a topic where subscribers are waiting, a topic where messages are being published, a service server or an action server), as the XML files can't provide the python classes that describe the ROS messages to be sent. When a new destination is created, you just have to add a dictionary entry according to the following rules:

  • The server name is the dictionary key. This is the dest attribute you declared while declaring the asociated order.
  • The value is a 2-value (3 in the case of action) tuple :
    • The server type in first position. The scheduler supports the following types of requests:
      • RequestTypes.PUB_MSG : the key is seen as a topic name. When the corresponding Order is executed, ai/scheduler publishes a message on the topic with the provided message parameters givent in the XML file.
      • RequestTypes.SUB_MSG : the key is seen as a topic name. The scheduler waits for a message to be published on that topic by an external node before considering the Order executed successfully.
      • RequestTypes.SERVICE : ai/scheduler sends a service request the the destination name, with the message parameters included in the XML definitions. The response message must have a ai_scheduler/TaskResult or bool success in it in order for the scheduler to know if the execution was successfully executed by the messge server.
      • RequestTypes.ACTION : a/scheduler sends a blocking (TODO for now) action request to the associated destination, with the XML parameters. a bool success or ai_scheduler/TaskResult result must exist in the response message.
    • You must then provide the Python class corresponding to the topic/service/action destination message. Simply add import my_package.msg (or .srv) in the file header zone, and then add in the tuple:
      • For a topic or service, provide the main message class (e.g. drivers_ard_hmi.msg.ROSEvent or drivers_ard_asserv.srv.SetPos)
      • For an action, provide the main action class in the second tuple position (e.g. movement_actuators.msg.dispatchAction) and the Goal class after that (e.g. movement_actuators.msg.dispatchGoal).
Example

The RequestTypes class in scheduler_communication.py must then have the following structure:

import ai_timer.srv
import ai_scheduler.msg

class RequestTypes(object):
    PUB_MSG = 0 # Publish a message on the specified topic.
    SUB_MSG = 1 # Wait for a message to be published at the specified topic name.
    SERVICE = 2 # Sends a service request to the specified destination.
    ACTION  = 3 # Sends a blocking action request to the specified destination.

    SERVERS = None

    @staticmethod
    def init():
        RequestTypes.SERVERS = {
            "/ai/scheduler/score": (RequestTypes.PUB_MSG, ai_scheduler.msg.AIScore),
            "/ai/timer/start":     (RequestTypes.SERVICE, ai_timer.srv.StartTimer)
        }
    ...

Running the package

Communication

How it Works

Just how does all that beautiful stuff work ?

Clone this wiki locally