Skip to content

jDEECo Convoy Tutorial OLD

misza edited this page Feb 11, 2013 · 1 revision

The purpose of this tutorial is to get user acquainted with JDEECo utility which is a Java realization of DEECo paradigms. Basic concepts will be introduced with the simple example, which is taken from the bigger use case scenario called "Robotic playground".

The example describes two robot components, which move robots along the predefined paths until they reach their destinations. One of the robots has role of the leader and moves on the way regardless the current situation on its path, while the other is initially stopped and starts moving only when it observes the first robot on its way.

Code snippets

  • Launcher:
	package cz.cuni.mff.d3s.deeco.demo;

	public class Launcher {

		/**
		 * @param args
		 */
		public static void main(String[] args) {
			Class[] classes = { RobotLeaderComponent.class,
					RobotFollowerComponent.class };
			Class[] ensembles = { ConvoyEnsemble.class };
			KnowledgeManager km = new RepositoryKnowledgeManager(
					new TSKnowledgeRepository());
			Runtime runtime = new Runtime(classes, ensembles, km);
		}

	}
  • Leader:
	package cz.cuni.mff.d3s.deeco.demo.convoy;

	@DEECoComponent
	public class RobotLeaderComponent extends RootKnowledge {

		public Integer battery;
		public Path path;
		public String convoyRobot;
		public List<Path> crossingRobots;

		@DEECoInitialize
		public static RootKnowledge getInitialKnowledge() {
			RobotLeaderComponent k = new RobotLeaderComponent();
                  k.id = 1;
			k.battery = new Integer(100);
			k.path = new Path();
			k.path.currentPosition = new Integer(0);
			k.path.remainingPath = Arrays.asList(new Integer[] {new Integer(1), new Integer(2),
					new Integer(3), new Integer(4), new Integer(5), new Integer(6),
					new Integer(7), new Integer(8), new Integer(9)});
			k.convoyRobot = null;
			k.crossingRobots = null;
			return k;
		}

		@DEECoPeriodicScheduling(5000)
		@DEECoProcess
		public static void process(@DEECoProcessInOut("path") Path path,
				@DEECoProcessInOut("battery") OutWrapper<Integer> battery) {
			if (path.remainingPath.size() > 0) {
				path.currentPosition = path.remainingPath.remove(0);
				battery.item = new Integer(battery.item - 1);
				System.out.println("Leader is moving: " + path.remainingPath);
			}
		}
	}
  • Follower:
	package cz.cuni.mff.d3s.deeco.demo.convoy;

	@DEECoComponent
	public class RobotFollowerComponent extends RootKnowledge {

		public Integer battery;
		public Path path;
		public String convoyRobot;
		public List<Path> crossingRobots;

		@DEECoInitialize
		public static RootKnowledge getInitialKnowledge() {
			RobotFollowerComponent k = new RobotFollowerComponent();
                  k.id = 2;
			k.battery = new Integer(100);
			k.path = new Path();
			k.path.currentPosition = new Integer(1);
			k.path.remainingPath = Arrays.asList(new Integer[] { new Integer(2),
					new Integer(3), new Integer(4), new Integer(5), new Integer(6),
					new Integer(7), new Integer(8), new Integer(9)});
			k.convoyRobot = null;
			k.crossingRobots = null;
			return k;
		}

		@DEECoProcess
		@DEECoPeriodicScheduling(4000)
		public static void process(@DEECoProcessInOut("path") Path path,
				@DEECoProcessInOut("battery") OutWrapper<Integer> battery,
				@DEECoProcessIn("convoyRobot") String convoyRobot) {
			if (convoyRobot != null && path.remainingPath.size() > 0) {
				path.currentPosition = path.remainingPath.remove(0);
				battery.item = new Integer(battery.item - 1);
				System.out.println("Follower is moving: " + path.remainingPath);
			}
		}
	}
  • Convoy ensemble:
	package cz.cuni.mff.d3s.deeco.demo.convoy;

	@DEECoEnsemble
	@DEECoPeriodicScheduling(2000)
	public class ConvoyEnsemble {

		public static class ConvoyOutInterface extends Knowledge {
			public String convoyRobot;
		}

		public static class EnsemblePath extends Knowledge {
			public Integer currentPosition;
			public List<Integer> remainingPath;
		}

		@DEECoEnsembleMembership
		public static boolean membership(@DEECoMemberIn("id") String mId,
				@DEECoMemberIn("path.remainingPath") List<Integer> mRemainingPath,
				@DEECoCoordinatorIn("id") String cId,
				@DEECoCoordinatorIn("path") EnsemblePath cPath) {
			if (!mId.equals(cId)) {
				return mRemainingPath.size() > 0
						&& cPath.remainingPath.size() > 0
						&& cPath.currentPosition
								.equals(getNextPosition(mRemainingPath));
			}
			return false;
		}

		@DEECoEnsembleMapper
		public static void map(@DEECoMemberOut ConvoyOutInterface mOutCR,
				@DEECoCoordinatorIn("path.remainingPath") List<Integer> cRemainingPath) {
			mOutCR.convoyRobot = "1";
		}

		public static Integer getNextPosition(List<Integer> remainingPath) {
			if (remainingPath.size() > 0) {
				return remainingPath.get(0);
			}
			return -1;
		}
	}

Launcher

The Launcher class main method instantiates the DEECo runtime, which automatically starts its operation - classes are "interpreted" and appropriate processes are started.

Robot Follower and robot Leader

Basically there are two robot roles "Leader" and "Follower", which have their own Java class definition. Each of those classes extends the RootKnowledge type, which (using the "id" public field) describes knowledge of a particular component (i.e. top-level node in the tree knowledge structure). Additionally they are marked with the @DEECoComponent annotation, allowing the system to properly identify component classes. In this case both components put additional public fields to their definitions, which are initialized in the static (and also public) method tagged with the @DEECoInitialize annotation. This method does not take any parameters and returns an instance of the containing class. It is used to retrieve an initial state of component knowledge, and as can be seen in the code above all declared fields are assigned some initial values. Apart from the knowledge initializing method, each component is expected to have at least one process method which executes relying on component data. Such method is tagged with @DEECoProcess annotation and can take a random number of properly tagged parameters. Allowed annotations for the process method parameters are: @DEECoProcessIn, @DEECoProcessOut and @DEECoProcessInOut. Parameters marked as an input will be retrieved from the knowledge but never stored back after the execution. Those marked as an output, will be first instantiated (using non-parameterized constructors for the class) and pass to the method before its execution. When the execution completes, they are stored in the knowledge. Parameters, annotated as both input and output, are first retrieved from the knowledge and then (after the method execution) stored back to it. Each of those annotation contains the value attribute, which specifies the parameter name together with the knowledge nesting path. To explain it, let's consider the following parameter: @DEECoProcessInOut("path") Path path. For this parameter the value attribute is "path", which means that the required (as it is also an input parameter) knowledge value will be searched in the knowledge structure under the node: 1.path or 2.path. Numbers at the beginning denote the particular knowledge ids, and so for the leader it is 1 and for the follower it is 2. As it was mentioned before, it is possible to use nesting paths in a parameter annotation attribute. Let's assume that a process, needs only the information about the robot's current position. With JDEECo it can be done in the following way: @DEECoProcessIn("path.currentPosition") Integer position. Similarly to the previous case the search will be performed by prepending the value attribute with the components id (for example 1.path.currentPosition). The last but not least important thing regarding the process method parameters are the outputs. Very often it is necessary to change value of an object, which type is immutable (for example Integer). As such, JDEECo provides the OutWrapper generic class which, allows for modification of immutable types, and store those changes in the knowledge repository. As for sample usage, have a look at the battery parameter.

Moreover, a developer may put the additional annotation above the process method header, called either: @DEECoPeriodicScheduling or @DEECoTriggeredScheduling. At the moment only @DEECoPeriodicScheduling is supported and it is treated as default annotation. As the name indicates this annotation allows for describing process method execution scheme, which can be periodic or triggered. Periodic type of scheduling annotation contains the value attribute which is the period interval of method execution, given in milliseconds.

Convoy ensemble

To let the follower robot to move we need to establish an ensemble between those robots. In JDEECo ensembles are defined as the first class objects. Similarly to the knowledge component class, it is tagged with an annotation. In this case it is @DEECoEnsemble. As ensembling process can be either triggered and periodic, the proper scheduling describing annotation can be used to denote an ensemble execution scheme. In the ensemble definition there are two important methods: an ensemble membership checking function and mapping function. To properly identify them, annotations (@DEECoEnsembleMembership and @DEECoEnsembleMapper respectively) are used, before the method headers. In both cases, the methods can accept a random number of parameters, but in case of the membership checking function those parameters can be of input type only. Additionally, method tagged with @DEECoEnsembleMembership should return boolean value indicating if the ensemble can be established. As can be seen from the code above, method parameters are also tagged. The rules from the process method parameters apply here as well and the only difference is the additional distinguishment between coordinator and member parameters. To find out more details about what it means, please refer to the DEECo component model description (Ensemble describing part).


An important thing to mention is that, the parameters for both process methods and ensemble methods are retrieved using duck typing. As such it is possible to define your own structures (extending the Knowledge class), with fields which are actually needed for those method execution.