diff --git a/libs/ragconnect-0.3.1.jar b/libs/ragconnect-0.3.1.jar index da8df316201d4ddede05a35e14d01f757df33582..508b2e6617ba61492f47c7237dfbf66c62314dcc 100644 Binary files a/libs/ragconnect-0.3.1.jar and b/libs/ragconnect-0.3.1.jar differ diff --git a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java index 29c0d850fd2c370f5776469701314c9ac7c5c0d5..e4ca8598e02d52aeac9d1fda7130687004e7e8a6 100644 --- a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java +++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Util.java @@ -72,14 +72,4 @@ public class Util { } return repoRoot.resolve(moduleName); } - - private static class HostAndPort { - String host; - int port; - } - - @FunctionalInterface - public interface HandleLink { - void handle(boolean isEndEffector, String topic, String name) throws IOException; - } } diff --git a/ros3rag.common/src/main/resources/tasks.gradle b/ros3rag.common/src/main/resources/tasks.gradle index 79b3eab1860edfbace31eb2fda88a3dd09f262e0..9311f58134a7a1b36e692b4de82e54c622807a1c 100644 --- a/ros3rag.common/src/main/resources/tasks.gradle +++ b/ros3rag.common/src/main/resources/tasks.gradle @@ -44,9 +44,7 @@ task grammar2uml(type: JavaExec) { args([ '--verbose', 'src/gen/jastadd/types.relast' - ] - + - project.ext.relastFiles) + ] + project.ext.relastFiles) } // phase: RelAst @@ -62,9 +60,8 @@ task relastToJastAdd(type: JavaExec) { "--serializer=jackson", "--resolverHelper", "--file", - "src/gen/jastadd/types.relast"] - + - project.ext.relastFiles) + "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") diff --git a/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/MainA.java b/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/MainA.java index 223cf3ea869712b80860ececbb4a19b6e52dd34a..6ecddba2557aad6fb43f6063442bee6f3ad49bb9 100644 --- a/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/MainA.java +++ b/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/MainA.java @@ -4,11 +4,14 @@ import de.tudresden.inf.st.placeA.ast.MqttHandler; import de.tudresden.inf.st.placeA.ast.Robot; import de.tudresden.inf.st.placeA.ast.Scene; import de.tudresden.inf.st.placeA.ast.WorldModelA; +import de.tudresden.inf.st.ros3rag.common.Configuration; import de.tudresden.inf.st.ros3rag.common.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -25,6 +28,7 @@ public class MainA { private final static String TOPIC_MODEL = "place-a/model"; private final static String TOPIC_STATUS = "place-a/status"; + private final static String TOPIC_REWIND = "place-a/rewind"; private final static String TOPIC_EXIT = "place-a/exit"; private final static String TOPIC_SCENE_INIT = "place-a/scene/init"; @@ -36,6 +40,13 @@ public class MainA { private MqttHandler mainHandler; private WorldModelA model; + private Configuration config; + + private static final Map<String, String> channelDescriptions = new LinkedHashMap<>() {{ + put(TOPIC_MODEL, "Print current model (detailed if message starts with 'detail"); + put(TOPIC_REWIND, "Rewind app to start"); + put(TOPIC_EXIT, "Exit app"); + }}; public static void main(String[] args) throws Exception { new MainA().run(args); @@ -46,9 +57,7 @@ public class MainA { // --- No configuration below this line --- - final var config = Util.parseConfig(UtilA.pathToDirectoryOfPlaceA().resolve(configFile).toFile()); - - model = new WorldModelA(); + config = Util.parseConfig(UtilA.pathToDirectoryOfPlaceA().resolve(configFile).toFile()); /// Prepare main handler mainHandler = new MqttHandler("mainHandler").dontSendWelcomeMessage(); @@ -57,6 +66,15 @@ public class MainA { mainHandler.waitUntilReady(2, TimeUnit.SECONDS); mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown()); mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes))); + mainHandler.newConnection(TOPIC_REWIND, bytes -> + { + try { + rewind("rewind"); + } catch (Exception e) { + logger.catching(e); + } + } + ); mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_BLUE, bytes -> UtilA.updatePositionOfObjectToLocation(model.getScene(), "objectRed1", "binBlue") @@ -65,6 +83,18 @@ public class MainA { UtilA.updatePositionOfObjectToLocation(model.getScene(), "objectRed1", "binRed") ); + logger.info("Supported commands: {}", channelDescriptions); + + rewind("Start"); + + Runtime.getRuntime().addShutdownHook(new Thread(this::close)); + + exitCondition.await(); + } + + private void rewind(String statusMessage) throws Exception { + model = new WorldModelA(); + /// Reading scene and robot de.tudresden.inf.st.ceti.Scene scene = readScene( UtilA.pathToDirectoryOfPlaceA().resolve(config.filenameInitialScene) @@ -83,17 +113,9 @@ public class MainA { model.connectScene(mqttUri(TOPIC_SCENE_UPDATE_FROM_ROS, config)); model.getScene().connectLogicalScene(mqttUri(TOPIC_SCENE_UPDATE_TO_PLACE_B, config), true); - logStatus("Start"); - - logger.info("To print the current model states, send a message to the topic '{}'.", TOPIC_MODEL); - logger.info("To exit the system cleanly, send a message to the topic '{}', or use Ctrl+C.", TOPIC_EXIT); + logStatus(statusMessage); mainHandler.publish(TOPIC_SCENE_INIT, scene.toByteArray()); -// logger.fatal("Skipping publishing to {} for now", TOPIC_SCENE_INIT); - - Runtime.getRuntime().addShutdownHook(new Thread(this::close)); - - exitCondition.await(); } private void setRobot(String name) { diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd b/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd index 0a63106de789c89b84ed8b808322c620287f67ae..8443d3414568223fd0c93c8e9e09c47f6ac30ec7 100644 --- a/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd +++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd @@ -21,24 +21,27 @@ aspect Computation { result.add(diff); continue; } + if (myObject.hasLocatedAt() && !otherObject.hasLocatedAt()) { + var diff = new DifferenceObjectMisplaced(); + diff.setObject(myObject); + diff.setPreviousLocation(myObject.getLocatedAt()); + result.add(diff); + continue; + } + if (!myObject.hasLocatedAt() && !otherObject.hasLocatedAt() || + (myObject.hasLocatedAt() && otherObject.hasLocatedAt() && + myObject.getLocatedAt().getName().equals(otherObject.getLocatedAt().getName()))) { + // no diff if otherObject has no location information, and if both objects are located at same location + // otherObject is always non-null, so this case does not need to be treated + continue; + } + var difference = new DifferenceObjectAtWrongPlace(); + difference.setObject(myObject); if (myObject.hasLocatedAt()) { - if (!otherObject.hasLocatedAt()) { - var diff = new DifferenceObjectMisplaced(); - diff.setObject(myObject); - diff.setPreviousLocation(myObject.getLocatedAt()); - result.add(diff); - continue; - } - if (!myObject.getLocatedAt().getName().equals(otherObject.getLocatedAt().getName())) { - // object at different locations - var difference = new DifferenceObjectAtWrongPlace(); - difference.setObject(myObject); - difference.setPreviousLocation(myObject.getLocatedAt()); - difference.setNewLocation(otherObject.getLocatedAt()); - result.add(difference); - } + difference.setPreviousLocation(myObject.getLocatedAt()); } - // other difference not handled yet, e.g. object deleted, or objects having no locations + difference.setNewLocation(otherObject.getLocatedAt()); + result.add(difference); } return result; } @@ -60,7 +63,9 @@ aspect Computation { Set<Robot> robotsFitForPreviousLocation = new HashSet<>(); Set<Robot> robotsFitForNewLocation = new HashSet<>(); for (var robot : worldModelB().getRobotList()) { - if (robot.canReach(getPreviousLocation().getName())) { + // check if robot can reach both, location (if any) and the object + if ((!hasPreviousLocation() || robot.canReach(getPreviousLocation().getName())) && + robot.canReach(getObject().getName())) { robotsFitForPreviousLocation.add(robot); } if (robot.canReach(getNewLocation().getName())) { @@ -68,7 +73,13 @@ aspect Computation { } } if (robotsFitForPreviousLocation.isEmpty()) { - return Collections.singletonList(new ErrorOperation("No robot can reach previous location " + getPreviousLocation().getName())); + StringBuilder sb = new StringBuilder("No robot can reach object "); + sb.append(getObject().getName()); + if (hasPreviousLocation()) { + sb.append(" and ").append(getPreviousLocation().getName()); + } + sb.append("!"); + return Collections.singletonList(new ErrorOperation(sb.toString())); } if (robotsFitForNewLocation.isEmpty()) { return Collections.singletonList(new ErrorOperation("No robot can reach new location " + getNewLocation().getName())); @@ -178,13 +189,13 @@ aspect Printing { syn String Difference.prettyPrint(); eq DifferenceObjectAtWrongPlace.prettyPrint() { - return "+DifferenceObjectAtWrongPlace of " + getObject().prettyPrint() + ": " + getPreviousLocation().prettyPrint() + " -> " + getNewLocation().prettyPrint() + "+"; + return "-DifferenceObjectAtWrongPlace of " + getObject().prettyPrint() + ": " + (hasPreviousLocation() ? getPreviousLocation().prettyPrint() : "_") + " -> " + getNewLocation().prettyPrint() + "-"; } eq DifferenceNewObject.prettyPrint() { - return "+DifferenceNewObject of " + getObject().prettyPrint() + "+"; + return "-DifferenceNewObject of " + getObject().prettyPrint() + "-"; } eq DifferenceObjectMisplaced.prettyPrint() { - return "+DifferenceObjectMisplaced of " + getObject().prettyPrint() + ": " + getPreviousLocation().prettyPrint() + "+"; + return "-DifferenceObjectMisplaced of " + getObject().prettyPrint() + ": " + getPreviousLocation().prettyPrint() + "-"; } syn String Operation.prettyPrint(); diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.relast b/ros3rag.placeB/src/main/jastadd/WorldModelB.relast index dbb21249db70b8a3a05ded34b61b5d0cb94a06b6..3263e7ff0b6d8b9de31237299829ed48abce0292 100644 --- a/ros3rag.placeB/src/main/jastadd/WorldModelB.relast +++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.relast @@ -5,7 +5,7 @@ Robot ::= <Name:String> CanReachObjectOfInterestWrapper ; abstract Difference ; rel Difference.Object -> LogicalMovableObject ; DifferenceObjectAtWrongPlace : Difference ; -rel DifferenceObjectAtWrongPlace.PreviousLocation -> LogicalDropOffLocation ; +rel DifferenceObjectAtWrongPlace.PreviousLocation? -> LogicalDropOffLocation ; rel DifferenceObjectAtWrongPlace.NewLocation -> LogicalDropOffLocation ; DifferenceNewObject : Difference ; DifferenceObjectMisplaced : Difference ; diff --git a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/MainB.java b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/MainB.java index d7ce667c1169305a873e22d5b73adb254a2d89ce..201fa0eba667d16d21520f99e937eaa23415af0a 100644 --- a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/MainB.java +++ b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/MainB.java @@ -7,9 +7,12 @@ import de.tudresden.inf.st.ros3rag.common.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -26,6 +29,7 @@ public class MainB { private final static String TOPIC_MODEL = "place-b/model"; private final static String TOPIC_STATUS = "place-b/status"; + private final static String TOPIC_REWIND = "place-b/rewind"; private final static String TOPIC_EXIT = "place-b/exit"; private final static String TOPIC_MY_SCENE_INIT = "place-b/scene/init"; @@ -39,6 +43,13 @@ public class MainB { private MqttHandler mainHandler; private WorldModelB model; + private Configuration config; + + private static final Map<String, String> channelDescriptions = new LinkedHashMap<>() {{ + put(TOPIC_MODEL, "Print current model (detailed if message starts with 'detail"); + put(TOPIC_REWIND, "Rewind app to start"); + put(TOPIC_EXIT, "Exit app"); + }}; public static void main(String[] args) throws Exception { new MainB().run(args); @@ -49,8 +60,7 @@ public class MainB { // --- No configuration below this line --- - final var config = Util.parseConfig(UtilB.pathToDirectoryOfPlaceB().resolve(configFile).toFile()); - model = new WorldModelB(); + config = Util.parseConfig(UtilB.pathToDirectoryOfPlaceB().resolve(configFile).toFile()); /// Prepare main handler mainHandler = new MqttHandler("mainHandler").dontSendWelcomeMessage(); @@ -59,11 +69,32 @@ public class MainB { CountDownLatch exitCondition = new CountDownLatch(1); mainHandler.newConnection(TOPIC_EXIT, bytes -> exitCondition.countDown()); mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes))); + mainHandler.newConnection(TOPIC_REWIND, bytes -> + { + try { + rewind("rewind"); + } catch (Exception e) { + logger.catching(e); + } + } + ); mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_RED, bytes -> UtilB.updatePositionOfObjectToLocation(model.getMyScene(), "objectRed1", "binRed") ); + logger.info("Supported commands: {}", channelDescriptions); + + rewind("Start"); + + Runtime.getRuntime().addShutdownHook(new Thread(this::close)); + + exitCondition.await(); + } + + private void rewind(String statusMessage) throws Exception { + model = new WorldModelB(); + /// Reading scene and robots de.tudresden.inf.st.ceti.Scene scene = readScene( UtilB.pathToDirectoryOfPlaceB().resolve(config.filenameInitialScene) @@ -99,17 +130,9 @@ public class MainB { model.connectOtherScene(mqttUri(TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A, config)); model.connectNextOperation(mqttUri(TOPIC_COMMAND, config), false); - logStatus("Start"); - - logger.info("To print the current model states, send a message to the topic '{}'.", TOPIC_MODEL); - logger.info("To exit the system cleanly, send a message to the topic '{}', or use Ctrl+C.", TOPIC_EXIT); + logStatus(statusMessage); mainHandler.publish(TOPIC_MY_SCENE_INIT, scene.toByteArray()); -// logger.fatal("Skipping publishing to {} for now", TOPIC_MY_SCENE_INIT); - - Runtime.getRuntime().addShutdownHook(new Thread(this::close)); - - exitCondition.await(); } private void logStatus(String message) {