From 0e2c0f00bf3374dac8f3c06376d265aa64b12cf6 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Thu, 5 May 2022 18:16:06 +0200 Subject: [PATCH] working on real collaboration - update config structure - fixed exit and rewind - reread config on rewind - read regions on both sites - add demo commands for site B - create svg at model-command for site-B, and publish filename - enhance compute-operations: source location can be collaboration zone as well, add wait command when zone is not owned and occupied - connect occupiedCollaborationZoneNames with self-loop and "moving-in" and "moving-out" logic --- .../inf/st/ros3rag/common/Configuration.java | 14 ++- .../st/ros3rag/common/SharedMainParts.java | 22 +++-- .../de/tudresden/inf/st/placeA/MainA.java | 10 +- .../de/tudresden/inf/st/placeA/UtilA.java | 13 +++ .../main/resources/config-a-placeworld.yaml | 5 + .../src/main/jastadd/WorldModelB.connect | 71 ++++++++++++++- .../src/main/jastadd/WorldModelB.jadd | 66 +++++++++++--- .../src/main/jastadd/WorldModelB.relast | 4 +- .../de/tudresden/inf/st/placeB/MainB.java | 91 ++++++++++++++++--- .../tudresden/inf/st/placeB/SimpleMainB.java | 72 +++++---------- .../de/tudresden/inf/st/placeB/UtilB.java | 27 +++++- .../main/resources/config-b-placeworld.yaml | 15 ++- .../main/resources/regions-b-placeworld.json | 3 +- 13 files changed, 317 insertions(+), 96 deletions(-) create mode 100644 ros3rag.placeA/src/main/resources/config-a-placeworld.yaml diff --git a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Configuration.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Configuration.java index daf8b29..ee6c6f5 100644 --- a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Configuration.java +++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/Configuration.java @@ -12,13 +12,19 @@ import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) public class Configuration { public String mqttHost; - public String filenameInitialSceneA; public String filenameRegions; public String coordinatorMqttTopicPrefix; - public List<ReachabilityConfig> reachability; + public ConfigurationForA forA; + public ConfigurationForB forB; - public static class ReachabilityConfig { - public String filename; + public static class ConfigurationForA { + public String filenameInitialScene; + } + + public static class ConfigurationForB { + public List<String> reachability; + public List<String> topicsSceneUpdate; + public String topicCommand; } public boolean useCoordinator() { diff --git a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/SharedMainParts.java b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/SharedMainParts.java index 0204821..89e81de 100644 --- a/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/SharedMainParts.java +++ b/ros3rag.common/src/main/java/de/tudresden/inf/st/ros3rag/common/SharedMainParts.java @@ -65,18 +65,21 @@ public abstract class SharedMainParts<MqttHandler extends SharedMainParts.MqttHa mainHandler.newConnection(TOPIC_EXIT, bytes -> { logger.info("Got exit command"); exitCondition.countDown(); + startCondition.countDown(); logger.debug("exit latch count = {}, start latch count= {}", exitCondition.getCount(), startCondition.getCount()); }); mainHandler.newConnection(TOPIC_MODEL, bytes -> logStatus(new String(bytes))); mainHandler.newConnection(TOPIC_REWIND, bytes -> - { - try { - rewind("rewind"); - } catch (Exception e) { - logger.catching(e); + new Thread(() -> { + { + try { + rewind("rewind"); + } catch (Exception e) { + logger.catching(e); + } } - } + }).start() ); if (config.useCoordinator()) { logger.info("Using coordinator logic"); @@ -136,11 +139,14 @@ public abstract class SharedMainParts<MqttHandler extends SharedMainParts.MqttHa logger.debug("Closing previous connections for {}", cellName); model.ragconnectCloseConnections(); } + + config = Util.parseConfig(pathToConfig.toFile()); + logger.debug("Creating world model for {}", cellName); model = createWorldModel(); logger.debug("Reading robots for {}", cellName); - readRobotsAndReachability(); + readInitialConfigs(); logger.debug("Setup model connection for {}", cellName); model.ragconnectCheckIncremental(); @@ -172,7 +178,7 @@ public abstract class SharedMainParts<MqttHandler extends SharedMainParts.MqttHa protected abstract WorldModel createWorldModel() throws Exception; - protected abstract void readRobotsAndReachability() throws Exception; + protected abstract void readInitialConfigs() throws Exception; protected abstract void connectEndpoints() throws IOException; 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 2dfe785..a0dc2e0 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,7 +4,9 @@ import de.tudresden.inf.st.placeA.ast.MqttHandler; import de.tudresden.inf.st.placeA.ast.Scene; import de.tudresden.inf.st.placeA.ast.WorldModelA; import de.tudresden.inf.st.ros3rag.common.SharedMainParts; +import de.tudresden.inf.st.ros3rag.common.Util; +import java.io.File; import java.io.IOException; import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri; @@ -62,14 +64,18 @@ public class MainA extends SharedMainParts<MqttHandler, WorldModelA> { @Override protected WorldModelA createWorldModel() throws Exception { de.tudresden.inf.st.ceti.Scene scene = readScene( - UtilA.pathToDirectoryOfPlaceA().resolve(config.filenameInitialSceneA) + UtilA.pathToDirectoryOfPlaceA().resolve(config.forA.filenameInitialScene) ); Scene myScene = UtilA.convert(scene); return new WorldModelA().setScene(myScene); } @Override - protected void readRobotsAndReachability() { + protected void readInitialConfigs() throws IOException { + // read and set regions + File regionFile = UtilA.pathToDirectoryOfPlaceA().resolve(config.filenameRegions).toFile(); + UtilA.setRegions(model, Util.parseRegionConfig(regionFile)); + // no robots to be set } diff --git a/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/UtilA.java b/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/UtilA.java index 405f67a..0fea7e2 100644 --- a/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/UtilA.java +++ b/ros3rag.placeA/src/main/java/de/tudresden/inf/st/placeA/UtilA.java @@ -1,6 +1,8 @@ package de.tudresden.inf.st.placeA; import de.tudresden.inf.st.placeA.ast.*; +import de.tudresden.inf.st.ros3rag.common.RegionConfiguration; +import de.tudresden.inf.st.ros3rag.common.RegionConfiguration.RegionDefinition; import de.tudresden.inf.st.ros3rag.common.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,6 +25,17 @@ public class UtilA { return new ExposingASTNode().exposed_apply_ConvertScene(scene); } + static void setRegions(WorldModelA model, RegionConfiguration config) { + JastAddList<Region> result = new JastAddList<>(); + for (RegionDefinition def : config.regions) { + Region region = new Region(); + region.setName(def.name); + region.setLocationNames(String.join(",", def.positions)); + result.add(region); + } + model.setRegionList(result); + } + static void updatePositionOfObjectToLocation(Scene scene, String objName, String locationName) { ObjectOfInterest obj = scene.resolveObjectOfInterest(objName); ObjectOfInterest location = scene.resolveObjectOfInterest(locationName); diff --git a/ros3rag.placeA/src/main/resources/config-a-placeworld.yaml b/ros3rag.placeA/src/main/resources/config-a-placeworld.yaml new file mode 100644 index 0000000..19e4029 --- /dev/null +++ b/ros3rag.placeA/src/main/resources/config-a-placeworld.yaml @@ -0,0 +1,5 @@ +mqttHost: "192.168.0.122" +filenameRegions: "src/main/resources/regions-a-placeworld.json" +forA: + filenameInitialScene: "src/main/resources/config-scene-a-placeworld.json" +coordinatorMqttTopicPrefix: "coordinating/rag-a" diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.connect b/ros3rag.placeB/src/main/jastadd/WorldModelB.connect index 2ef0239..de33b2f 100644 --- a/ros3rag.placeB/src/main/jastadd/WorldModelB.connect +++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.connect @@ -4,6 +4,7 @@ receive indexed WorldModelB.OtherScene ; receive WorldModelB.TestingOtherScene ; receive Robot.CanReachObjectOfInterestWrapper using ParseReachability, ConvertReachability ; receive Robot.OwnedCollaborationZoneNames using ConfigChangeCommandCheckForOwnedCollaborationZone ; +receive Robot.OccupiedCollaborationZoneNames using CommandCheckForOccupiedCollaborationZone ; // --- sending --- send WorldModelB.NextOperation using PrintOperation ; @@ -27,7 +28,7 @@ ConfigChangeCommandCheckForOwnedCollaborationZone maps byte[] bytes to String {: if (!command.hasConfigChange()) { reject(); } - System.out.println(command); +// System.out.println(command); de.tudresden.inf.st.ceti.ConfigChange cc = command.getConfigChange(); Scene scene = worldModelB().getMyScene(); ObjectOfInterest obj = scene.resolveObjectOfInterest(cc.getIdCollaborationZone()); @@ -49,3 +50,71 @@ ConfigChangeCommandCheckForOwnedCollaborationZone maps byte[] bytes to String {: } return String.join(",", collaborationZoneNames); :} + +CommandCheckForOccupiedCollaborationZone maps byte[] bytes to String {: + de.tudresden.inf.st.ceti.Command command = null; + try { + command = de.tudresden.inf.st.ceti.Command.parseFrom(bytes); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + reject(); + } + // if the command is not the correct command type, do not change anything + if (!command.hasPickAndPlace() && !command.hasEvacuate()) { + reject(); + } +// System.out.println(command); + + Scene scene = worldModelB().getMyScene(); + Robot thisRobot = (Robot) this; + +// // get current value, but remove every "moving out" zone +// List<String> occupiedZoneNames = thisRobot.occupiedCollaborationZonesAsList().stream() +// .filter(!zone -> zone.startsWith("(^)")) +// .collect(java.util.stream.Collectors.toList()); + + // with a new command, begin with a clean occ list + List<String> occupiedZoneNames = new java.util.ArrayList<>(); + + // (>) == moving in, (^) == evacuate/moving out + boolean updated = false; + if (command.hasPickAndPlace()) { + de.tudresden.inf.st.ceti.PickAndPlace pp = command.getPickAndPlace(); + + // if the command is not executed by this robot, do not change anything + if (!thisRobot.getName().equals(pp.getIdRobot())) { + reject(); + } + + ObjectOfInterest obj = scene.resolveObjectOfInterest(pp.getIdPlace()); + DropOffLocation loc = obj.asDropOffLocation(); + if (loc.isCollaborationZone()) { + CollaborationZone cz = loc.asCollaborationZone(); + String specialIncomingName = "(>)" + cz.getName(); + if (!occupiedZoneNames.contains(specialIncomingName)) { + occupiedZoneNames.add(specialIncomingName); + updated = true; + } + } + } else if (command.hasEvacuate()) { + de.tudresden.inf.st.ceti.Evacuate ev = command.getEvacuate(); + + // if the command is not executed by this robot, do not change anything + if (!thisRobot.getName().equals(ev.getIdRobot())) { + reject(); + } + ObjectOfInterest obj = scene.resolveObjectOfInterest(ev.getIdCollaborationZone()); + DropOffLocation loc = obj.asDropOffLocation(); + if (loc.isCollaborationZone()) { + CollaborationZone cz = loc.asCollaborationZone(); + String specialEvacuateName = "(^)" + cz.getName(); + if (!occupiedZoneNames.contains(specialEvacuateName)) { + occupiedZoneNames.add(specialEvacuateName); + updated = true; + } + } + } + if (!updated) { + reject(); + } + return String.join(",", occupiedZoneNames); +:} diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd b/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd index 0980bd0..6142c56 100644 --- a/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd +++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.jadd @@ -165,22 +165,43 @@ aspect Computation { Vertex transit = previousVertex; for (Edge edge : shortestPath) { Vertex target = edge.getFrom().equals(transit) ? edge.getTo() : edge.getFrom(); + DropOffLocation sourceLocation = worldModelB().getMyScene().resolveObjectOfInterest(previousVertex.asVertexWithObjectOfInterest().getNameOfObjectOfInterest()).asDropOffLocation(); DropOffLocation targetLocation = worldModelB().getMyScene().resolveObjectOfInterest(target.asVertexWithObjectOfInterest().getNameOfObjectOfInterest()).asDropOffLocation(); // Robot executingRobot = worldModelB().findRobot(edge.asEdgeWithRobot().getNameOfRobot()); worldModelB().findRobot(edge.asEdgeWithRobot().getNameOfRobot()).ifPresentOrElse(executingRobot -> { + /* for both locations, in case it is a collaboration zone, we need to ensure the following: + (a) claimed by the executing robot, and + (b) not occupied by another robot, and + (c) free (as no movable object is contained) -- this should be reflected in the graph! + */ + if (sourceLocation.isCollaborationZone()) { + CollaborationZone cz = sourceLocation.asCollaborationZone(); + System.out.println("source is cz, occ:" + (cz.hasOccupient() ? cz.occupient().nameAndHash() : "none") + ", owner: " + (cz.hasOwner() ? cz.owner().nameAndHash() : "none")); + // order is important here, first add Evacuate, then ConfigChange + if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) { + result.add(Evacuate.of(cz.occupient(), cz)); + } + if (!cz.hasOwner() || (cz.hasOwner() && !cz.owner().equals(executingRobot))) { + if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) { + result.add(Wait.of()); + } else { + result.add(ConfigChange.of(executingRobot, cz)); + } + } + } if (targetLocation.isCollaborationZone()) { - /* here we need to check, if the collaboration zone is - (a) claimed by the executing robot, and - (b) occupied by another robot, and - (c) free (as no movable object is contained) -- this should be reflected in the graph! - */ CollaborationZone cz = targetLocation.asCollaborationZone(); + System.out.println("target is cz, occ:" + (cz.hasOccupient() ? cz.occupient().nameAndHash() : "none") + ", owner: " + (cz.hasOwner() ? cz.owner().nameAndHash() : "none")); // order is important here, first add Evacuate, then ConfigChange if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) { result.add(Evacuate.of(cz.occupient(), cz)); } if (!cz.hasOwner() || (cz.hasOwner() && !cz.owner().equals(executingRobot))) { - result.add(ConfigChange.of(executingRobot, cz)); + if (cz.hasOccupient() && !cz.occupient().equals(executingRobot)) { + result.add(Wait.of()); + } else { + result.add(ConfigChange.of(executingRobot, cz)); + } } } result.add(PickAndPlace.of(executingRobot, getObject(), targetLocation)); @@ -229,6 +250,10 @@ aspect Computation { return result; } + public static Wait Wait.of() { + return new Wait(); + } + //--- getNextOperation --- syn Operation WorldModelB.getNextOperation() { if (diffToOperations().getNumChild() == 0) { @@ -306,6 +331,7 @@ aspect AttributeMappings { .setIdCollaborationZone(getCollaborationZone().getName()) .build()) .build().toByteArray(); + eq Wait.toProtobufByteArray() = null; } aspect Navigation { @@ -323,9 +349,20 @@ aspect Navigation { // eq WorldModelB.getChild().allMappings() = getLocationMapping(); syn boolean CollaborationZone.hasOccupient() = occupient() != null; syn Robot CollaborationZone.occupient() { + // (>) == moving in, (^) == evacuate/moving out for (Robot robot : worldModelB().getRobotList()) { - if (getName().equals(robot.getOccupiedCollaborationZoneName())) { - return robot; + for (String zoneName : arrayAsList(robot.getOccupiedCollaborationZoneNames())) { + if (zoneName.startsWith("(>)") && zoneName.substring(3).equals(getName())) { + // robot is currently moving into this zone. always regard it as occupied by it + return robot; + } + if (zoneName.startsWith("(^)") && zoneName.substring(3).equals(getName()) && robot.isBusy()) { + // robot is busy moving out of this zone. regard it as occupied as long as the robot is busy + return robot; + } + if (zoneName.equals(getName())) { + return robot; + } } } return null; @@ -333,7 +370,7 @@ aspect Navigation { syn boolean CollaborationZone.hasOwner() = owner() != null; syn Robot CollaborationZone.owner() { for (Robot robot : worldModelB().getRobotList()) { - List<String> collaborationZoneNames = Arrays.asList(robot.getOwnedCollaborationZoneNames().split(",")); + List<String> collaborationZoneNames = arrayAsList(robot.getOwnedCollaborationZoneNames()); if (collaborationZoneNames.contains(getName())) { return robot; } @@ -341,6 +378,7 @@ aspect Navigation { return null; } syn List<String> Robot.ownedCollaborationZonesAsList() = arrayAsList(getOwnedCollaborationZoneNames()); + syn List<String> Robot.occupiedCollaborationZonesAsList() = arrayAsList(getOccupiedCollaborationZoneNames()); eq Region.locationList() { List<DropOffLocation> result = new ArrayList<>(); if (!worldModelB().hasMyScene()) { return result; } @@ -398,18 +436,24 @@ aspect Printing { eq Evacuate.prettyPrint() { return "+Evacuate: " + getRobotToExecute().prettyPrint() + " from " + getCollaborationZone().prettyPrint() + "+"; } + eq Wait.prettyPrint() { + return "+Wait+"; + } } aspect DumpAst { - public void WorldModelB.dumpAst(java.util.function.Consumer<de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder> options) { + public String WorldModelB.dumpAst(java.util.function.Consumer<de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder> options) { String now = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME).replaceAll("[:\\.]", "-"); try { de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder builder = de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper.read(this); options.accept(builder); //builder.dumpAsPNG(java.nio.file.Paths.get("images/" + now + ".png")); - builder.dumpAsSVG(java.nio.file.Paths.get("images/" + now + ".svg")); + java.nio.file.Path path = java.nio.file.Paths.get("images/" + now + ".svg"); + builder.dumpAsSVG(path); + return path.getFileName().toString(); } catch (java.io.IOException e) { e.printStackTrace(); + return null; } } } diff --git a/ros3rag.placeB/src/main/jastadd/WorldModelB.relast b/ros3rag.placeB/src/main/jastadd/WorldModelB.relast index e6bb98b..7dc16b5 100644 --- a/ros3rag.placeB/src/main/jastadd/WorldModelB.relast +++ b/ros3rag.placeB/src/main/jastadd/WorldModelB.relast @@ -1,7 +1,7 @@ WorldModelB ::= Region* Robot* [MyScene:Scene] OtherScene:LogicalScene* /NextOperation:Operation/ TestingOtherScene:LogicalScene* ; // FIXME inline CanReachObjectOfInterestWrapper -Robot ::= <Name:String> CanReachObjectOfInterestWrapper <OwnedCollaborationZoneNames> <OccupiedCollaborationZoneName> ; +Robot ::= <Name:String> CanReachObjectOfInterestWrapper <OwnedCollaborationZoneNames> <OccupiedCollaborationZoneNames> ; // relations into nodes received by RagConnect are not allowed //rel Robot.OwnedCollaborationZone* <-> CollaborationZone.Owner? ; //rel Robot.OccupiedCollaborationZone? <-> CollaborationZone.Occupient? ; @@ -34,3 +34,5 @@ rel ConfigChange.CollaborationZone -> CollaborationZone ; Evacuate : Operation ; rel Evacuate.CollaborationZone -> CollaborationZone ; + +Wait : Operation ; 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 4095335..027516d 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 @@ -1,13 +1,18 @@ package de.tudresden.inf.st.placeB; +import de.tudresden.inf.st.ceti.Object; import de.tudresden.inf.st.ceti.Reachability; import de.tudresden.inf.st.placeB.ast.*; import de.tudresden.inf.st.ros3rag.common.Configuration; import de.tudresden.inf.st.ros3rag.common.SharedMainParts; +import de.tudresden.inf.st.ros3rag.common.Util; +import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.function.Function; import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri; @@ -17,19 +22,16 @@ import static de.tudresden.inf.st.ros3rag.common.Util.mqttUri; * @author rschoene - Initial contribution */ public class MainB extends SharedMainParts<MqttHandler, WorldModelB> { - private final String TOPIC_MY_SCENE_UPDATE_FROM_ROS; - private final String TOPIC_COMMAND; - private final String TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A; private final String TOPIC_DEMO_MOVE_objectRed1_RED; + private final String TOPIC_MODEL_SVG_PATH; + + private de.tudresden.inf.st.ceti.Scene demo_scene; MainB(String configFile) { super("place-b", UtilB.pathToDirectoryOfPlaceB().resolve(configFile)); - this.TOPIC_MY_SCENE_UPDATE_FROM_ROS = cellName + "/scene/update"; - this.TOPIC_COMMAND = cellName + "/command"; - - this.TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A = "place-a/logical/update"; this.TOPIC_DEMO_MOVE_objectRed1_RED = cellName + "/demo/move/objectRed1/red"; + this.TOPIC_MODEL_SVG_PATH = cellName + "/model/svg/path"; } public static void main(String[] args) throws Exception { @@ -47,6 +49,47 @@ public class MainB extends SharedMainParts<MqttHandler, WorldModelB> { mainHandler.newConnection(TOPIC_DEMO_MOVE_objectRed1_RED, bytes -> UtilB.updatePositionOfObjectToLocation(model.getMyScene(), "objectRed1", "binRed") ); + mainHandler.newConnection("demo/initial_scene", bytes -> { + try { + demo_scene = Util.readScene(UtilB.pathToDirectoryOfPlaceB().resolve("src/main/resources/config-scene-b-placeworld-manual.json")); + mainHandler.publish(config.forB.topicsSceneUpdate.get(0), demo_scene.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + }); + mainHandler.newConnection("demo/arm1/active", bytes -> + updateAndPublishScene("arm1", robot -> robot.toBuilder().setActive(true).build())); + mainHandler.newConnection("demo/arm1/inactive", bytes -> + updateAndPublishScene("arm1", robot -> robot.toBuilder().setActive(false).build())); + mainHandler.newConnection("demo/arm2/active", bytes -> + updateAndPublishScene("arm2", robot -> robot.toBuilder().setActive(true).build())); + mainHandler.newConnection("demo/arm2/inactive", bytes -> + updateAndPublishScene("arm2", robot -> robot.toBuilder().setActive(false).build())); + mainHandler.newConnection("demo/big-blue/cz", bytes -> + updateAndPublishScene("bigBlue", bigBlue -> { + Object.Builder builder = bigBlue.toBuilder(); + builder.getPosBuilder() + .setX(0.0012) + .setY(0.65) + .setZ(0.94); + return builder.build(); + }) + ); + mainHandler.newConnection("demo/big-blue/g1", bytes -> + updateAndPublishScene("bigBlue", bigBlue -> { + Object.Builder builder = bigBlue.toBuilder(); + builder.getPosBuilder() + .setX(0.1) + .setY(1.0) + .setZ(0.93); + return builder.build(); + }) + ); + } + + private void updateAndPublishScene(String objectName, Function<Object, Object> change) { + UtilB.updateObject(demo_scene, objectName, change); + mainHandler.publish(config.forB.topicsSceneUpdate.get(0), demo_scene.toByteArray()); } @Override @@ -57,13 +100,17 @@ public class MainB extends SharedMainParts<MqttHandler, WorldModelB> { } @Override - protected void readRobotsAndReachability() throws Exception { + protected void readInitialConfigs() throws Exception { model.setMyScene(new Scene()); + // read and set regions + File regionBFile = UtilB.pathToDirectoryOfPlaceB().resolve(config.filenameRegions).toFile(); + UtilB.setRegions(model, Util.parseRegionConfig(regionBFile)); + // init robots and reachability - for (Configuration.ReachabilityConfig reachabilityConfig : config.reachability) { + for (String reachabilityFileName : config.forB.reachability) { // assumption: robots do not change during runtime, so we have stable connections - Path path = UtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(reachabilityConfig.filename)); + Path path = UtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(reachabilityFileName)); Reachability reachability = UtilB.readReachability(path); Robot robot = UtilB.createRobot(reachability.getIdRobot()); @@ -76,17 +123,33 @@ public class MainB extends SharedMainParts<MqttHandler, WorldModelB> { @Override protected void connectEndpoints() throws IOException { - model.connectMyScene(mqttUri(TOPIC_MY_SCENE_UPDATE_FROM_ROS, config)); - model.connectOtherScene(mqttUri(TOPIC_OTHER_SCENE_UPDATE_FROM_PLACE_A, config), 0); - model.connectNextOperation(mqttUri(TOPIC_COMMAND, config), false); + for (String topic : config.forB.topicsSceneUpdate) { + model.connectMyScene(mqttUri(topic, config)); + } + model.connectOtherScene(mqttUri("place-a/logical/update", config), 0); + model.connectNextOperation(mqttUri(config.forB.topicCommand, config), false); for (Robot robot : model.getRobotList()) { // self-loop - robot.connectOwnedCollaborationZoneNames(mqttUri(TOPIC_COMMAND, config)); + robot.connectOwnedCollaborationZoneNames(mqttUri(config.forB.topicCommand, config)); + robot.connectOccupiedCollaborationZoneNames(mqttUri(config.forB.topicCommand, config)); } } @Override protected String getModelInfos(WorldModelB worldModelB, boolean detailed) { + try { + String filename = model.dumpAst(builder -> { + builder.excludeChildren("Orientation", "Size"); + builder.excludeRelations("ContainedInRegion"); + builder.includeNonterminalAttributes("LogicalScene", "diffScenes", "diffToOperations"); + builder.includeAttributes("realRegion", "computeOperations"); + builder.includeNullNodes(); + }); + mainHandler.publish(TOPIC_MODEL_SVG_PATH, filename.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + logger.catching(e); + } + return UtilB.getModelInfos(model, detailed); } diff --git a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java index 41630be..8021b43 100644 --- a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java +++ b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/SimpleMainB.java @@ -4,7 +4,6 @@ import de.tudresden.inf.st.ceti.Object; import de.tudresden.inf.st.ceti.Reachability; import de.tudresden.inf.st.placeB.ast.*; import de.tudresden.inf.st.ros3rag.common.Configuration; -import de.tudresden.inf.st.ros3rag.common.Configuration.ReachabilityConfig; import de.tudresden.inf.st.ros3rag.common.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -18,7 +17,6 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -64,7 +62,7 @@ public class SimpleMainB { @SuppressWarnings("unused" ) Scenario[] allScenarios = new Scenario[] { s2022, sMini, sPlaceworld, sPlaceworldManual }; - final Scenario scenario = sPlaceworldManual; + final Scenario scenario = sPlaceworld; public static void main(String[] args) throws Exception { System.out.println("Running SimpleMainB"); @@ -81,11 +79,10 @@ public class SimpleMainB { config.mqttHost = scenario.mqttHost; String filenameInitialSceneB = "src/main/resources/config-scene-b-" + scenario.suffix + ".json"; config.filenameRegions = "src/main/resources/regions-b-" + scenario.suffix + ".json"; - ReachabilityConfig reachabilityR1 = new ReachabilityConfig(); - reachabilityR1.filename = "src/main/resources/reachability-b-r1-" + scenario.suffix + ".json"; - ReachabilityConfig reachabilityR2 = new ReachabilityConfig(); - reachabilityR2.filename = "src/main/resources/reachability-b-r2-" + scenario.suffix + ".json"; - config.reachability = Arrays.asList(reachabilityR1, reachabilityR2); + config.forB.reachability = Arrays.asList( + "src/main/resources/reachability-b-r1-" + scenario.suffix + ".json", + "src/main/resources/reachability-b-r2-" + scenario.suffix + ".json" + ); Configuration configA = new Configuration(); String filenameInitialSceneA = "src/main/resources/config-scene-a-" + scenario.suffix + ".json"; @@ -108,20 +105,20 @@ public class SimpleMainB { mqttHandler.waitUntilReady(2, TimeUnit.SECONDS); model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS); - Scene myScene; + Scene myScene = new Scene(); // read initial scene Path initialSceneFile = UtilB.pathToDirectoryOfPlaceB().resolve(filenameInitialSceneB); - de.tudresden.inf.st.ceti.Scene initialScene = Util.readScene(initialSceneFile); - if (scenario.loadAndChangeScenes) { - myScene = UtilB.convert(initialScene); - } else { - myScene = new Scene(); - - mqttHandler.newConnection("coordinating/rag-b/command", bytes -> { - if (new String(bytes).equals("start")) { - mqttHandler.publish(scenario.topicSceneUpdateB, initialScene.toByteArray()); - } - }); + if (initialSceneFile.toFile().exists()) { + de.tudresden.inf.st.ceti.Scene initialScene = Util.readScene(initialSceneFile); + if (scenario.loadAndChangeScenes) { + myScene = UtilB.convert(initialScene); + } else { + mqttHandler.newConnection("coordinating/rag-b/command", bytes -> { + if (new String(bytes).equals("start")) { + mqttHandler.publish(scenario.topicSceneUpdateB, initialScene.toByteArray()); + } + }); + } } model.setMyScene(myScene); @@ -130,9 +127,9 @@ public class SimpleMainB { UtilB.setRegions(model, Util.parseRegionConfig(regionBFile)); // init robots and reachability - for (ReachabilityConfig reachabilityConfig : config.reachability) { + for (String reachabilityFileName : config.forB.reachability) { // assumption: robots do not change during runtime, so we have stable connections - Path path = UtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(reachabilityConfig.filename)); + Path path = UtilB.pathToDirectoryOfPlaceB().resolve(Paths.get(reachabilityFileName)); Reachability reachability = UtilB.readReachability(path); Robot robot = UtilB.createRobot(reachability.getIdRobot()); @@ -188,7 +185,9 @@ public class SimpleMainB { LogicalScene logicalSceneFromPlaceA = sceneFromPlaceA.getLogicalScene(); byte[] bytesToSend = _ragconnect__apply__TreeDefaultLogicalSceneToBytesMapping(logicalSceneFromPlaceA); - if (scenario.loadAndChangeScenes) { + if (scenario.loadAndChangeScenes && initialSceneFile.toFile().exists()) { + de.tudresden.inf.st.ceti.Scene initialScene = Util.readScene(initialSceneFile); + describedWait(1, "send new logical scene" ); mqttHandler.publish(topicUpdateFromPlaceA, bytesToSend); @@ -246,7 +245,7 @@ public class SimpleMainB { de.tudresden.inf.st.ceti.Scene scene, @SuppressWarnings("SameParameterValue" ) String objectName, Position newPosition) { - return updateObject(scene, objectName, obj -> { + return UtilB.updateObject(scene, objectName, obj -> { Object.Builder builder = obj.toBuilder(); builder.getPosBuilder() .setX(newPosition.getX()) @@ -259,30 +258,7 @@ public class SimpleMainB { static de.tudresden.inf.st.ceti.Scene updateNotBusyOfRobot( de.tudresden.inf.st.ceti.Scene scene, String objectName) { - return updateObject(scene, objectName, obj -> obj.toBuilder().setActive(false).build()); - } - - static de.tudresden.inf.st.ceti.Scene updateObject( - de.tudresden.inf.st.ceti.Scene scene, - String objectName, - Function<Object, Object> change) { - List<Object> objectsList = scene.getObjectsList(); - Object newObj = null; - int index, objectsListSize; - for (index = 0, objectsListSize = objectsList.size(); index < objectsListSize; index++) { - Object obj = objectsList.get(index); - if (obj.getId().equals(objectName)) { - newObj = change.apply(obj); - break; - } - } - if (newObj == null) { - logger.error("Did not find object {}!", objectName); - } else { - scene = scene.toBuilder().setObjects(index, newObj).build(); - logger.info("Update {} in scene to:\n {}", objectName, newObj); - } - return scene; + return UtilB.updateObject(scene, objectName, obj -> obj.toBuilder().setActive(false).build()); } diff --git a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/UtilB.java b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/UtilB.java index d58dc9e..0619a5a 100644 --- a/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/UtilB.java +++ b/ros3rag.placeB/src/main/java/de/tudresden/inf/st/placeB/UtilB.java @@ -1,6 +1,7 @@ package de.tudresden.inf.st.placeB; import com.google.protobuf.util.JsonFormat; +import de.tudresden.inf.st.ceti.Object; import de.tudresden.inf.st.ceti.Reachability; import de.tudresden.inf.st.placeB.ast.*; import de.tudresden.inf.st.ros3rag.common.RegionConfiguration; @@ -12,7 +13,8 @@ import org.apache.logging.log4j.Logger; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.stream.Collectors; +import java.util.List; +import java.util.function.Function; /** * Static utility methods used only for place B. @@ -153,6 +155,29 @@ public class UtilB { model.setRegionList(result); } + static de.tudresden.inf.st.ceti.Scene updateObject( + de.tudresden.inf.st.ceti.Scene scene, + String objectName, + Function<Object, Object> change) { + List<Object> objectsList = scene.getObjectsList(); + Object newObj = null; + int index, objectsListSize; + for (index = 0, objectsListSize = objectsList.size(); index < objectsListSize; index++) { + Object obj = objectsList.get(index); + if (obj.getId().equals(objectName)) { + newObj = change.apply(obj); + break; + } + } + if (newObj == null) { + logger.error("Did not find object {}!", objectName); + } else { + scene = scene.toBuilder().setObjects(index, newObj).build(); + logger.info("Update {} in scene to:\n {}", objectName, newObj); + } + return scene; + } + @SuppressWarnings("rawtypes") static class ExposingASTNode extends ASTNode { public Scene exposed_apply_ConvertScene(de.tudresden.inf.st.ceti.Scene pbScene) throws Exception { diff --git a/ros3rag.placeB/src/main/resources/config-b-placeworld.yaml b/ros3rag.placeB/src/main/resources/config-b-placeworld.yaml index c6d99b6..72a4db5 100644 --- a/ros3rag.placeB/src/main/resources/config-b-placeworld.yaml +++ b/ros3rag.placeB/src/main/resources/config-b-placeworld.yaml @@ -1,6 +1,11 @@ -mqttHost: "localhost" -useReachability: true -reachability: - - filename: "src/main/resources/reachability-b-arm1-placeworld.json" - - filename: "src/main/resources/reachability-b-arm2-placeworld.json" +mqttHost: "192.168.0.122" +filenameRegions: "src/main/resources/regions-b-placeworld.json" +forB: + topicsSceneUpdate: + - "/ceti_cell_placeworld/scene/update" + - "/ceti_cell_2_placeworld/scene/update" + topicCommand: "/ceti_cell_placeworld/command" + reachability: + - "src/main/resources/reachability-b-arm1-placeworld.json" + - "src/main/resources/reachability-b-arm2-placeworld.json" coordinatorMqttTopicPrefix: "coordinating/rag-b" diff --git a/ros3rag.placeB/src/main/resources/regions-b-placeworld.json b/ros3rag.placeB/src/main/resources/regions-b-placeworld.json index 19abce0..da798ae 100644 --- a/ros3rag.placeB/src/main/resources/regions-b-placeworld.json +++ b/ros3rag.placeB/src/main/resources/regions-b-placeworld.json @@ -4,6 +4,7 @@ { "name": "B", "positions": ["B1", "B2"] }, { "name": "C", "positions": ["C1"] }, { "name": "G", "positions": ["G1"] }, - { "name": "E", "positions": ["E1"] } + { "name": "E", "positions": ["E1"] }, + { "name": "CZ", "positions": ["cz1"] } ] } -- GitLab