From a79fe71e7a3b6db552e4e6f27db6355e49ec7d9f Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Thu, 5 May 2022 18:06:31 +0200
Subject: [PATCH] new functions

- display latest svg image
- updated demo commands
- updated conversion topics
---
 cgv_connector.proto  |  63 +++++---
 cgv_connector_pb2.py | 275 +++++++++++++++++++++++++++------
 main.py              | 355 ++++++++++++++++++++++++++-----------------
 utils.py             |  18 ++-
 4 files changed, 500 insertions(+), 211 deletions(-)

diff --git a/cgv_connector.proto b/cgv_connector.proto
index ca2f8c4..0a7e924 100644
--- a/cgv_connector.proto
+++ b/cgv_connector.proto
@@ -1,5 +1,5 @@
-// cgv_connector.proto
-// this file contains the messages that are exchanged between the cgv framework and the st ROS interface
+// connector.proto
+// this file contains the messages that are exchanged between the ROS connector and other systems
 
 syntax = "proto3";
 
@@ -10,22 +10,22 @@ message Object {
 
     // Position is object-center related
     message Position {
-        float x = 1; // in m
-        float y = 2; // in m
-        float z = 3; // height in m
+        double x = 1; // in m
+        double y = 2; // in m
+        double z = 3; // height in m
     }
 
     // 3D description of the object
     message Size {
-        float length = 1; // in m
-        float width = 2;  // in m
-        float height = 3; // in m
+        double length = 1; // in m
+        double width = 2;  // in m
+        double height = 3; // in m
     }
     message Orientation {
-        float x = 1; // normalized quaternion
-        float y = 2;
-        float z = 3;
-        float w = 4;
+        double x = 1; // normalized quaternion
+        double y = 2;
+        double z = 3;
+        double w = 4;
     }
     message Color {
         float r = 1; // 0..1
@@ -38,6 +38,9 @@ message Object {
         BIN = 2;
         ARM = 3;
         DROP_OFF_LOCATION = 4;
+        HUMAN = 5;
+        ROBOT = 6;
+        COLLABORATION_ZONE = 7;
     }
 
     string id = 1;
@@ -46,26 +49,46 @@ message Object {
     Size size = 4;
     Orientation orientation = 5;
     Color color = 6;
+    bool active = 7;
 }
 
-// the scene is stored within the ROS side and sent to the CGV framework
+// the scene is stored within the ROS side and sent to clients
 message Scene {
     repeated Object objects = 1;
 }
 
 // the selection is done by the CGV framework and sent to ROS
+// FIXME can be removed
 message Selection {
     string id = 1; // the id corresponds to an id of an Object in a Scene
 }
 
-// vvv from rs vvv.
-// Merged message to contain both pick and place in one
-message MergedSelection {
-    string idRobot = 1; // the id corresponds to and id of the robot Object that should execute this operation
-    string idPick = 2; // the id corresponds to an id of the Object in a Scene to be picked
-    string idPlace = 3; // the id corresponds to an id of the Object in a Scene where the picked object shall be placed
+message Command {
+    oneof msg {
+        PickAndPlace pickAndPlace = 1;
+        ConfigChange configChange = 2;
+        Evacuate evacuate = 3;
+    }
+}
+
+message PickAndPlace {
+    string idRobot = 1;  // id of the robot that should execute this operation
+    string idPick = 2;  // id of the object in the scene to be picked
+    string idPlace = 3;  // id of the location the picked object shall be placed.
+}
+
+message ConfigChange {
+    string idCollaborationZone = 1;  // id of collaboration zone to change
+    string idRobotNewOwner = 2;  // id of robot that will become new owner
 }
+
+message Evacuate {
+    string idRobot = 1;  // id of robot that need to move out of its currently defined collision objects
+    string idCollaborationZone = 2;  // id of collaboration zone to evacuate
+}
+
 // Reachability of objects, as reported by MoveIt
+// FIXME can be removed
 message Reachability {
     message ObjectReachability {
         string idObject = 1; // the id of the object to reach
@@ -73,4 +96,4 @@ message Reachability {
     }
     string idRobot = 1; // the id of the robot arm
     repeated ObjectReachability objects = 2; // all objects reachable
-}
\ No newline at end of file
+}
diff --git a/cgv_connector_pb2.py b/cgv_connector_pb2.py
index 2ae9aa9..9434e42 100644
--- a/cgv_connector_pb2.py
+++ b/cgv_connector_pb2.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: cgv_connector.proto
-
+"""Generated protocol buffer code."""
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import message as _message
 from google.protobuf import reflection as _reflection
@@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
   syntax='proto3',
   serialized_options=b'\n\030de.tudresden.inf.st.cetiP\001',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x13\x63gv_connector.proto\"\xc3\x03\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1a\n\x04type\x18\x02 \x01(\x0e\x32\x0c.Object.Type\x12\x1d\n\x03pos\x18\x03 \x01(\x0b\x32\x10.Object.Position\x12\x1a\n\x04size\x18\x04 \x01(\x0b\x32\x0c.Object.Size\x12(\n\x0borientation\x18\x05 \x01(\x0b\x32\x13.Object.Orientation\x12\x1c\n\x05\x63olor\x18\x06 \x01(\x0b\x32\r.Object.Color\x1a+\n\x08Position\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\x1a\x35\n\x04Size\x12\x0e\n\x06length\x18\x01 \x01(\x02\x12\r\n\x05width\x18\x02 \x01(\x02\x12\x0e\n\x06height\x18\x03 \x01(\x02\x1a\x39\n\x0bOrientation\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\x12\t\n\x01w\x18\x04 \x01(\x02\x1a(\n\x05\x43olor\x12\t\n\x01r\x18\x01 \x01(\x02\x12\t\n\x01g\x18\x02 \x01(\x02\x12\t\n\x01\x62\x18\x03 \x01(\x02\"E\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03\x42OX\x10\x01\x12\x07\n\x03\x42IN\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\x15\n\x11\x44ROP_OFF_LOCATION\x10\x04\"!\n\x05Scene\x12\x18\n\x07objects\x18\x01 \x03(\x0b\x32\x07.Object\"\x17\n\tSelection\x12\n\n\x02id\x18\x01 \x01(\t\"C\n\x0fMergedSelection\x12\x0f\n\x07idRobot\x18\x01 \x01(\t\x12\x0e\n\x06idPick\x18\x02 \x01(\t\x12\x0f\n\x07idPlace\x18\x03 \x01(\t\"\x8d\x01\n\x0cReachability\x12\x0f\n\x07idRobot\x18\x01 \x01(\t\x12\x31\n\x07objects\x18\x02 \x03(\x0b\x32 .Reachability.ObjectReachability\x1a\x39\n\x12ObjectReachability\x12\x10\n\x08idObject\x18\x01 \x01(\t\x12\x11\n\treachable\x18\x02 \x01(\x08\x42\x1c\n\x18\x64\x65.tudresden.inf.st.cetiP\x01\x62\x06proto3'
+  serialized_pb=b'\n\x13\x63gv_connector.proto\"\x81\x04\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1a\n\x04type\x18\x02 \x01(\x0e\x32\x0c.Object.Type\x12\x1d\n\x03pos\x18\x03 \x01(\x0b\x32\x10.Object.Position\x12\x1a\n\x04size\x18\x04 \x01(\x0b\x32\x0c.Object.Size\x12(\n\x0borientation\x18\x05 \x01(\x0b\x32\x13.Object.Orientation\x12\x1c\n\x05\x63olor\x18\x06 \x01(\x0b\x32\r.Object.Color\x12\x0e\n\x06\x61\x63tive\x18\x07 \x01(\x08\x1a+\n\x08Position\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\x12\t\n\x01z\x18\x03 \x01(\x01\x1a\x35\n\x04Size\x12\x0e\n\x06length\x18\x01 \x01(\x01\x12\r\n\x05width\x18\x02 \x01(\x01\x12\x0e\n\x06height\x18\x03 \x01(\x01\x1a\x39\n\x0bOrientation\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\x12\t\n\x01z\x18\x03 \x01(\x01\x12\t\n\x01w\x18\x04 \x01(\x01\x1a(\n\x05\x43olor\x12\t\n\x01r\x18\x01 \x01(\x02\x12\t\n\x01g\x18\x02 \x01(\x02\x12\t\n\x01\x62\x18\x03 \x01(\x02\"s\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03\x42OX\x10\x01\x12\x07\n\x03\x42IN\x10\x02\x12\x07\n\x03\x41RM\x10\x03\x12\x15\n\x11\x44ROP_OFF_LOCATION\x10\x04\x12\t\n\x05HUMAN\x10\x05\x12\t\n\x05ROBOT\x10\x06\x12\x16\n\x12\x43OLLABORATION_ZONE\x10\x07\"!\n\x05Scene\x12\x18\n\x07objects\x18\x01 \x03(\x0b\x32\x07.Object\"\x17\n\tSelection\x12\n\n\x02id\x18\x01 \x01(\t\"}\n\x07\x43ommand\x12%\n\x0cpickAndPlace\x18\x01 \x01(\x0b\x32\r.PickAndPlaceH\x00\x12%\n\x0c\x63onfigChange\x18\x02 \x01(\x0b\x32\r.ConfigChangeH\x00\x12\x1d\n\x08\x65vacuate\x18\x03 \x01(\x0b\x32\t.EvacuateH\x00\x42\x05\n\x03msg\"@\n\x0cPickAndPlace\x12\x0f\n\x07idRobot\x18\x01 \x01(\t\x12\x0e\n\x06idPick\x18\x02 \x01(\t\x12\x0f\n\x07idPlace\x18\x03 \x01(\t\"D\n\x0c\x43onfigChange\x12\x1b\n\x13idCollaborationZone\x18\x01 \x01(\t\x12\x17\n\x0fidRobotNewOwner\x18\x02 \x01(\t\"8\n\x08\x45vacuate\x12\x0f\n\x07idRobot\x18\x01 \x01(\t\x12\x1b\n\x13idCollaborationZone\x18\x02 \x01(\t\"\x8d\x01\n\x0cReachability\x12\x0f\n\x07idRobot\x18\x01 \x01(\t\x12\x31\n\x07objects\x18\x02 \x03(\x0b\x32 .Reachability.ObjectReachability\x1a\x39\n\x12ObjectReachability\x12\x10\n\x08idObject\x18\x01 \x01(\t\x12\x11\n\treachable\x18\x02 \x01(\x08\x42\x1c\n\x18\x64\x65.tudresden.inf.st.cetiP\x01\x62\x06proto3'
 )
 
 
@@ -56,11 +56,26 @@ _OBJECT_TYPE = _descriptor.EnumDescriptor(
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='HUMAN', index=5, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='ROBOT', index=6, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='COLLABORATION_ZONE', index=7, number=7,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=406,
-  serialized_end=475,
+  serialized_start=422,
+  serialized_end=537,
 )
 _sym_db.RegisterEnumDescriptor(_OBJECT_TYPE)
 
@@ -75,21 +90,21 @@ _OBJECT_POSITION = _descriptor.Descriptor(
   fields=[
     _descriptor.FieldDescriptor(
       name='x', full_name='Object.Position.x', index=0,
-      number=1, type=2, cpp_type=6, label=1,
+      number=1, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='y', full_name='Object.Position.y', index=1,
-      number=2, type=2, cpp_type=6, label=1,
+      number=2, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='z', full_name='Object.Position.z', index=2,
-      number=3, type=2, cpp_type=6, label=1,
+      number=3, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -106,8 +121,8 @@ _OBJECT_POSITION = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=205,
-  serialized_end=248,
+  serialized_start=221,
+  serialized_end=264,
 )
 
 _OBJECT_SIZE = _descriptor.Descriptor(
@@ -120,21 +135,21 @@ _OBJECT_SIZE = _descriptor.Descriptor(
   fields=[
     _descriptor.FieldDescriptor(
       name='length', full_name='Object.Size.length', index=0,
-      number=1, type=2, cpp_type=6, label=1,
+      number=1, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='width', full_name='Object.Size.width', index=1,
-      number=2, type=2, cpp_type=6, label=1,
+      number=2, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='height', full_name='Object.Size.height', index=2,
-      number=3, type=2, cpp_type=6, label=1,
+      number=3, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -151,8 +166,8 @@ _OBJECT_SIZE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=250,
-  serialized_end=303,
+  serialized_start=266,
+  serialized_end=319,
 )
 
 _OBJECT_ORIENTATION = _descriptor.Descriptor(
@@ -165,28 +180,28 @@ _OBJECT_ORIENTATION = _descriptor.Descriptor(
   fields=[
     _descriptor.FieldDescriptor(
       name='x', full_name='Object.Orientation.x', index=0,
-      number=1, type=2, cpp_type=6, label=1,
+      number=1, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='y', full_name='Object.Orientation.y', index=1,
-      number=2, type=2, cpp_type=6, label=1,
+      number=2, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='z', full_name='Object.Orientation.z', index=2,
-      number=3, type=2, cpp_type=6, label=1,
+      number=3, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
       name='w', full_name='Object.Orientation.w', index=3,
-      number=4, type=2, cpp_type=6, label=1,
+      number=4, type=1, cpp_type=5, label=1,
       has_default_value=False, default_value=float(0),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
@@ -203,8 +218,8 @@ _OBJECT_ORIENTATION = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=305,
-  serialized_end=362,
+  serialized_start=321,
+  serialized_end=378,
 )
 
 _OBJECT_COLOR = _descriptor.Descriptor(
@@ -248,8 +263,8 @@ _OBJECT_COLOR = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=364,
-  serialized_end=404,
+  serialized_start=380,
+  serialized_end=420,
 )
 
 _OBJECT = _descriptor.Descriptor(
@@ -302,6 +317,13 @@ _OBJECT = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='active', full_name='Object.active', index=6,
+      number=7, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -316,7 +338,7 @@ _OBJECT = _descriptor.Descriptor(
   oneofs=[
   ],
   serialized_start=24,
-  serialized_end=475,
+  serialized_end=537,
 )
 
 
@@ -347,8 +369,8 @@ _SCENE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=477,
-  serialized_end=510,
+  serialized_start=539,
+  serialized_end=572,
 )
 
 
@@ -379,35 +401,86 @@ _SELECTION = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=512,
-  serialized_end=535,
+  serialized_start=574,
+  serialized_end=597,
+)
+
+
+_COMMAND = _descriptor.Descriptor(
+  name='Command',
+  full_name='Command',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='pickAndPlace', full_name='Command.pickAndPlace', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='configChange', full_name='Command.configChange', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='evacuate', full_name='Command.evacuate', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='msg', full_name='Command.msg',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=599,
+  serialized_end=724,
 )
 
 
-_MERGEDSELECTION = _descriptor.Descriptor(
-  name='MergedSelection',
-  full_name='MergedSelection',
+_PICKANDPLACE = _descriptor.Descriptor(
+  name='PickAndPlace',
+  full_name='PickAndPlace',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='idRobot', full_name='MergedSelection.idRobot', index=0,
+      name='idRobot', full_name='PickAndPlace.idRobot', index=0,
       number=1, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='idPick', full_name='MergedSelection.idPick', index=1,
+      name='idPick', full_name='PickAndPlace.idPick', index=1,
       number=2, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='idPlace', full_name='MergedSelection.idPlace', index=2,
+      name='idPlace', full_name='PickAndPlace.idPlace', index=2,
       number=3, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
@@ -425,8 +498,86 @@ _MERGEDSELECTION = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=537,
-  serialized_end=604,
+  serialized_start=726,
+  serialized_end=790,
+)
+
+
+_CONFIGCHANGE = _descriptor.Descriptor(
+  name='ConfigChange',
+  full_name='ConfigChange',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='idCollaborationZone', full_name='ConfigChange.idCollaborationZone', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='idRobotNewOwner', full_name='ConfigChange.idRobotNewOwner', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=792,
+  serialized_end=860,
+)
+
+
+_EVACUATE = _descriptor.Descriptor(
+  name='Evacuate',
+  full_name='Evacuate',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='idRobot', full_name='Evacuate.idRobot', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='idCollaborationZone', full_name='Evacuate.idCollaborationZone', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=862,
+  serialized_end=918,
 )
 
 
@@ -464,8 +615,8 @@ _REACHABILITY_OBJECTREACHABILITY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=691,
-  serialized_end=748,
+  serialized_start=1005,
+  serialized_end=1062,
 )
 
 _REACHABILITY = _descriptor.Descriptor(
@@ -502,8 +653,8 @@ _REACHABILITY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=607,
-  serialized_end=748,
+  serialized_start=921,
+  serialized_end=1062,
 )
 
 _OBJECT_POSITION.containing_type = _OBJECT
@@ -517,12 +668,27 @@ _OBJECT.fields_by_name['orientation'].message_type = _OBJECT_ORIENTATION
 _OBJECT.fields_by_name['color'].message_type = _OBJECT_COLOR
 _OBJECT_TYPE.containing_type = _OBJECT
 _SCENE.fields_by_name['objects'].message_type = _OBJECT
+_COMMAND.fields_by_name['pickAndPlace'].message_type = _PICKANDPLACE
+_COMMAND.fields_by_name['configChange'].message_type = _CONFIGCHANGE
+_COMMAND.fields_by_name['evacuate'].message_type = _EVACUATE
+_COMMAND.oneofs_by_name['msg'].fields.append(
+  _COMMAND.fields_by_name['pickAndPlace'])
+_COMMAND.fields_by_name['pickAndPlace'].containing_oneof = _COMMAND.oneofs_by_name['msg']
+_COMMAND.oneofs_by_name['msg'].fields.append(
+  _COMMAND.fields_by_name['configChange'])
+_COMMAND.fields_by_name['configChange'].containing_oneof = _COMMAND.oneofs_by_name['msg']
+_COMMAND.oneofs_by_name['msg'].fields.append(
+  _COMMAND.fields_by_name['evacuate'])
+_COMMAND.fields_by_name['evacuate'].containing_oneof = _COMMAND.oneofs_by_name['msg']
 _REACHABILITY_OBJECTREACHABILITY.containing_type = _REACHABILITY
 _REACHABILITY.fields_by_name['objects'].message_type = _REACHABILITY_OBJECTREACHABILITY
 DESCRIPTOR.message_types_by_name['Object'] = _OBJECT
 DESCRIPTOR.message_types_by_name['Scene'] = _SCENE
 DESCRIPTOR.message_types_by_name['Selection'] = _SELECTION
-DESCRIPTOR.message_types_by_name['MergedSelection'] = _MERGEDSELECTION
+DESCRIPTOR.message_types_by_name['Command'] = _COMMAND
+DESCRIPTOR.message_types_by_name['PickAndPlace'] = _PICKANDPLACE
+DESCRIPTOR.message_types_by_name['ConfigChange'] = _CONFIGCHANGE
+DESCRIPTOR.message_types_by_name['Evacuate'] = _EVACUATE
 DESCRIPTOR.message_types_by_name['Reachability'] = _REACHABILITY
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -579,12 +745,33 @@ Selection = _reflection.GeneratedProtocolMessageType('Selection', (_message.Mess
   })
 _sym_db.RegisterMessage(Selection)
 
-MergedSelection = _reflection.GeneratedProtocolMessageType('MergedSelection', (_message.Message,), {
-  'DESCRIPTOR' : _MERGEDSELECTION,
+Command = _reflection.GeneratedProtocolMessageType('Command', (_message.Message,), {
+  'DESCRIPTOR' : _COMMAND,
+  '__module__' : 'cgv_connector_pb2'
+  # @@protoc_insertion_point(class_scope:Command)
+  })
+_sym_db.RegisterMessage(Command)
+
+PickAndPlace = _reflection.GeneratedProtocolMessageType('PickAndPlace', (_message.Message,), {
+  'DESCRIPTOR' : _PICKANDPLACE,
+  '__module__' : 'cgv_connector_pb2'
+  # @@protoc_insertion_point(class_scope:PickAndPlace)
+  })
+_sym_db.RegisterMessage(PickAndPlace)
+
+ConfigChange = _reflection.GeneratedProtocolMessageType('ConfigChange', (_message.Message,), {
+  'DESCRIPTOR' : _CONFIGCHANGE,
+  '__module__' : 'cgv_connector_pb2'
+  # @@protoc_insertion_point(class_scope:ConfigChange)
+  })
+_sym_db.RegisterMessage(ConfigChange)
+
+Evacuate = _reflection.GeneratedProtocolMessageType('Evacuate', (_message.Message,), {
+  'DESCRIPTOR' : _EVACUATE,
   '__module__' : 'cgv_connector_pb2'
-  # @@protoc_insertion_point(class_scope:MergedSelection)
+  # @@protoc_insertion_point(class_scope:Evacuate)
   })
-_sym_db.RegisterMessage(MergedSelection)
+_sym_db.RegisterMessage(Evacuate)
 
 Reachability = _reflection.GeneratedProtocolMessageType('Reachability', (_message.Message,), {
 
diff --git a/main.py b/main.py
index ccb658b..92152b6 100644
--- a/main.py
+++ b/main.py
@@ -3,6 +3,8 @@ import datetime
 import queue
 import threading
 import time
+import base64
+import flask
 
 import dash
 from dash import dcc
@@ -16,8 +18,14 @@ import cgv_connector_pb2
 import utils
 
 external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
-
-MQTT_SERVER = 'localhost'
+fixed_svg_filename = "ros3rag/ros3rag.placeB/images/2022-05-04T10-19-30-9155.svg"
+fixed_svg_filename = "2022-05-04T10-19-30-9155.svg"
+# fixed_svg_filename = ""
+image_directory = '/data/git/jastadd/ros3rag/ros3rag.placeB/images/'
+static_image_route = '/static/'
+
+MQTT_SERVER = '192.168.0.122'
+# MQTT_SERVER = 'localhost'
 mqttc = mqtt.Client()
 
 # mqtt client connected?
@@ -41,22 +49,30 @@ commands = {
     'send-place-b-rewind': ('place-b/rewind', '1'),
     'send-place-b-start': ('coordinating/rag-b/command', 'start'),
     'send-place-b-exit': ('place-b/exit', '1'),
-    'send-place-a-demo-objRed-blue': ('place-a/demo/move/objectRed1/blue', '1'),
-    'send-place-a-demo-objRed-red': ('place-a/demo/move/objectRed1/red', '1'),
-    'send-place-b-demo-objRed-red': ('place-b/demo/move/objectRed1/red', '1'),
+    # 'send-place-a-demo-objRed-blue': ('place-a/demo/move/objectRed1/blue', '1'),
+    # 'send-place-a-demo-objRed-red': ('place-a/demo/move/objectRed1/red', '1'),
+    # 'send-place-b-demo-objRed-red': ('place-b/demo/move/objectRed1/red', '1'),
+
+    'send-place-b-demo-initial_scene': ('demo/initial_scene', '1'),
+    'send-place-b-demo-arm1-active': ('demo/arm1/active', '1'),
+    'send-place-b-demo-arm1-inactive': ('demo/arm1/inactive', '1'),
+    'send-place-b-demo-arm2-active': ('demo/arm2/active', '1'),
+    'send-place-b-demo-arm2-inactive': ('demo/arm2/inactive', '1'),
+    'send-place-b-demo-big-blue-cz': ('demo/big-blue/cz', '1'),
+    'send-place-b-demo-big-blue-g1': ('demo/big-blue/g1', '1'),
 
     'send-coordinator-model': ('coordinator/model', '1'),
     'send-coordinator-model-details': ('coordinator/model', 'details'),
     'send-coordinator-exit': ('coordinator/exit', '1'),
 
-    'send-place-a-robot-ctrl-up': ('ros-place-a/status', 'up'),
-    'send-place-b-robot-ctrl-up': ('ros-place-b/status', 'up'),
+    # 'send-place-a-robot-ctrl-up': ('ros-place-a/status', 'up'),
+    # 'send-place-b-robot-ctrl-up': ('ros-place-b/status', 'up'),
     'send-place-a-rag-up': ('rag-a/status', 'up'),
     'send-place-b-rag-up': ('rag-b/status', 'up'),
     'send-dummy-up': ('random/status', 'up'),
 
-    'send-place-a-robot-ctrl-ready': ('ros-place-a/status', 'ready'),
-    'send-place-b-robot-ctrl-ready': ('ros-place-b/status', 'ready'),
+    # 'send-place-a-robot-ctrl-ready': ('ros-place-a/status', 'ready'),
+    # 'send-place-b-robot-ctrl-ready': ('ros-place-b/status', 'ready'),
     'send-place-a-rag-ready': ('rag-a/status', 'ready'),
     'send-place-b-rag-ready': ('rag-b/status', 'ready'),
     'send-dummy-ready': ('random/status', 'ready'),
@@ -75,9 +91,13 @@ complex_commands = {
 }
 
 conversion_topics = {
+    '/ceti_cell_placeworld/scene/update': (cgv_connector_pb2.Scene(), utils.format_scene),
+    '/ceti_cell_2_placeworld/scene/update': (cgv_connector_pb2.Scene(), utils.format_scene),
+    '/moveit_sorting_controller/scene/update': (cgv_connector_pb2.Scene(), utils.format_scene),
     'place-a/scene/update': (cgv_connector_pb2.Scene(), utils.format_scene),
     'place-b/scene/update': (cgv_connector_pb2.Scene(), utils.format_scene),
-    'place-b/command': (cgv_connector_pb2.MergedSelection(), utils.format_command),
+    'place-b/command': (cgv_connector_pb2.Command(), utils.format_command),
+    '/ceti_cell_placeworld/command': (cgv_connector_pb2.Command(), utils.format_command),
     'place-b/reachability/arm1': (cgv_connector_pb2.Reachability(), utils.format_reachability),
     'place-b/reachability/arm2': (cgv_connector_pb2.Reachability(), utils.format_reachability),
     'place-b/reachability/arm3': (cgv_connector_pb2.Reachability(), utils.format_reachability),
@@ -85,6 +105,7 @@ conversion_topics = {
 
 bytes_topics = [
 ]
+svg_image_topic = 'place-b/model/svg/path'
 
 button_style_normal = {"marginRight": "15px"}
 button_style_exit = {**button_style_normal, "backgroundColor": "red", "color": "white"}
@@ -92,146 +113,167 @@ textarea_style_normal = {'width': '100%', 'height': '200px', 'resize': 'vertical
 
 app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
 app.layout = html.Div([
-    html.Div([  # First Row
-        html.Div([  # Column for place a
-            dcc.Textarea(
-                id='place-a-input-json',
-                placeholder='place-a-input-json',
-                value='{}',
-                style=textarea_style_normal
-            ),
-            html.Button('Send to place-a/scene/update', id='send-place-a-update'),
-            html.Div(id='hidden-div-scene-a', style={'display': 'none'})
-        ], className="six columns"),
-        html.Div([  # Column for place b
-            dcc.Textarea(
-                id='place-b-input-json',
-                placeholder='place-b-input-json',
-                value='{}',
-                style=textarea_style_normal
-            ),
-            html.Button('Send to place-b/scene/update', id='send-place-b-update'),
-            html.Div(id='hidden-div-scene-b', style={'display': 'none'}),
-            html.Div([  # Row for reachability
-                html.Div([  # Column for reachability arm 1
+    dcc.Tabs([
+        dcc.Tab(label="Buttons and Log", children=[
+            html.Div([  # First Row
+                html.Div([  # Column for place a
                     dcc.Textarea(
-                        id='place-b-reachability-1-json',
-                        placeholder='place-b-reachability-1-json',
+                        id='place-a-input-json',
+                        placeholder='place-a-input-json',
                         value='{}',
                         style=textarea_style_normal
                     ),
-                    html.Button('Send to place-b/reachability/arm1', id='send-place-b-reachability-1-update'),
+                    html.Button('Send to place-a/scene/update', id='send-place-a-update'),
+                    html.Div(id='hidden-div-scene-a', style={'display': 'none'})
                 ], className="six columns"),
-                html.Div([  # Column for reachability arm 2
+                html.Div([  # Column for place b
                     dcc.Textarea(
-                        id='place-b-reachability-2-json',
-                        placeholder='place-b-reachability-2-json',
+                        id='place-b-input-json',
+                        placeholder='place-b-input-json',
                         value='{}',
                         style=textarea_style_normal
                     ),
-                    html.Button('Send to place-b/reachability/arm2', id='send-place-b-reachability-2-update'),
+                    html.Button('Send to place-b/scene/update', id='send-place-b-update'),
+                    html.Div(id='hidden-div-scene-b', style={'display': 'none'}),
+                    html.Div([  # Row for reachability
+                        html.Div([  # Column for reachability arm 1
+                            dcc.Textarea(
+                                id='place-b-reachability-1-json',
+                                placeholder='place-b-reachability-1-json',
+                                value='{}',
+                                style=textarea_style_normal
+                            ),
+                            html.Button('Send to place-b/reachability/arm1', id='send-place-b-reachability-1-update'),
+                        ], className="six columns"),
+                        html.Div([  # Column for reachability arm 2
+                            dcc.Textarea(
+                                id='place-b-reachability-2-json',
+                                placeholder='place-b-reachability-2-json',
+                                value='{}',
+                                style=textarea_style_normal
+                            ),
+                            html.Button('Send to place-b/reachability/arm2', id='send-place-b-reachability-2-update'),
+                        ], className="six columns"),
+                    ], className='row', style={'marginTop': '15px'}),
                 ], className="six columns"),
-            ], className='row', style={'marginTop': '15px'}),
-        ], className="six columns"),
-    ], className='row', style={'display': 'none'}),
-    # dcc.Markdown("---"),
-    html.Div([  # Row for commands
-        html.Div([  # Column for commands of place b
-            html.H3("Coordinator"),
-        # html.Div([  # Row for commands coordinator
-            html.Button('Model', id='send-coordinator-model', style=button_style_normal),
-            html.Button('Model (Details)', id='send-coordinator-model-details', style=button_style_normal),
-            html.Button('Exit', id='send-coordinator-exit', style=button_style_exit),
-        # ], className='row'),
-        # html.Div([  # Row for commands up
-            html.Button('Robot Control A Up', id='send-place-a-robot-ctrl-up', style=button_style_normal),
-            html.Button('Robot Control B Up', id='send-place-b-robot-ctrl-up', style=button_style_normal),
-            html.Button('RAG A Up', id='send-place-a-rag-up', style=button_style_normal),
-            html.Button('RAG B Up', id='send-place-b-rag-up', style=button_style_normal),
-            html.Button('Dummy Up', id='send-dummy-up', style=button_style_normal),
-        # ], className='row'),
-        # html.Div([  # Row for commands ready
-            html.Button('Robot Control A Ready', id='send-place-a-robot-ctrl-ready', style=button_style_normal),
-            html.Button('Robot Control B Ready', id='send-place-b-robot-ctrl-ready', style=button_style_normal),
-            html.Button('RAG A Ready', id='send-place-a-rag-ready', style=button_style_normal),
-            html.Button('RAG B Ready', id='send-place-b-rag-ready', style=button_style_normal),
-            html.Button('Dummy Ready', id='send-dummy-ready', style=button_style_normal),
-        # ], className='row'),
-        ], className="four columns"),
-        html.Div([  # Column for commands of place a
-            html.H3("Commands Place A"),
-            html.Button('Model', id='send-place-a-model', style=button_style_normal),
-            html.Button('Model (Details)', id='send-place-a-model-details', style=button_style_normal),
-            html.Button('Rewind', id='send-place-a-rewind', style=button_style_normal),
-            html.Button('Start', id='send-place-a-start', style=button_style_normal),
-            html.Button('Exit', id='send-place-a-exit', style=button_style_exit),
-            html.Button('obj-Red -> Red', id='send-place-a-demo-objRed-red', style=button_style_normal),
-            html.Button('obj-Red -> Blue', id='send-place-a-demo-objRed-blue', style=button_style_normal),
-        ], className="four columns"),
-        html.Div([  # Column for commands of place b
-            html.H3("Commands Place B"),
-            html.Button('Model', id='send-place-b-model', style=button_style_normal),
-            html.Button('Model (Details)', id='send-place-b-model-details', style=button_style_normal),
-            html.Button('Rewind', id='send-place-b-rewind', style=button_style_normal),
-            html.Button('Start', id='send-place-b-start', style=button_style_normal),
-            html.Button('Exit', id='send-place-b-exit', style=button_style_exit),
-            html.Button('obj-Red -> Red', id='send-place-b-demo-objRed-red', style=button_style_normal),
-        ], className="four columns"),
-    ], className='row'),
-    # dcc.Markdown("---"),
-    html.H2("Filtered MQTT Log"),
-    dcc.Textarea(
-        id='filtered-mqtt-log',
-        value="",
-        readOnly=True,
-        style={**textarea_style_normal, 'height': '400px', 'fontFamily': 'Consolas, monospace'}
-    ),
-    dcc.Checklist(
-        id='topics-to-filter',
-        options=[{'label': topic, 'value': topic} for topic in conversion_topics],
-        value=[topic for topic in conversion_topics],
-        labelStyle={'display': 'inline-block'}
-    ),
-    html.H2("MQTT Log"),
-    dcc.Textarea(
-        id='mqtt-log',
-        value="",
-        readOnly=True,
-        style={**textarea_style_normal, 'height': '400px', 'fontFamily': 'Consolas, monospace'}
-    ),
-    dcc.Checklist(
-        id="should-scroll-mqtt-log",
-        options=[{"label": "Auto-Scroll", "value": "Auto-Scroll"}],
-        value=["Auto-Scroll"],
-        labelStyle={"display": "inline-block"},
-    ),
-    dcc.Checklist(
-        id="mqtt-connected",
-        options=[{"label": "MQTT connected?", "value": "yes", "disabled": True}],
-        value=[],
-        labelStyle={"display": "inline-block"},
-    ),
-    html.Button('Clear log', id='clear-mqtt-log', style=button_style_normal),
-    dcc.Markdown("---"),
-    html.Div([
-        html.P("Topic"),
-        dcc.Input(id='manual-mqtt-topic'),
-        html.P("Message"),
-        dcc.Input(id='manual-mqtt-message'),
-        # dcc.Textarea(id='manual-mqtt-message', style={'width': '50%', 'font-family': 'Consolas, monospace'}),
-        html.Button('Send', id='manual-mqtt-send')
-    ], className='row', style=dict(display='flex')),
-
-    # -- Invisible elements --
-    dcc.Location(id='url', refresh=False),
-    dcc.Interval(
-        id='every-1-second',
-        interval=1000,  # in milliseconds
-        n_intervals=0
-    ),
-    visdcc.Run_js(id='javascriptLog', run=""),
-    html.Div(id='hidden-div', style={'display': 'none'})
-])
+            ], className='row', style={'display': 'none'}),
+            # dcc.Markdown("---"),
+            html.Div([  # Row for commands
+                html.Div([  # Column for commands of place b
+                    html.H3("Coordinator"),
+                # html.Div([  # Row for commands coordinator
+                    html.Button('Model', id='send-coordinator-model', style=button_style_normal),
+                    html.Button('Model (Details)', id='send-coordinator-model-details', style=button_style_normal),
+                    html.Button('Exit', id='send-coordinator-exit', style=button_style_exit),
+                # ], className='row'),
+                # html.Div([  # Row for commands up
+                    # html.Button('Robot Control A Up', id='send-place-a-robot-ctrl-up', style=button_style_normal),
+                    # html.Button('Robot Control B Up', id='send-place-b-robot-ctrl-up', style=button_style_normal),
+                    html.Button('RAG A Up', id='send-place-a-rag-up', style=button_style_normal),
+                    html.Button('RAG B Up', id='send-place-b-rag-up', style=button_style_normal),
+                    html.Button('Dummy Up', id='send-dummy-up', style=button_style_normal),
+                # ], className='row'),
+                # html.Div([  # Row for commands ready
+                    # html.Button('Robot Control A Ready', id='send-place-a-robot-ctrl-ready', style=button_style_normal),
+                    # html.Button('Robot Control B Ready', id='send-place-b-robot-ctrl-ready', style=button_style_normal),
+                    html.Button('RAG A Ready', id='send-place-a-rag-ready', style=button_style_normal),
+                    html.Button('RAG B Ready', id='send-place-b-rag-ready', style=button_style_normal),
+                    html.Button('Dummy Ready', id='send-dummy-ready', style=button_style_normal),
+                # ], className='row'),
+                ], className="four columns"),
+                html.Div([  # Column for commands of place a
+                    html.H3("Commands Place A"),
+                    html.Button('Model', id='send-place-a-model', style=button_style_normal),
+                    html.Button('Model (Details)', id='send-place-a-model-details', style=button_style_normal),
+                    html.Button('Rewind', id='send-place-a-rewind', style=button_style_normal),
+                    html.Button('Start', id='send-place-a-start', style=button_style_normal),
+                    html.Button('Exit', id='send-place-a-exit', style=button_style_exit),
+                    # html.Button('obj-Red -> Red', id='send-place-a-demo-objRed-red', style=button_style_normal),
+                    # html.Button('obj-Red -> Blue', id='send-place-a-demo-objRed-blue', style=button_style_normal),
+                ], className="four columns"),
+                html.Div([  # Column for commands of place b
+                    html.H3("Commands Place B"),
+                    html.Button('Model', id='send-place-b-model', style=button_style_normal),
+                    html.Button('Model (Details)', id='send-place-b-model-details', style=button_style_normal),
+                    html.Button('Rewind', id='send-place-b-rewind', style=button_style_normal),
+                    html.Button('Start', id='send-place-b-start', style=button_style_normal),
+                    html.Button('Exit', id='send-place-b-exit', style=button_style_exit),
+                    # html.Button('obj-Red -> Red', id='send-place-b-demo-objRed-red', style=button_style_normal),
+                    html.Button('initial_scene', id='send-place-b-demo-initial_scene', style=button_style_normal),
+                    html.Button('arm1-active', id='send-place-b-demo-arm1-active', style=button_style_normal),
+                    html.Button('arm1-inactive', id='send-place-b-demo-arm1-inactive', style=button_style_normal),
+                    html.Button('arm2-active', id='send-place-b-demo-arm2-active', style=button_style_normal),
+                    html.Button('arm2-inactive', id='send-place-b-demo-arm2-inactive', style=button_style_normal),
+                    html.Button('big-blue-cz', id='send-place-b-demo-big-blue-cz', style=button_style_normal),
+                    html.Button('big-blue-g1', id='send-place-b-demo-big-blue-g1', style=button_style_normal),
+                ], className="four columns"),
+            ], className='row'),
+            # dcc.Markdown("---"),
+            html.H2("Filtered MQTT Log"),
+            dcc.Textarea(
+                id='filtered-mqtt-log',
+                value="",
+                readOnly=True,
+                style={**textarea_style_normal, 'height': '400px', 'fontFamily': 'Consolas, monospace'}
+            ),
+            dcc.Checklist(
+                id='topics-to-filter',
+                options=[{'label': topic, 'value': topic} for topic in conversion_topics],
+                value=[topic for topic in conversion_topics],
+                labelStyle={'display': 'inline-block'}
+            ),
+            html.H2("MQTT Log"),
+            dcc.Textarea(
+                id='mqtt-log',
+                value="",
+                readOnly=True,
+                style={**textarea_style_normal, 'height': '400px', 'fontFamily': 'Consolas, monospace'}
+            ),
+            dcc.Checklist(
+                id="should-scroll-mqtt-log",
+                options=[{"label": "Auto-Scroll", "value": "Auto-Scroll"}],
+                value=["Auto-Scroll"],
+                labelStyle={"display": "inline-block"},
+            ),
+            dcc.Checklist(
+                id="mqtt-connected",
+                options=[{"label": "MQTT connected?", "value": "yes", "disabled": True}],
+                value=[],
+                labelStyle={"display": "inline-block"},
+            ),
+            html.Button('Clear log', id='clear-mqtt-log', style=button_style_normal),
+            dcc.Markdown("---"),
+            html.Div([
+                html.P("Topic"),
+                dcc.Input(id='manual-mqtt-topic', style={"margin-left": "5px"}),
+                html.P("Message", style={"margin-left": "15px"}),
+                dcc.Input(id='manual-mqtt-message', style={"margin-left": "5px"}),
+                # dcc.Textarea(id='manual-mqtt-message', style={'width': '50%', 'font-family': 'Consolas, monospace'}),
+                html.Button('Send', id='manual-mqtt-send', style={"margin-left": "15px"})
+            ], className='row', style=dict(display='flex')),
+
+            # -- Invisible elements --
+            dcc.Location(id='url', refresh=False),
+            dcc.Interval(
+                id='every-1-second',
+                interval=1000,  # in milliseconds
+                n_intervals=0
+            ),
+            visdcc.Run_js(id='javascriptLog', run=""),
+            html.Div(id='hidden-div', style={'display': 'none'})
+        ]), # Tab "Buttons and Log"
+    dcc.Tab(label="SVG Model B", children=[
+            html.Div([
+                html.P("Name:"),
+                html.P(id='model-b-svg-name', style={"margin-left": "15px"}),
+            ], className='row', style=dict(display='flex')),
+            html.Div([
+                html.Img(id='model-b-svg-img', src="/static/{}".format(fixed_svg_filename))
+            ], style=dict(position='fixed', overflow='scroll', width='100%')),
+            # html.Img(src="data:image/svg;base64,{}".format(base64.b64encode(open(fixed_svg_filename, 'rb').read()).decode()))
+        ]) # Tab "SVG Model B"
+    ]) # Tabs
+]) # Div
 
 
 @app.callback(
@@ -339,15 +381,17 @@ def check_connection(_n_intervals):
     Output('mqtt-log', 'value'),
     Output('javascriptLog', 'run'),
     Output('topics-to-filter', 'options'),
+    Output('model-b-svg-img', 'src'),
     Input('every-1-second', 'n_intervals'),
     Input('clear-mqtt-log', 'n_clicks'),
     Input('topics-to-filter', 'options'),
     Input('topics-to-filter', 'value'),
+    Input('model-b-svg-img', 'src'),
     State('filtered-mqtt-log', 'value'),
     State('mqtt-log', 'value'),
     State('should-scroll-mqtt-log', 'value')
 )
-def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_filter,
+def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_filter, previous_svg_img_src,
                        filtered_value, value, should_scroll):
     """
     Periodically update mqtt log
@@ -355,18 +399,20 @@ def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_f
     :param (Input) clear_n_clicks: clear.n_clicks
     :param (Input) filter_options: displayed topics to show in filtered log
     :param (Input) topics_to_filter: topics to show in filtered log
+    :param (Input) previous_svg_img_src: previous 'src' of the svg showing latest model of site B
     :param (State) value: current content of mqtt log
     :param (State) filtered_value: current content of filtered mqtt log
     :param (State) should_scroll: checkbox value whether to scroll to the end after update
     :return: new content of mqtt log
     """
+    new_svg_img_src = previous_svg_img_src
     ctx = dash.callback_context
     if not ctx.triggered:
         return dash.no_update
 
     trigger_id = ctx.triggered[0]['prop_id'].split('.')[0]
     if trigger_id == 'clear-mqtt-log':
-        return "", "", "", filter_options
+        return "", "", "", filter_options, new_svg_img_src
 
     if trigger_id == 'topics-to-filter':
         filtered_value = ""
@@ -392,6 +438,9 @@ def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_f
                 filtered_value = ""
             for msg in local_messages:
                 topic_match, topic = utils.topic_match(topics_to_filter, msg)
+                if topic == svg_image_topic:
+                    new_svg_img_src = '/static/' + utils.parse_log_msg(msg)[2]
+                    print('found new svg: ' + new_svg_img_src)
                 if topic_match:
                     filtered_value += msg + "\n"
                 if topic not in (option['label'] for option in filter_options):
@@ -404,7 +453,7 @@ def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_f
              var textarea = document.getElementById('mqtt-log');
              textarea.scrollTop = textarea.scrollHeight;
              ''' if should_scroll else ""
-    return filtered_value, value, log_cmd, filter_options
+    return filtered_value, value, log_cmd, filter_options, new_svg_img_src
 
 
 @app.callback(
@@ -448,6 +497,26 @@ def send_manual(n_clicks, topic, message):
     return dash.no_update
 
 
+@app.callback(
+    Output('model-b-svg-name', 'children'),
+    Input('model-b-svg-img', 'src'),
+)
+def update_svg_name(name):
+    return name
+
+
+# Add a static image route that serves images from desktop
+# Be *very* careful here - you don't want to serve arbitrary files
+# from your computer or server
+@app.server.route('{}<image_path>.svg'.format(static_image_route))
+def serve_image(image_path):
+    image_name = '{}.svg'.format(image_path)
+    print('{}/{}'.format(image_directory, image_name))
+    # if image_name not in list_of_images:
+    #     raise Exception('"{}" is excluded from the allowed static files'.format(image_path))
+    return flask.send_from_directory(image_directory, image_name)
+
+
 def on_mqtt_connect(_client, _userdata, _flags, _rc, _properties=None):
     # Callback for mqtt client when connected
     print('\nConnected at ' + datetime.datetime.now().isoformat())
diff --git a/utils.py b/utils.py
index b3751da..271200a 100644
--- a/utils.py
+++ b/utils.py
@@ -49,14 +49,24 @@ def topic_match(topics_to_filter, msg, last_match=True):
 def format_scene(scene: cgv_connector_pb2.Scene):
     result = ""
     for obj in scene.objects:
-        if obj.type == cgv_connector_pb2.Object.Type.BOX:
+        if obj.type != cgv_connector_pb2.Object.Type.DROP_OFF_LOCATION and obj.type != cgv_connector_pb2.Object.Type.UNKNOWN:
             pos = obj.pos
-            result += f"\n<obj {obj.id:15} at ({pos.x:6.2} {pos.y:6.2} {pos.z:6.2})>"
+            result += f"\n<{cgv_connector_pb2.Object.Type.Name(obj.type):20} {obj.id:15} at ({pos.x:6.2} {pos.y:6.2} {pos.z:6.2}) {obj.active}>"
+            # result += str(obj)
+    # result = scene
     return result
 
 
-def format_command(command: cgv_connector_pb2.MergedSelection):
-    return f"<cmd by {command.idRobot} of {command.idPick} to {command.idPlace}>"
+def format_command(command: cgv_connector_pb2.Command):
+    if command.HasField("pickAndPlace"):
+        pickAndPlace = command.pickAndPlace
+        return f"<PickAndPlace by {pickAndPlace.idRobot} of {pickAndPlace.idPick} to {pickAndPlace.idPlace}>"
+    if command.HasField("configChange"):
+        configChange = command.configChange
+        return f"<ConfigChange by {configChange.idRobotNewOwner} for {configChange.idCollaborationZone}>"
+    if command.HasField("evacuate"):
+        return f"<Evacuate by {command.evacuate.idRobot}>"
+    return "<unknown command>"
 
 
 def _get_reach_objects(r):
-- 
GitLab