From fb2feec693d6d40548648191eeb343fccf9f5f48 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Tue, 25 May 2021 18:38:47 +0200
Subject: [PATCH] begin with coordinator
---
ros3rag.coordinator/.gitignore | 5 +
ros3rag.coordinator/build.gradle | 159 +++++++++++++++++
.../src/main/jastadd/Coordinator.connect | 15 ++
.../src/main/jastadd/Coordinator.flex | 65 +++++++
.../src/main/jastadd/Coordinator.jrag | 62 +++++++
.../src/main/jastadd/Coordinator.parser | 65 +++++++
.../src/main/jastadd/Coordinator.relast | 6 +
.../src/main/jastadd/dummy/types.connect | 0
.../src/main/jastadd/dummy/types.jrag | 0
.../src/main/jastadd/dummy/types.relast | 0
.../inf/st/coordinator/MainCoordinator.java | 166 ++++++++++++++++++
.../src/main/resources/ros3rag.coordinator | 25 +++
settings.gradle | 1 +
13 files changed, 569 insertions(+)
create mode 100644 ros3rag.coordinator/.gitignore
create mode 100644 ros3rag.coordinator/build.gradle
create mode 100644 ros3rag.coordinator/src/main/jastadd/Coordinator.connect
create mode 100644 ros3rag.coordinator/src/main/jastadd/Coordinator.flex
create mode 100644 ros3rag.coordinator/src/main/jastadd/Coordinator.jrag
create mode 100644 ros3rag.coordinator/src/main/jastadd/Coordinator.parser
create mode 100644 ros3rag.coordinator/src/main/jastadd/Coordinator.relast
create mode 100644 ros3rag.coordinator/src/main/jastadd/dummy/types.connect
create mode 100644 ros3rag.coordinator/src/main/jastadd/dummy/types.jrag
create mode 100644 ros3rag.coordinator/src/main/jastadd/dummy/types.relast
create mode 100644 ros3rag.coordinator/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java
create mode 100644 ros3rag.coordinator/src/main/resources/ros3rag.coordinator
diff --git a/ros3rag.coordinator/.gitignore b/ros3rag.coordinator/.gitignore
new file mode 100644
index 0000000..87b4cdd
--- /dev/null
+++ b/ros3rag.coordinator/.gitignore
@@ -0,0 +1,5 @@
+build
+src/gen-res/
+src/gen/
+out/
+*.class
diff --git a/ros3rag.coordinator/build.gradle b/ros3rag.coordinator/build.gradle
new file mode 100644
index 0000000..3b03cd8
--- /dev/null
+++ b/ros3rag.coordinator/build.gradle
@@ -0,0 +1,159 @@
+buildscript {
+ repositories.mavenCentral()
+ dependencies {
+ classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
+ }
+}
+
+plugins {
+ id 'ros3rag.java-application-conventions'
+ id 'ros3rag.java-ragconnect-conventions'
+}
+
+mainClassName = 'de.tudresden.inf.st.coordinator.MainCoordinator'
+
+dependencies {
+}
+
+ext.ragConnectInputGrammar = 'src/main/jastadd/Coordinator.relast'
+ext.ragConnectInputConnect = 'src/main/jastadd/Coordinator.connect'
+ext.ragConnectRootNode = 'Coordinator'
+ext.relastFiles = ["src/gen/jastadd/Coordinator.relast", "src/gen/jastadd/RagConnect.relast"]
+ext.jastaddAstPackage = 'de.tudresden.inf.st.coordinator.ast'
+
+
+apply plugin: 'jastadd'
+
+dependencies {
+// jastadd2 "org.jastadd:jastadd:2.3.5"
+ jastadd2 fileTree(include: ['jastadd2.jar'], dir: '../libs')
+ api group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'
+
+}
+
+sourceCompatibility = 11
+targetCompatibility = 11
+
+// phases: ragConnect -> RelAst -> JastAdd
+// phase: ragConnect
+task ragConnect(type: JavaExec) {
+ group = 'Build'
+ main = 'org.jastadd.ragconnect.compiler.Compiler'
+ classpath = configurations.ragconnectClasspath
+
+ args([
+ '--o=src/gen/jastadd',
+ project.ext.ragConnectInputGrammar,
+ project.ext.ragConnectInputConnect,
+ '--logReads',
+ '--logWrites',
+// '--verbose',
+ '--rootNode=' + project.ext.ragConnectRootNode,
+ '--incremental=param',
+ "--tracing=cache,flush"
+ ])
+
+}
+
+// Input files for relast
+//def relastFiles = ["src/gen/jastadd/MinimalModel.relast", "src/gen/jastadd/RagConnect.relast"]
+
+task grammar2uml(type: JavaExec) {
+ main = 'de.tudresden.inf.st.jastadd.grammar2uml.compiler.Compiler'
+ classpath = configurations.grammar2umlClasspath
+
+ args([
+ '--verbose',
+ 'src/gen/jastadd/types.relast'
+ ] + project.ext.relastFiles)
+}
+
+// phase: RelAst
+task relastToJastAdd(type: JavaExec) {
+ group = 'Build'
+ main = "-jar"
+
+ args(["../libs/relast.jar",
+ "--grammarName=./src/gen/jastadd/model",
+ "--useJastAddNames",
+ "--listClass=java.util.ArrayList",
+ "--jastAddList=JastAddList",
+ "--serializer=jackson",
+ "--resolverHelper",
+ "--file",
+ "src/gen/jastadd/types.relast"
+ ] + project.ext.relastFiles)
+
+ inputs.files project.ext.relastFiles + ['src/gen/jastadd/types.relast']
+ outputs.files file("./src/gen/jastadd/model.ast"), file("./src/gen/jastadd/model.jadd")
+}
+
+// phase: JastAdd
+jastadd {
+ configureModuleBuild()
+ modules {
+ //noinspection GroovyAssignabilityCheck
+ module("coordinator") {
+
+// java {
+// basedir "src/"
+// include "main/**/*.java"
+// include "gen/**/*.java"
+// }
+
+ jastadd {
+ basedir "src/"
+ include "main/jastadd/**/*.ast"
+ include "main/jastadd/**/*.jadd"
+ include "main/jastadd/**/*.jrag"
+ include "gen/jastadd/**/*.ast"
+ include "gen/jastadd/**/*.jadd"
+ include "gen/jastadd/**/*.jrag"
+ }
+ scanner {
+ include "src/main/jastadd/Coordinator.flex"
+ }
+
+ parser {
+ include "src/main/jastadd/Coordinator.parser"
+ }
+ }
+ }
+
+ cleanGen.doFirst {
+ delete "src/gen/java/de"
+ delete "src/gen-res/BuildInfo.properties"
+ }
+
+ module = "coordinator"
+
+ astPackage = project.ext.jastaddAstPackage
+
+ genDir = 'src/gen/java'
+
+ buildInfoDir = 'src/gen-res'
+
+ parser.name = 'CoordinatorParser'
+
+ scanner.genDir = "src/gen/java/de/tudresden/inf/st/coordinator/scanner"
+ parser.genDir = "src/gen/java/de/tudresden/inf/st/coordinator/parser"
+
+ // jastaddOptions = ["--lineColumnNumbers", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
+ // default options are: '--rewrite=cnta', '--safeLazy', '--visitCheck=false', '--cacheCycle=false'
+ extraJastAddOptions = [
+ '--lineColumnNumbers',
+ '--List=JastAddList',
+ '--cache=all',
+ "--flush=api",
+ "--incremental=param,debug",
+ "--tracing=cache,flush",
+ ]
+}
+
+cleanGen.doFirst {
+ delete "src/gen/jastadd"
+}
+
+// Workflow configuration for phases
+generateAst.dependsOn relastToJastAdd
+relastToJastAdd.dependsOn ragConnect
diff --git a/ros3rag.coordinator/src/main/jastadd/Coordinator.connect b/ros3rag.coordinator/src/main/jastadd/Coordinator.connect
new file mode 100644
index 0000000..d7bca5d
--- /dev/null
+++ b/ros3rag.coordinator/src/main/jastadd/Coordinator.connect
@@ -0,0 +1,15 @@
+receive Component.IncomingStatus ;
+//send tree Coordinator.NextComponentToStart using NameOfComponent ;
+//
+//NameOfComponent maps Component c to String {:
+// return c.getName();
+//:}
+
+send Component.NextCommand using CommandCheck ;
+
+CommandCheck maps String command to String {:
+ if (command == null) {
+ reject();
+ }
+ return command;
+:}
diff --git a/ros3rag.coordinator/src/main/jastadd/Coordinator.flex b/ros3rag.coordinator/src/main/jastadd/Coordinator.flex
new file mode 100644
index 0000000..39f328d
--- /dev/null
+++ b/ros3rag.coordinator/src/main/jastadd/Coordinator.flex
@@ -0,0 +1,65 @@
+package de.tudresden.inf.st.coordinator.scanner;
+
+import de.tudresden.inf.st.coordinator.parser.CoordinatorParser.Terminals;
+
+%%
+
+// define the signature for the generated scanner
+%public
+%final
+%class CoordinatorScanner
+%extends beaver.Scanner
+
+// the interface between the scanner and the parser is the nextToken() method
+%type beaver.Symbol
+%function nextToken
+%yylexthrow beaver.Scanner.Exception
+
+// store line and column information in the tokens
+%line
+%column
+
+// this code will be inlined in the body of the generated scanner class
+%{
+ private beaver.Symbol sym(short id) {
+ return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext());
+ }
+ private beaver.Symbol symText(short id) {
+ return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext().substring(1, yytext().length() - 1));
+ }
+%}
+
+WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
+//Identifier = [:jletter:][:jletterdigit:]*
+Text = \" ([^\"]*) \"
+
+//Integer = [:digit:]+ // | "+" [:digit:]+ | "-" [:digit:]+
+//Real = [:digit:]+ "." [:digit:]* | "." [:digit:]+
+
+Comment = "//" [^\n\r]+
+
+%%
+
+// discard whitespace information and comments
+{WhiteSpace} { }
+{Comment} { }
+
+// ** token definitions **
+// Begin of line with capital letter
+"components" { return sym(Terminals.COMPONENTS); }
+"component" { return sym(Terminals.COMPONENT); }
+"docker compose" { return sym(Terminals.DOCKER_COMPOSE); }
+"mqtt topic" { return sym(Terminals.MQTT_TOPIC); }
+"=" { return sym(Terminals.EQUALS); }
+"," { return sym(Terminals.COMMA); }
+"<" { return sym(Terminals.LT); }
+"{" { return sym(Terminals.LB_CURLY); }
+"}" { return sym(Terminals.RB_CURLY); }
+
+//{Identifier} { return sym(Terminals.NAME); }
+{Text} { return symText(Terminals.TEXT); }
+//{Integer} { return sym(Terminals.INTEGER); }
+//{Real} { return sym(Terminals.REAL); }
+<<EOF>> { return sym(Terminals.EOF); }
+/* error fallback */
+[^] { throw new Error("Illegal character '"+ yytext() +"' at line " + (yyline+1) + " column " + (yycolumn+1)); }
diff --git a/ros3rag.coordinator/src/main/jastadd/Coordinator.jrag b/ros3rag.coordinator/src/main/jastadd/Coordinator.jrag
new file mode 100644
index 0000000..33bd6e5
--- /dev/null
+++ b/ros3rag.coordinator/src/main/jastadd/Coordinator.jrag
@@ -0,0 +1,62 @@
+aspect Computation {
+ syn String Component.getNextCommand() {
+ if (!getIncomingStatus().equals("up")) {
+ System.out.println(getName() + " not up");
+ // component is not "up" yet
+ return null;
+ }
+ for (Component predecessor : getPredecessorList()) {
+ if (!predecessor.getIncomingStatus().equals("ready")) {
+ // one of required component is not "ready" yet
+ System.out.println(getName() + " missing " + predecessor.getName());
+ return null;
+ }
+ }
+ // all required components are "ready", and this component is "up"
+ System.out.println(getName() + " ready to be started");
+ return "start";
+ }
+
+ public void Component.callDockerCompose() {
+ String[] args = { "docker-compose", "up", "-d", getDockerComposeName() };
+ System.out.println("Would start > " + java.util.Arrays.toString(args));
+ ProcessBuilder builder = new ProcessBuilder(args);
+// builder.redirectOutput(err);
+// builder.redirectError(err);
+
+// Process process = builder.start();
+// process.waitFor();
+// return process.exitValue();
+ return;
+ }
+}
+
+aspect Printing {
+ syn String Coordinator.prettyPrint() {
+ StringBuilder sb = new StringBuilder();
+ for (Component comp : getComponentList()) {
+ sb.append(comp.prettyPrint()).append("\n");
+ }
+ return sb.toString();
+ }
+
+ syn String Component.prettyPrint() {
+ return "<Name: " + getName() + ", DockerComposeName: " + getDockerComposeName() + ", MqttTopicPrefix: " + getMqttTopicPrefix() + ", IncomingStatus: " + getIncomingStatus() + ", NextCommand: " + getNextCommand() + ">";
+ }
+}
+
+aspect AdditionalTypes {
+ public class ReversedList<T> extends beaver.Symbol implements Iterable<T> {
+ private java.util.Deque<T> delegatee = new java.util.ArrayDeque<>();
+
+ public java.util.Iterator<T> iterator() {
+ return delegatee.descendingIterator();
+ }
+
+ public void add(T t) {
+ delegatee.add(t);
+ }
+ }
+
+ public class StringList extends ReversedList<String> {}
+}
diff --git a/ros3rag.coordinator/src/main/jastadd/Coordinator.parser b/ros3rag.coordinator/src/main/jastadd/Coordinator.parser
new file mode 100644
index 0000000..e00f826
--- /dev/null
+++ b/ros3rag.coordinator/src/main/jastadd/Coordinator.parser
@@ -0,0 +1,65 @@
+%header {:
+package de.tudresden.inf.st.coordinator.parser;
+import de.tudresden.inf.st.coordinator.ast.*;
+import java.util.Map;
+import java.util.HashMap;
+:} ;
+
+%embed {:
+ private static <T extends ASTNode<?>> void insertZero(JastAddList<T> listNode, T child) {
+ listNode.insertChild(child, 0);
+ }
+
+ private void replaceRelations(Coordinator o) {
+ for (ParsedPrecedenceRelation rel : o.getParsedPrecedenceRelationList()) {
+ for (Component pred : rel.getPredecessorList()) {
+ for (Component succ : rel.getSuccessorList()) {
+ pred.addSuccessor(succ);
+ }
+ }
+ }
+ }
+:} ;
+
+%goal goal;
+Coordinator goal =
+ COMPONENTS LB_CURLY coordinator_body.o RB_CURLY {: o.treeResolveAll(); replaceRelations(o); return o; :}
+
+Coordinator coordinator_body =
+ component.c goal.o {: o.addComponent(c); return o; :}
+ string_list.preds LT string_list.succs goal.o
+ {:
+ ParsedPrecedenceRelation rel = new ParsedPrecedenceRelation();
+ o.addParsedPrecedenceRelation(rel);
+ preds.forEach(pred -> rel.addPredecessor(Component.createRef(pred)));
+ succs.forEach(succ -> rel.addPredecessor(Component.createRef(succ)));
+ return o;
+ :}
+ | {: return new Coordinator(); :}
+ ;
+
+Component component =
+ COMPONENT TEXT.name DOCKER_COMPOSE EQUALS TEXT.dc MQTT_TOPIC EQUALS TEXT.mqtt
+ {:
+ Component result = new Component();
+ result.setName(name);
+ result.setDockerComposeName(dc);
+ result.setMqttTopicPrefix(mqtt);
+ return result;
+ :}
+ ;
+
+StringList string_list =
+ LB_SQUARE string_list_body.slb RB_SQUARE {: return slb; :}
+ | LB_SQUARE RB_SQUARE {: return new StringList(); :}
+ ;
+
+StringList string_list_body =
+ TEXT.n COMMA string_list_body.slb {: slb.add(n); return slb; :}
+ | TEXT.n
+ {:
+ StringList result = new StringList();
+ result.add(n);
+ return result;
+ :}
+ ;
diff --git a/ros3rag.coordinator/src/main/jastadd/Coordinator.relast b/ros3rag.coordinator/src/main/jastadd/Coordinator.relast
new file mode 100644
index 0000000..f5acd03
--- /dev/null
+++ b/ros3rag.coordinator/src/main/jastadd/Coordinator.relast
@@ -0,0 +1,6 @@
+Coordinator ::= Component* ParsedPrecedenceRelation* ; // /NextComponentToStart:Component/ ;
+Component ::= <Name:String> <DockerComposeName:String> <MqttTopicPrefix:String> <IncomingStatus:String> /<NextCommand:String>/ ;
+rel Component.Predecessor* <-> Component.Successor* ;
+ParsedPrecedenceRelation ;
+rel ParsedPrecedenceRelation.Predecessor* -> Component ;
+rel ParsedPrecedenceRelation.Successor* -> Component ;
diff --git a/ros3rag.coordinator/src/main/jastadd/dummy/types.connect b/ros3rag.coordinator/src/main/jastadd/dummy/types.connect
new file mode 100644
index 0000000..e69de29
diff --git a/ros3rag.coordinator/src/main/jastadd/dummy/types.jrag b/ros3rag.coordinator/src/main/jastadd/dummy/types.jrag
new file mode 100644
index 0000000..e69de29
diff --git a/ros3rag.coordinator/src/main/jastadd/dummy/types.relast b/ros3rag.coordinator/src/main/jastadd/dummy/types.relast
new file mode 100644
index 0000000..e69de29
diff --git a/ros3rag.coordinator/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java b/ros3rag.coordinator/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java
new file mode 100644
index 0000000..e184767
--- /dev/null
+++ b/ros3rag.coordinator/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java
@@ -0,0 +1,166 @@
+package de.tudresden.inf.st.coordinator;
+
+import beaver.Parser;
+import de.tudresden.inf.st.coordinator.ast.Component;
+import de.tudresden.inf.st.coordinator.ast.Coordinator;
+import de.tudresden.inf.st.coordinator.ast.MqttHandler;
+import de.tudresden.inf.st.coordinator.parser.CoordinatorParser;
+import de.tudresden.inf.st.coordinator.scanner.CoordinatorScanner;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Entrypoint for Coordinator.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class MainCoordinator {
+
+ private static final String TOPIC_EXIT = "coordinator/exit";
+ private static final String TOPIC_MODEL = "coordinator/model";
+ private static final String TOPIC_STATUS = "coordinator/status";
+ private static final String TOPIC_READY = "coordinator/ready";
+ private Coordinator coordinator;
+ private MqttHandler mainHandler;
+ private Component rosCore;
+ private Component mosquitto;
+
+ public static void main(String[] args) throws Exception {
+ MainCoordinator main = new MainCoordinator();
+// main.manuallyBuild();
+ main.parsedBuild();
+ main.start();
+ }
+
+ private void manuallyBuild() {
+ coordinator = new Coordinator();
+ Component robotCtrlA = newComponent("Robot Control A", "ros_place_a", "ros-place-a");
+ Component robotCtrlB = newComponent("Robot Control B", "ros_place_b", "ros-place-b");
+ Component ragA = newComponent("RAG A", "rag_place_a", "rag-a");
+ Component ragB = newComponent("RAG B", "rag_place_b", "rag-b");
+ Component random = newComponent("Random Dummy", "cgv_random_dummy", "random");
+ rosCore = newComponent("ROS core", "ros_core", "");
+ mosquitto = newComponent("MQTT broker", "mosquitto", "");
+
+ coordinator.addComponent(robotCtrlA);
+ coordinator.addComponent(robotCtrlB);
+ coordinator.addComponent(ragA);
+ coordinator.addComponent(ragB);
+ coordinator.addComponent(random);
+ coordinator.addComponent(rosCore);
+ coordinator.addComponent(mosquitto);
+
+ // ros core needed for all other ros nodes
+ rosCore.addSuccessor(robotCtrlA);
+ rosCore.addSuccessor(robotCtrlB);
+ rosCore.addSuccessor(random);
+
+ // mqtt broker needed for all robot ctrl and rag nodes
+ mosquitto.addSuccessor(robotCtrlA);
+ mosquitto.addSuccessor(robotCtrlB);
+ mosquitto.addSuccessor(ragA);
+ mosquitto.addSuccessor(ragB);
+
+ // robot control needs to start before rag
+ robotCtrlA.addSuccessor(ragA);
+ robotCtrlB.addSuccessor(ragB);
+
+ // rag place B needs to start before rag place A
+ ragB.addSuccessor(ragA);
+
+ // random should start last
+ robotCtrlA.addSuccessor(random);
+ robotCtrlB.addSuccessor(random);
+ ragA.addSuccessor(random);
+ ragB.addSuccessor(random);
+ }
+
+ private void parsedBuild() throws IOException, Parser.Exception {
+ Reader in = Files.newBufferedReader(Paths.get("src", "main", "resources", "ros3rag.coordinator"));
+
+ CoordinatorScanner scanner = new CoordinatorScanner(in);
+ CoordinatorParser parser = new CoordinatorParser();
+
+ coordinator = (Coordinator) parser.parse(scanner);
+
+ for (Component comp : coordinator.getComponentList()) {
+ if (comp.getName().equals("rosCore")) {
+ rosCore = comp;
+ }
+ if (comp.getName().equals("mosquitto")) {
+ mosquitto = comp;
+ }
+ }
+
+ in.close();
+ }
+
+ private void start() throws Exception {
+ final String mqttHost = "localhost";
+
+ coordinator.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
+
+ for (Component comp : coordinator.getComponentList()) {
+ comp.connectIncomingStatus("mqtt://" + mqttHost + "/" + comp.getMqttTopicPrefix() + "/status");
+ comp.connectNextCommand("mqtt://" + mqttHost + "/" + comp.getMqttTopicPrefix() + "/command", false);
+ }
+
+ for (Component comp : coordinator.getComponentList()) {
+ comp.callDockerCompose();
+ }
+
+ mainHandler = new MqttHandler().dontSendWelcomeMessage();
+ mainHandler.setHost(mqttHost);
+ mainHandler.waitUntilReady(2, TimeUnit.SECONDS);
+ CountDownLatch exitCondition = new CountDownLatch(1);
+ mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown());
+ mainHandler.newConnection(TOPIC_MODEL, bytes -> this.printStatus());
+ mainHandler.newConnection(TOPIC_READY, bytes -> this.setReady());
+ Runtime.getRuntime().addShutdownHook(new Thread(this::close));
+
+ // wait some time for ros_core and mqtt_broker to be started
+ TimeUnit.SECONDS.sleep(2);
+
+ setReady();
+
+ exitCondition.await();
+ }
+
+ private void setReady() {
+ // set ros-core and mqtt-broker to ready
+ rosCore.setIncomingStatus("ready");
+ mosquitto.setIncomingStatus("ready");
+ }
+
+ private void printStatus() {
+ String content = coordinator.prettyPrint();
+ System.out.println(content);
+ if (mainHandler != null) {
+ mainHandler.publish(TOPIC_STATUS, content.getBytes(StandardCharsets.UTF_8));
+ }
+ }
+
+ private void close() {
+ if (coordinator != null) {
+ coordinator.ragconnectCloseConnections();
+ }
+ if (mainHandler != null) {
+ mainHandler.close();
+ }
+ }
+
+ private static Component newComponent(String name, String dockerComposeName, String mqttTopicPrefix) {
+ Component result = new Component();
+ result.setName(name);
+ result.setDockerComposeName(dockerComposeName);
+ result.setMqttTopicPrefix(mqttTopicPrefix);
+ return result;
+ }
+
+}
diff --git a/ros3rag.coordinator/src/main/resources/ros3rag.coordinator b/ros3rag.coordinator/src/main/resources/ros3rag.coordinator
new file mode 100644
index 0000000..c37c6a6
--- /dev/null
+++ b/ros3rag.coordinator/src/main/resources/ros3rag.coordinator
@@ -0,0 +1,25 @@
+components {
+ component "robotCtrlA" docker compose = "ros_place_a" mqtt topic = "ros-place-a"
+ component "robotCtrlB" docker compose = "ros_place_b" mqtt topic = "ros-place-b"
+ component "ragA" docker compose = "rag_place_a" mqtt topic = "rag-a"
+ component "ragB" docker compose = "rag_place_b" mqtt topic = "rag-b"
+ component "random" docker compose = "cgv_random_dummy" mqtt topic = "random"
+ component "rosCore" docker compose = "ros_core" mqtt topic = ""
+ component "mosquitto" docker compose = "mosquitto" mqtt topic = ""
+
+ // ros core needed for all other ros nodes
+ rosCore < robotCtrlA, robotCtrlB, random
+
+ // mqtt broker needed for all robot ctrl and rag nodes
+ mosquitto < robotCtrlA, robotCtrlB, ragA, ragB
+
+ // robot control needs to start before rag
+ robotCtrlA < ragA
+ robotCtrlB < ragB
+
+ // rag place B needs to start before rag place A
+ ragB < ragA
+
+ // random should start last
+ robotCtrlA, robotCtrlB, ragA, ragB < random
+}
diff --git a/settings.gradle b/settings.gradle
index bd2c1a8..b2e62eb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,6 +3,7 @@ rootProject.name = 'ros3rag'
include 'ros3rag.placeA'
include 'ros3rag.placeB'
include 'ros3rag.common'
+include 'ros3rag.coordinator'
// include 'ros3rag.senderstub'
// include 'ros3rag.receiverstub'
--
GitLab