From 8d9719318999ef0da376432e67e519c9828ce6bb Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Thu, 14 May 2020 09:09:25 +0200
Subject: [PATCH] Implement observer (WIP)

---
 .../ObjectPoseObserver/ObjectPoseObserver.cpp | 167 ++++++++++++++++--
 .../ObjectPoseObserver/ObjectPoseObserver.h   |  57 ++++--
 2 files changed, 203 insertions(+), 21 deletions(-)

diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
index 4bfd62e21..cc982097f 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
@@ -22,9 +22,29 @@
 
 #include "ObjectPoseObserver.h"
 
+#include <SimoxUtility/meta/EnumNames.hpp>
+
+#include <RobotAPI/libraries/core/Pose.h>
+
+
+std::ostream& armarx::objpose::operator<<(std::ostream& os, const ObjectID& id)
+{
+    return os << "'" << id.project << "/" << id.name << "'";
+}
+
+
 
 namespace armarx
 {
+
+    const simox::meta::EnumNames<objpose::ObjectTypeEnum> ObjectTypeEnumNames =
+    {
+        { objpose::ObjectTypeEnum::AnyObject, "AnyObject" },
+        { objpose::ObjectTypeEnum::KnownObject, "KnownObject" },
+        { objpose::ObjectTypeEnum::UnknownObject, "UnknownObject" }
+    };
+
+
     ObjectPoseObserverPropertyDefinitions::ObjectPoseObserverPropertyDefinitions(std::string prefix) :
         armarx::ObserverPropertyDefinitions(prefix)
     {
@@ -34,6 +54,11 @@ namespace armarx
     {
         armarx::PropertyDefinitionsPtr defs(new ObjectPoseObserverPropertyDefinitions(getConfigIdentifier()));
 
+        defs->defineOptionalProperty<std::string>("ObjectPoseTopicName", "ObjectPoseTopic", "Name of the Object Pose Topic.");
+
+        defs->optional(visu.enabled, "visu.enabled", "Enable or disable visualization of objects.");
+        defs->optional(visu.inGlobalFrame, "visu.inGlobalFrame", "If true, show global poses. If false, show poses in robot frame.");
+
         return defs;
     }
 
@@ -45,6 +70,7 @@ namespace armarx
 
     void ObjectPoseObserver::onInitObserver()
     {
+        usingTopicFromProperty("ObjectPoseTopicName");
     }
 
     void ObjectPoseObserver::onConnectObserver()
@@ -60,46 +86,111 @@ namespace armarx
     }
 
 
-    void ObjectPoseObserver::reportProviderInfo(const std::string& providerName, const objpose::ProviderInfo& info, const Ice::Current&)
+    void ObjectPoseObserver::reportProviderAvailable(const std::string& providerName, const Ice::Current&)
     {
+        objpose::ObjectPoseProviderPrx provider = getProviderProxy(providerName);
+        if (!provider)
+        {
+            ARMARX_WARNING << "Received availability signal from provider '" << providerName << "', "
+                           << "but could not get provider proxy.";
+            return;
+        }
+        objpose::ProviderInfo info = provider->getProviderInfo();
+
+        {
+            std::scoped_lock lock(dataMutex);
+            if (providers.count(providerName) == 0)
+            {
+                ARMARX_VERBOSE << "New provider '" << providerName << "' available.";
+            }
+            providers[providerName] = info;
 
+            if (updateCounters.count(providerName) == 0)
+            {
+                updateCounters[providerName] = 0;
+            }
+        }
+
+        if (!existsChannel(providerName))
+        {
+            offerChannel(providerName, "Channel of provider '" + providerName + "'.");
+        }
+        offerOrUpdateDataField(providerName, "objectType", ObjectTypeEnumNames.to_name(info.objectType), "");
     }
 
-    void ObjectPoseObserver::reportObjectPoses(const std::string& providerName, const objpose::ObjectPoseSeq& candidates, const Ice::Current&)
+    void ObjectPoseObserver::reportObjectPoses(const std::string& providerName, const objpose::ObjectPoseSeq& objectPoses, const Ice::Current&)
     {
-
+        std::scoped_lock lock(dataMutex);
+        ARMARX_INFO << "received object poses from " << providerName;
+        this->objectPoses[providerName] = objectPoses;
+        handleProviderUpdate(providerName);
     }
 
-    objpose::InfoMap ObjectPoseObserver::getAvailableProvidersWithInfo(const Ice::Current&)
+
+    objpose::ObjectPoseSeq ObjectPoseObserver::getObjectPoses(const Ice::Current&)
     {
         return {};
     }
 
-    Ice::StringSeq ObjectPoseObserver::getAvailableProviderNames(const Ice::Current&)
+    objpose::ObjectPoseSeq ObjectPoseObserver::getObjectPosesByProvider(const std::string& providerName, const Ice::Current&)
     {
         return {};
     }
 
-    objpose::ProviderInfo ObjectPoseObserver::getProviderInfo(const std::string& providerName, const Ice::Current&)
+
+    void ObjectPoseObserver::requestObjects(const objpose::ObjectIDSeq& objectIDs, Ice::Long relativeTimeoutMS, const Ice::Current&)
+    {
+        std::map<std::string, objpose::ObjectIDSeq> requests;
+
+        {
+            std::scoped_lock lock(dataMutex);
+            for (const auto& objectID : objectIDs)
+            {
+                for (const auto& [name, info] : providers)
+                {
+                    // ToDo: optimize look up by using sets.
+                    if (std::find(info.supportedObjects.begin(), info.supportedObjects.end(), objectID) != info.supportedObjects.end())
+                    {
+                        requests[name].push_back(objectID);
+                    }
+                }
+            }
+        }
+
+        for (const auto& [providerName, objects] : requests)
+        {
+            objpose::ObjectPoseProviderPrx provider = getProviderProxy(providerName);
+            if (provider)
+            {
+                ARMARX_VERBOSE << "Requesting provider '" << providerName << "' for objects " << objects;
+                provider->requestObjects(objects, relativeTimeoutMS);
+            }
+        }
+    }
+
+
+    objpose::ProviderInfoMap ObjectPoseObserver::getAvailableProvidersWithInfo(const Ice::Current&)
     {
         return {};
     }
 
-    bool ObjectPoseObserver::hasProvider(const std::string& providerName, const Ice::Current&)
+    Ice::StringSeq ObjectPoseObserver::getAvailableProviderNames(const Ice::Current&)
     {
         return {};
     }
 
-    objpose::ObjectPoseSeq ObjectPoseObserver::getObjectPoses(const Ice::Current&)
+    objpose::ProviderInfo ObjectPoseObserver::getProviderInfo(const std::string& providerName, const Ice::Current&)
     {
         return {};
     }
 
-    objpose::ObjectPoseSeq ObjectPoseObserver::getObjectPosesByProvider(const std::string& providerName, const Ice::Current&)
+    bool ObjectPoseObserver::hasProvider(const std::string& providerName, const Ice::Current&)
     {
         return {};
     }
 
+
+
     Ice::Int ObjectPoseObserver::getUpdateCounterByProvider(const std::string& providerName, const Ice::Current&)
     {
         return {};
@@ -110,9 +201,63 @@ namespace armarx
         return {};
     }
 
-    bool ObjectPoseObserver::setProviderConfig(const std::string& providerName, const StringVariantBaseMap& config, const Ice::Current&)
+
+    void ObjectPoseObserver::handleProviderUpdate(const std::string& providerName)
     {
-        return {};
+        // Initialized to 0 on first access.
+        updateCounters[providerName]++;
+        if (providers.count(providerName) == 0)
+        {
+            providers[providerName] = objpose::ProviderInfo();
+        }
+
+        if (!existsChannel(providerName))
+        {
+            offerChannel(providerName, "Channel of provider '" + providerName + "'.");
+        }
+        offerOrUpdateDataField(providerName, "updateCounter", Variant(updateCounters.at(providerName)), "Counter incremented for each update.");
+        offerOrUpdateDataField(providerName, "candidateCount", Variant(int(objectPoses.at(providerName).size())), "Number of provided object poses.");
+
+        if (visu.enabled)
+        {
+            visProviderUpdate(providerName);
+        }
+    }
+
+
+    void ObjectPoseObserver::visProviderUpdate(const std::string& providerName)
+    {
+        viz::Layer layer = arviz.layer(providerName);
+
+        for (const objpose::ObjectPose& objectPose : objectPoses.at(providerName))
+        {
+            const objpose::ObjectID id = objectPose.objectID;
+            std::string key = id.project + "/" + id.name;
+
+            std::optional<ObjectInfo> objectInfo = objectFinder.findObject(id.project, id.name);
+            if (!objectInfo)
+            {
+                ARMARX_WARNING << "Cannot visualize object '" << key << "'.";
+                continue;
+            }
+
+            Eigen::Matrix4f pose = armarx::PosePtr::dynamicCast(objectPose.objectPose)->toEigen();
+            if (visu.inGlobalFrame)
+            {
+                // pose = armarx::PosePtr::dynamicCast(objectPose.robotPose)->toEigen() * pose;
+            }
+
+            layer.add(viz::Object(id.project + "/" + id.name)
+                      .file("", objectInfo->getSimoxXML()).pose(pose));
+        }
+
+        arviz.commit(layer);
+    }
+
+    objpose::ObjectPoseProviderPrx ObjectPoseObserver::getProviderProxy(const std::string& providerName)
+    {
+        return getProxy<objpose::ObjectPoseProviderPrx>(providerName, false, "", false);
     }
 
 }
+
diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
index e00b4bc45..4b9d84788 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.h
@@ -22,15 +22,24 @@
 
 #pragma once
 
+#include <mutex>
 
 #include <ArmarXCore/observers/Observer.h>
 
 #include <RobotAPI/interface/objectpose/ObjectPoseObserver.h>
 #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
 
+#include "ObjectFinder.h"
+
 #define ICE_CURRENT_ARG const Ice::Current& = Ice::emptyCurrent
 
 
+namespace armarx::objpose
+{
+    std::ostream& operator<<(std::ostream& os, const ObjectID& id);
+}
+
+
 namespace armarx
 {
     /**
@@ -38,7 +47,7 @@ namespace armarx
      * @brief Property definitions of `ObjectPoseObserver`.
      */
     class ObjectPoseObserverPropertyDefinitions :
-            public ObserverPropertyDefinitions
+        public ObserverPropertyDefinitions
     {
     public:
         ObjectPoseObserverPropertyDefinitions(std::string prefix);
@@ -58,9 +67,9 @@ namespace armarx
      * Detailed description of class ObjectPoseObserver.
      */
     class ObjectPoseObserver :
-            virtual public Observer
-            , virtual public objpose::ObjectPoseObserverInterface
-            , virtual public armarx::ArVizComponentPluginUser
+        virtual public Observer
+        , virtual public objpose::ObjectPoseObserverInterface
+        , virtual public armarx::ArVizComponentPluginUser
     {
     public:
 
@@ -70,22 +79,25 @@ namespace armarx
 
         // ObjectPoseTopic interface
     public:
-        void reportProviderInfo(const std::string& providerName, const objpose::ProviderInfo& info, ICE_CURRENT_ARG) override;
-        void reportObjectPoses(const std::string& providerName, const objpose::ObjectPoseSeq& candidates, ICE_CURRENT_ARG) override;
+        void reportProviderAvailable(const std::string& providerName, ICE_CURRENT_ARG) override;
+        void reportObjectPoses(const std::string& providerName, const objpose::ObjectPoseSeq& objectPoses, ICE_CURRENT_ARG) override;
 
         // ObjectPoseObserverInterface interface
     public:
-        objpose::InfoMap getAvailableProvidersWithInfo(ICE_CURRENT_ARG) override;
+
+        objpose::ObjectPoseSeq getObjectPoses(ICE_CURRENT_ARG) override;
+        objpose::ObjectPoseSeq getObjectPosesByProvider(const std::string& providerName, ICE_CURRENT_ARG) override;
+
+        void requestObjects(const objpose::ObjectIDSeq& objectIDs, Ice::Long relativeTimeoutMS, ICE_CURRENT_ARG) override;
+
         Ice::StringSeq getAvailableProviderNames(ICE_CURRENT_ARG) override;
         objpose::ProviderInfo getProviderInfo(const std::string& providerName, ICE_CURRENT_ARG) override;
+        objpose::ProviderInfoMap getAvailableProvidersWithInfo(ICE_CURRENT_ARG) override;
         bool hasProvider(const std::string& providerName, ICE_CURRENT_ARG) override;
 
-        objpose::ObjectPoseSeq getObjectPoses(ICE_CURRENT_ARG) override;
-        objpose::ObjectPoseSeq getObjectPosesByProvider(const std::string& providerName, ICE_CURRENT_ARG) override;
 
         Ice::Int getUpdateCounterByProvider(const std::string& providerName, ICE_CURRENT_ARG) override;
         StringIntDictionary getAllUpdateCounters(ICE_CURRENT_ARG) override;
-        bool setProviderConfig(const std::string& providerName, const StringVariantBaseMap& config, ICE_CURRENT_ARG) override;
 
 
     protected:
@@ -98,9 +110,34 @@ namespace armarx
 
         armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
 
+    private:
+
+        void handleProviderUpdate(const std::string& providerName);
+        void visProviderUpdate(const std::string& providerName);
+
+        objpose::ObjectPoseProviderPrx getProviderProxy(const std::string& providerName);
+
 
     private:
 
+        Ice::StringSeq getAvailableProviderNames();
+
+
+        std::mutex dataMutex;
+        objpose::ProviderInfoMap providers;
+
+        std::map<std::string, objpose::ObjectPoseSeq> objectPoses;
+        std::map<std::string, int> updateCounters;
+
+
+        ObjectFinder objectFinder;
+
+        struct Visu
+        {
+            bool enabled = false;
+            bool inGlobalFrame = true;
+        };
+        Visu visu;
 
     };
 
-- 
GitLab