-
Notifications
You must be signed in to change notification settings - Fork 5
Creating a Communication Policy
A communication policy is a set of rules or algorithm for deciding which neighbouring nodes receive communication. Communication includes a variety of message types, but mainly involves the advertising of objects.
- The 'Broadcast' communication policy communicates with all neighbouring nodes.
- The 'Smooth' policy communicates according to the vision graph, with a probability proportional to the pheromone link with another camera.
- The 'Step' policy communicates with nodes whose pheromone links are higher than a threshold, and with some probability to the entire network
To use the existing communication policies, use the -c (or --comm) flag on the command line when launching the simulation environment. The options are 0, 1 and 2 for Broadcast, Smooth and Step, respectively.
E.g. To run the given scenario with a broadcast policy, use this:
./run.sh scenarios/scenario1_active.xml -c 0
To run a custom communication policy, see the section below.
Let's take a look at the current code in the repository for communication policies.
In the 'src' (source) directory, the package epics.commpolicy contains the current communication policy classes. These classes must:
- Extend AbstractCommunication
- This is the parent class
- Implement a constructor
- This takes required objects
- Implement the multicast method
- This is where communication policy code is implemented
- Implement the broadcast method
- This should communicate a message to all nodes
Let's take a look at the Broadcast class.
public class Broadcast extends AbstractCommunication {
public Broadcast(AbstractAINode ai, ICameraController camController) {
super(ai, camController); // Passing up to super is sufficient
}
// Send message to desired neighbours (all of them in this case).
// The MessageType allows us to take different actions depending on the
// type of message. The object is the message being passed
public void multicast(MessageType mt, Object o) {
Map<ITrObjectRepresentation, List<String>> advertised = ai.getAdvertisedObjects();
for (ICameraController icc : camController.getNeighbours()) {
// This is the actual sending of the message
camController.sendMessage(icc.getName(), mt, o);
// When we have sent a search message, there is more logic to help
// deal with it. Namely, we add this camera to the entry for the
// object.
if (mt == MessageType.StartSearch) {
List<String> cams = advertised.get((ITrObjectRepresentation) o);
ai.incrementSentMessages();
if (cams != null) {
if (!cams.contains(icc.getName())) {
cams.add(icc.getName());
}
} else {
cams = new ArrayList<String>();
cams.add(icc.getName());
advertised.put((ITrObjectRepresentation) o, cams);
}
}
}
// If the object is no longer being searched, remove it
if (mt == MessageType.StopSearch) {
advertised.remove((ITrObjectRepresentation) o);
}
}
/*
* Here we should make sure all neighbours receive the message.
* Since this is a broadcast class, we simply defer to the multicast
* method, but if multicast does anything differently, we would normally
* create a Broadcast object in the constructor and use that object
* when this method is called (see how Smooth and Step handle this).
*/
@Override
public void broadcast(MessageType mt, Object o) {
multicast(mt, o);
}
}
Making a custom communication policy is as simple as modifying the above class. Let's make a random communication policy by copying the above class but adding a little randomness to it.
public class RandomComm extends AbstractCommunication {
Broadcast broadcast;
public RandomComm(AbstractAINode ai, ICameraController camController) {
super(ai, camController);
broadcast = new Broadcast(ai, camController);
}
public void multicast(MessageType mt, Object o) {
Map<ITrObjectRepresentation, List<String>> advertised = ai.getAdvertisedObjects();
for (ICameraController icc : camController.getNeighbours()) {
// Make it a 50% chance of communication
if (Math.random() > 0.5) {
camController.sendMessage(icc.getName(), mt, o);
} else {
continue;
}
if (mt == MessageType.StartSearch) {
List<String> cams = advertised.get((ITrObjectRepresentation) o);
ai.incrementSentMessages();
if (cams != null) {
if (!cams.contains(icc.getName())) {
cams.add(icc.getName());
}
} else {
cams = new ArrayList<String>();
cams.add(icc.getName());
advertised.put((ITrObjectRepresentation) o, cams);
}
}
}
if (mt == MessageType.StopSearch) {
advertised.remove((ITrObjectRepresentation) o);
}
}
@Override
public void broadcast(MessageType mt, Object o) {
broadcast.multicast(mt, o);
}
}
That's all we need to do. Make our changes (in the multicast method, in case you missed it), and save as a new class.
Once you have a class extending AbstractCommunication which you wish to use as a communication policy, you can use it in your AI nodes by following these instructions.
First, place the .java file anywhere in the 'src' directory. Then, compile the program with the compile script (comp.sh).
Run the simulation with the -c flag, using option 4, along with the -u (or --custom-comm) flag, using the fully-qualified class name of your communication policy as an argument. For example, a class named 'MyComm' in the package 'com.mypackage' would be used as follows:
./run.sh scenarios/scenario1_active.xml -c 4 -u com.mypackage.MyComm
If this doesn't work, ensure your source file is a valid AbstractCommunication object, and that the .java file is placed somewhere in the 'src' directory. You must also ensure the fully qualified class name is correctly passed to the -u flag.