From 9385b3333f61af9cc80e6a27eb4368d4e5bd8d4d Mon Sep 17 00:00:00 2001 From: Fabian Peller-Konrad <fabian.peller-konrad@kit.edu> Date: Thu, 13 Jan 2022 17:09:20 +0100 Subject: [PATCH] finalized first working version of skill provider and skill manager adapted some aron visitor stuff for type visitors (similar to data visitors) --- .../SkillProviderExample/CMakeLists.txt | 1 + .../SkillProviderExample.cpp | 44 +- .../SkillProviderExample.h | 9 +- .../server/SkillsMemory/SkillsMemory.cpp | 121 ++-- .../armem/server/SkillsMemory/SkillsMemory.h | 27 +- source/RobotAPI/gui-plugins/CMakeLists.txt | 2 +- .../SkillManagerPlugin/CMakeLists.txt | 16 + .../SkillManagerMonitorWidget.ui} | 93 ++- .../SkillManagerMonitorWidgetController.cpp | 607 ++++++++++++++++++ .../SkillManagerMonitorWidgetController.h | 195 ++++++ .../SkillObserverMonitor/CMakeLists.txt | 16 - .../SkillObserverMonitorWidgetController.cpp | 152 ----- .../SkillObserverMonitorWidgetController.h | 120 ---- source/RobotAPI/interface/CMakeLists.txt | 2 +- ...nterface.ice => SkillManagerInterface.ice} | 8 +- .../interface/skills/SkillMemoryInterface.ice | 6 +- .../skills/SkillProviderInterface.ice | 38 +- .../skills/StatechartListenerInterface.ice | 2 +- .../libraries/armem_skills/CMakeLists.txt | 6 +- .../libraries/armem_skills/aron/Skill.xml | 23 +- .../client/SkillProviderComponentPlugin.cpp | 140 ++-- .../client/SkillProviderComponentPlugin.h | 76 ++- .../server/SkillManagerComponentPlugin.cpp | 65 ++ ...Plugin.h => SkillManagerComponentPlugin.h} | 15 +- .../server/SkillObserverComponentPlugin.cpp | 52 -- .../segment/ExecutableSkillLibrarySegment.cpp | 24 +- .../segment/ExecutableSkillLibrarySegment.h | 7 +- .../server/segment/SkillEventSegment.cpp | 27 + .../server/segment/SkillEventSegment.h | 31 + .../segment/SkillExecutionRequestSegment.cpp | 4 +- .../aron/core/type/variant/Variant.h | 1 + .../aron/core/type/variant/container/Dict.cpp | 2 +- .../aron/core/type/variant/container/List.cpp | 2 +- .../core/type/variant/container/Object.cpp | 5 +- .../aron/core/type/variant/container/Object.h | 2 +- .../aron/core/type/variant/container/Pair.cpp | 4 +- .../core/type/variant/container/Tuple.cpp | 3 +- .../type/visitor/variant/VariantVisitor.cpp | 148 +++++ .../type/visitor/variant/VariantVisitor.h | 47 ++ 39 files changed, 1572 insertions(+), 571 deletions(-) create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt rename source/RobotAPI/gui-plugins/{SkillObserverMonitor/SkillObserverMonitorWidget.ui => SkillManagerPlugin/SkillManagerMonitorWidget.ui} (60%) create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h rename source/RobotAPI/interface/skills/{SkillObserverInterface.ice => SkillManagerInterface.ice} (77%) create mode 100644 source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp rename source/RobotAPI/libraries/armem_skills/server/{SkillObserverComponentPlugin.h => SkillManagerComponentPlugin.h} (62%) delete mode 100644 source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp create mode 100644 source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp create mode 100644 source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt b/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt index a90a8a25c..012e47bbd 100644 --- a/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt +++ b/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt @@ -6,6 +6,7 @@ set(COMPONENT_LIBS ArmarXGuiComponentPlugins RobotAPICore RobotAPIInterfaces + aron armem_skills aronjsonconverter ) diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp index 3404a3312..c22bf43ed 100644 --- a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp +++ b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp @@ -2,11 +2,13 @@ #include "SkillProviderExample.h" +#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> +#include <RobotAPI/libraries/aron/core/type/variant/primitive/String.h> #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> namespace armarx::skills::example { - SkillImplementation::Status HelloWorldSkill::execute(const aron::data::DictPtr& d) + SkillImplementation::Status HelloWorldSkill::execute(const aron::data::DictPtr& d, const CallbackT&) { ARMARX_IMPORTANT << "Hi, from the Hello World Skill.\n" << "I received the following data: \n" << @@ -15,6 +17,24 @@ namespace armarx::skills::example return SkillImplementation::Status::Succeeded; } + SkillImplementation::Status CallbackSkill::execute(const aron::data::DictPtr& d, const CallbackT& callback) + { + ARMARX_IMPORTANT << "Logging three updates via the callback"; + auto up1 = std::make_shared<aron::data::Dict>(); + up1->addElement("updateInfo", std::make_shared<aron::data::String>("Update 1")); + callback(up1); + + auto up2 = std::make_shared<aron::data::Dict>(); + up2->addElement("updateInfo", std::make_shared<aron::data::String>("Update 2")); + callback(up2); + + auto up3 = std::make_shared<aron::data::Dict>(); + up3->addElement("updateInfo", std::make_shared<aron::data::String>("Update 3")); + callback(up3); + + return SkillImplementation::Status::Succeeded; + } + SkillProviderExample::SkillProviderExample() : SkillProviderComponentPluginUser() @@ -35,20 +55,34 @@ namespace armarx::skills::example { // Add example skill { + auto helloWorldAcceptedType = std::make_shared<aron::type::Object>("helloWorldAcceptedType"); + auto helloWorldAcceptedTypeText = std::make_shared<aron::type::String>(aron::Path({"text"})); + helloWorldAcceptedType->addMemberType("text", helloWorldAcceptedTypeText); + skills::SkillDescription helloWorldDesc; - helloWorldDesc.acceptedType = nullptr; // accept everything helloWorldDesc.documentation = "This skill logs a message on ARMARX_IMPORTANT"; helloWorldDesc.name = "HelloWorld"; + helloWorldDesc.acceptedType = helloWorldAcceptedType->toObjectDTO(); + helloWorldDesc.timeoutMs = 1000; addSkill(std::make_shared<HelloWorldSkill>(), helloWorldDesc); } - // Add another example skill + // Add another lambda example skill { skills::SkillDescription fooDesc; - fooDesc.acceptedType = nullptr; + fooDesc.acceptedType = nullptr; // accept everything fooDesc.documentation = "This skill does exactly nothing."; fooDesc.name = "Foo"; - addSkill([](const aron::data::DictPtr&){ return true; }, fooDesc); + addSkill([](const aron::data::DictPtr&){ std::cout << "Hello from Foo" << std::endl; return true; }, fooDesc); + } + + // Add another example skill + { + skills::SkillDescription cbDesc; + cbDesc.acceptedType = nullptr; // accept everything + cbDesc.documentation = "This skill does shows callbacks."; + cbDesc.name = "ShowMeCallbacks"; + addSkill(std::make_shared<CallbackSkill>(), cbDesc); } } diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h index c9eb9026c..a6a9374a9 100644 --- a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h +++ b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h @@ -35,7 +35,14 @@ namespace armarx::skills::example class HelloWorldSkill : public SkillImplementation { public: - Status execute(const aron::data::DictPtr&) override; + Status execute(const aron::data::DictPtr&, const CallbackT&) override; + }; + + + class CallbackSkill : public SkillImplementation + { + public: + Status execute(const aron::data::DictPtr&, const CallbackT&) override; }; /** diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp index dbeb06e78..a11304d70 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp @@ -30,10 +30,6 @@ #include <ArmarXCore/core/time/TimeUtil.h> #include <ArmarXCore/core/logging/Logging.h> - -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> - #include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> @@ -44,12 +40,12 @@ namespace armarx { SkillsMemory::SkillsMemory(): - LightweightRemoteGuiComponentPluginUser(), ReadWritePluginUser(), StatechartListenerComponentPluginUser(), - SkillObserverComponentPluginUser(), + SkillManagerComponentPluginUser(), statechartListenerProviderSegment(iceAdapter()), executableSkillCoreSegment(iceAdapter()), + skillEventCoreSegment(iceAdapter()), skillExecutionRequestCoreSegment(iceAdapter()) { } @@ -64,7 +60,7 @@ namespace armarx executableSkillCoreSegment.defineProperties(defs, prefix + "executableskill."); skillExecutionRequestCoreSegment.defineProperties(defs, prefix + "executionrequest."); - setMemoryName("Skill"); + setMemoryName(MemoryName); return defs; } @@ -80,13 +76,12 @@ namespace armarx statechartListenerProviderSegment.init(); executableSkillCoreSegment.init(); skillExecutionRequestCoreSegment.init(); + skillEventCoreSegment.init(); } void SkillsMemory::onConnectComponent() { - createRemoteGuiTab(); - RemoteGui_startRunningTask(); } @@ -100,20 +95,15 @@ namespace armarx { } - armem::data::AddSegmentsResult SkillsMemory::addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&) - { - // This function is overloaded to trigger the remote gui rebuild. - armem::data::AddSegmentsResult result = ReadWritePluginUser::addSegments(input, false); - tab.rebuild = true; - return result; - } - armem::data::CommitResult SkillsMemory::commit(const armem::data::Commit& commit, const Ice::Current&) { - // This function is overloaded to trigger the remote gui rebuild and to check for skill executions + // This function is overloaded to check for skill executions + // First pass arg to parent func to ensure that data is written into memory and that clients are notified armem::data::CommitResult result = ReadWritePluginUser::commit(commit); + auto myPrx = getProxy<skills::SkillManagerInterfacePrx>(getName()); + for (const auto& up : commit.updates) { if (up.entityID.coreSegmentName == skills::segment::SkillExecutionRequestCoreSegment::CoreSegmentName) @@ -122,8 +112,7 @@ namespace armarx { ARMARX_CHECK_NOT_NULL(instance); - auto aron = aron::data::Variant::FromAronDTO(instance); - auto dict = aron::data::Dict::DynamicCastAndCheck(aron); + auto dict = std::make_shared<aron::data::Dict>(instance); // we got a skill execution request skills::arondto::SkillExecutionRequest request; @@ -131,18 +120,17 @@ namespace armarx auto params = aron::data::Dict::DynamicCastAndCheck(dict->at("params")); // ToDo remov and add to request - executableSkillCoreSegment.directlyExecuteSkill(request, params); + executableSkillCoreSegment.directlyExecuteSkill(request, myPrx, params); } } } - tab.rebuild = true; return result; } void SkillsMemory::addProvider(const std::string& skillProviderName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current ¤t) { - SkillObserverComponentPluginUser::addProvider(skillProviderName, provider, current); + SkillManagerComponentPluginUser::addProvider(skillProviderName, provider, current); executableSkillCoreSegment.addSkillProvider(skillProviderName, provider); } @@ -151,7 +139,7 @@ namespace armarx { executableSkillCoreSegment.removeSkillProvider(skillProviderName); - SkillObserverComponentPluginUser::removeProvider(skillProviderName, current); + SkillManagerComponentPluginUser::removeProvider(skillProviderName, current); } void SkillsMemory::executeSkill(const std::string& skillProviderName, const skills::SkillParametrization& params, const Ice::Current ¤t) @@ -163,49 +151,86 @@ namespace armarx skills::arondto::SkillExecutionRequest request; request.clientId = ""; request.providerName = skillProviderName; - request.skillName = params.name; + request.skillName = params.skillName; auto aron = request.toAron(); - aron->addElement("params", aron::data::Variant::FromAronDTO(params.params)); + aron::data::DictPtr aron_params = nullptr; + if (params.params) aron_params = std::make_shared<aron::data::Dict>(params.params); + + aron->addElement("params", aron_params); // todo add as any type + + armem::MemoryID skillExecutionMemID = skillExecutionRequestCoreSegment.getCoreSegment().id(); + skillExecutionMemID.providerSegmentName = request.providerName; + skillExecutionMemID.entityName = request.skillName; + + entityUpdate.entityID = skillExecutionMemID; entityUpdate.instancesData = { aron }; entityUpdate.confidence = 1.0; entityUpdate.timeCreated = armem::Time::now(); - iceAdapter().commit(comm); // commit and notify + armem::data::Commit iceCommit; + armarx::armem::toIce(iceCommit, comm); + commit(iceCommit, current); // commit and notify } - void SkillsMemory::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& x, const Ice::Current&) + void SkillsMemory::updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current ¤t) { - statechartListenerProviderSegment.reportStatechartTransitionWithParameters(x); - } + // add update for skill to memory + static std::map<armarx::skills::Execution::Status, std::string> ExecutionStatus2String = { + {armarx::skills::Execution::Status::Idle, "Idle"}, + {armarx::skills::Execution::Status::Scheduled, "Scheduled"}, + {armarx::skills::Execution::Status::Running, "Running"}, + {armarx::skills::Execution::Status::RunningButWaitingForDependencies, "RunningButWaitingForDependencies"}, + {armarx::skills::Execution::Status::Aborted, "Aborted"}, + {armarx::skills::Execution::Status::Failed, "Failed"}, + {armarx::skills::Execution::Status::Succeeded, "Succeeded"} + }; - void SkillsMemory::reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList& x, const Ice::Current&) - { - statechartListenerProviderSegment.reportStatechartTransitionWithParametersList(x); - } + // create commit about new update + armarx::skills::arondto::SkillExecutionEvent event; + event.providerName = providerName; + event.skillName = statusUpdate.usedParameterization.skillName; + event.status = ExecutionStatus2String.at(statusUpdate.status); + aron::data::DictPtr aron_params = nullptr; + if (statusUpdate.usedParameterization.params) aron_params = std::make_shared<aron::data::Dict>(statusUpdate.usedParameterization.params); + aron::data::DictPtr aron_result = nullptr; + if (statusUpdate.returnValue) aron_result = std::make_shared<aron::data::Dict>(statusUpdate.returnValue); - void SkillsMemory::createRemoteGuiTab() - { - using namespace armarx::RemoteGui::Client; + armem::MemoryID commitId = skillEventCoreSegment.getCoreSegment().id(); + commitId.providerSegmentName = event.providerName; + commitId.entityName = event.skillName; - { - // Core segments are locked by MemoryRemoteGui. - tab.memoryGroup = armem::server::MemoryRemoteGui().makeGroupBox(workingMemory()); - } + auto aron = event.toAron(); + aron->addElement("result", aron_result); + aron->addElement("params", aron_params); - VBoxLayout root = {tab.memoryGroup, VSpacer()}; - RemoteGui_createTab(getName(), root, &tab); + armem::Commit comm; + auto& entityUpdate = comm.add(); + entityUpdate.confidence = 1.0; + entityUpdate.timeCreated = armem::Time::now(); + entityUpdate.instancesData = { aron }; + entityUpdate.entityID = commitId; + + armem::data::Commit iceCommit; + armarx::armem::toIce(iceCommit, comm); + commit(iceCommit, current); // commit and notify } - void SkillsMemory::RemoteGui_update() + + /* + * Statechart stuff + */ + void SkillsMemory::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& x, const Ice::Current&) { - if (tab.rebuild.exchange(false)) - { - createRemoteGuiTab(); - } + statechartListenerProviderSegment.reportStatechartTransitionWithParameters(x); + } + + void SkillsMemory::reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList& x, const Ice::Current&) + { + statechartListenerProviderSegment.reportStatechartTransitionWithParametersList(x); } } diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h index cc1f95b9b..42e19e753 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h @@ -29,11 +29,9 @@ #include <ArmarXCore/interface/core/Profiler.h> #include <ArmarXCore/observers/ObserverObjectFactories.h> -#include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h> - #include <RobotAPI/interface/skills/SkillMemoryInterface.h> -#include <RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h> +#include <RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h> #include <RobotAPI/libraries/armem_skills/server/StatechartListenerComponentPlugin.h> #include <RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h> @@ -41,6 +39,7 @@ #include <RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.h> #include <RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h> #include <RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.h> +#include <RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h> namespace armarx { @@ -58,10 +57,9 @@ namespace armarx class SkillsMemory : virtual public armarx::Component, virtual public skills::SkillMemoryInterface, - virtual public LightweightRemoteGuiComponentPluginUser, virtual public armem::server::ReadWritePluginUser, virtual public StatechartListenerComponentPluginUser, - virtual public SkillObserverComponentPluginUser + virtual public SkillManagerComponentPluginUser { public: @@ -74,20 +72,15 @@ namespace armarx void reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters&, const Ice::Current&) override; void reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList&, const Ice::Current&) override; - // Override SkillObserver to add memory functions + // Override SkillManager to add memory functions void addProvider(const std::string&, const skills::SkillProviderInterfacePrx& provider, const Ice::Current ¤t) override; void removeProvider(const std::string&, const Ice::Current ¤t) override; void executeSkill(const std::string&, const skills::SkillParametrization& params, const Ice::Current ¤t) override; + void updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current ¤t) override; // WritingInterface interface - armem::data::AddSegmentsResult addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&) override; armem::data::CommitResult commit(const armem::data::Commit& commit, const Ice::Current&) override; - - // LightweightRemoteGuiComponentPluginUser interface - void createRemoteGuiTab(); - void RemoteGui_update() override; - protected: /// @see armarx::ManagedIceObject::onInitComponent() @@ -108,6 +101,8 @@ namespace armarx private: + static constexpr const char* MemoryName = "Skill"; + struct Properties { }; @@ -115,13 +110,7 @@ namespace armarx skills::segment::StatechartListenerProviderSegment statechartListenerProviderSegment; skills::segment::ExecutableSkillLibraryCoreSegment executableSkillCoreSegment; + skills::segment::SkillEventCoreSegment skillEventCoreSegment; skills::segment::SkillExecutionRequestCoreSegment skillExecutionRequestCoreSegment; - - struct RemoteGuiTab : RemoteGui::Client::Tab - { - std::atomic_bool rebuild = false; - RemoteGui::Client::GroupBox memoryGroup; - }; - RemoteGuiTab tab; }; } diff --git a/source/RobotAPI/gui-plugins/CMakeLists.txt b/source/RobotAPI/gui-plugins/CMakeLists.txt index d61010d07..3f50debe2 100644 --- a/source/RobotAPI/gui-plugins/CMakeLists.txt +++ b/source/RobotAPI/gui-plugins/CMakeLists.txt @@ -18,7 +18,7 @@ add_subdirectory(ObjectPoseGui) add_subdirectory(ArMemMemoryViewer) add_subdirectory(ArVizDrawerGui) add_subdirectory(FTSensorCalibrationGui) -add_subdirectory(SkillObserverMonitor) +add_subdirectory(SkillManagerPlugin) add_subdirectory(GraspCandidateViewer) add_subdirectory(BoxToGraspCandidates) diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt new file mode 100644 index 000000000..445d668cf --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LIB_NAME "SkillManagerMonitorGuiPlugin") +armarx_set_target("${LIB_NAME}") + +armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available") + +# do not rename this variable, it is used in armarx_gui_library()... +set(SOURCES SkillManagerMonitorWidgetController.cpp) +set(HEADERS SkillManagerMonitorWidgetController.h) +set(GUI_UIS SkillManagerMonitorWidget.ui) + +# Add more libraries you depend on here, e.g. ${QT_LIBRARIES}. +set(COMPONENT_LIBS RobotAPIInterfaces aron aronjsonconverter SimpleConfigDialog) + +if(ArmarXGui_FOUND) + armarx_gui_plugin("${LIB_NAME}" "${SOURCES}" "" "${GUI_UIS}" "" "${COMPONENT_LIBS}") +endif() diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui similarity index 60% rename from source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui rename to source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui index 16ded1c1b..258061d25 100644 --- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>SkillObserverMonitorWidget</class> - <widget class="QWidget" name="SkillObserverMonitorWidget"> + <class>SkillManagerMonitorWidget</class> + <widget class="QWidget" name="SkillManagerMonitorWidget"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>1148</width> - <height>859</height> + <width>1015</width> + <height>498</height> </rect> </property> <property name="windowTitle"> - <string>SkillObserverMonitorWidget</string> + <string>SkillManagerMonitorWidget</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> @@ -19,25 +19,35 @@ <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <widget class="QWidget" name="widget" native="true"> + <widget class="QGroupBox" name="groupBoxSkills"> + <property name="title"> + <string>Manager</string> + </property> <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QPushButton" name="pushButtonRefreshProvidedSkills"> + <property name="text"> + <string>Refresh</string> + </property> + </widget> + </item> <item row="1" column="0"> <widget class="QTreeWidget" name="treeWidgetSkills"> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> <column> <property name="text"> - <string notr="true">1</string> + <string>Skill</string> + </property> + </column> + <column> + <property name="text"> + <string>HasType</string> + </property> + </column> + <column> + <property name="text"> + <string>State</string> </property> </column> - </widget> - </item> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButtonRefreshProvidedSkills"> - <property name="text"> - <string>Refresh</string> - </property> </widget> </item> </layout> @@ -47,7 +57,40 @@ <string>Skill Details</string> </property> <layout class="QGridLayout" name="gridLayout_2"> - <item row="3" column="0"> + <item row="5" column="0"> + <widget class="QPushButton" name="pushButtonStopSkill"> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QPushButton" name="pushButtonExecuteSkill"> + <property name="text"> + <string>Execute</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QTreeWidget" name="treeWidgetSkillDetails"> + <column> + <property name="text"> + <string>Key</string> + </property> + </column> + <column> + <property name="text"> + <string>Value</string> + </property> + </column> + <column> + <property name="text"> + <string>Type</string> + </property> + </column> + </widget> + </item> + <item row="6" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -60,20 +103,6 @@ </property> </spacer> </item> - <item row="1" column="0"> - <widget class="QPushButton" name="pushButtonStopSkill"> - <property name="text"> - <string>Stop</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButtonStartSkill"> - <property name="text"> - <string>Start</string> - </property> - </widget> - </item> </layout> </widget> </widget> diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp new file mode 100644 index 000000000..2405e4561 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -0,0 +1,607 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * \package RobotAPI::gui-plugins::SkillManagerMonitorWidgetController + * \author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * \date 2020 + * \copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include <string> + +#include <ArmarXCore/util/CPPUtility/Iterator.h> + +#include "SkillManagerMonitorWidgetController.h" + +// debug +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> + +//config +namespace armarx +{ + QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent) + { + if (!dialog) + { + dialog = new SimpleConfigDialog(parent); + dialog->addProxyFinder<skills::SkillManagerInterfacePrx>("SkillManager", "", "Skill*"); + } + return qobject_cast<SimpleConfigDialog*>(dialog); + } + void SkillManagerMonitorWidgetController::configured() + { + observerName = dialog->getProxyName("SkillManager"); + } + void SkillManagerMonitorWidgetController::loadSettings(QSettings* settings) + { + observerName = settings->value("SkillManager", "SkillManager").toString().toStdString(); + } + void SkillManagerMonitorWidgetController::saveSettings(QSettings* settings) + { + settings->setValue("SkillManager", QString::fromStdString(observerName)); + } +} + +//visitors +namespace armarx +{ + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::createSimpleTreeViewWidget(Input& i) + { + ARMARX_CHECK_NOT_NULL(i); + ARMARX_CHECK_NOT_NULL(parentItem); + + auto key = i->getPath().getLastElement(); + createdQWidgetItem = new QTreeWidgetItem(parentItem); + createdQWidgetItem->setText(0, QString::fromStdString(key)); + createdQWidgetItem->setText(2, QString::fromStdString(i->getShortName())); + createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ObjectPtr& i) + { + ARMARX_CHECK_NOT_NULL(i); + ARMARX_CHECK_NOT_NULL(parentItem); + + auto key = i->getObjectName(); + if (i->getPath().hasElement()) + { + key = i->getPath().getLastElement(); + } + + createdQWidgetItem = new QTreeWidgetItem(parentItem); + createdQWidgetItem->setText(0, QString::fromStdString(key)); + + for (const auto& [key, value] : i->getMemberTypes()) + { + SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor v(createdQWidgetItem); + aron::type::visit(v, value); + + if (v.createdQWidgetItem) + { + createdQWidgetItem->addChild(v.createdQWidgetItem); + } + } + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PositionPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::OrientationPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PosePtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i) + { createSimpleTreeViewWidget(i); } + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::TimePtr& i) + { createSimpleTreeViewWidget(i); } + + void SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitUnknown(Input&) + { + ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for a skill argument type."; + } + + + + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ObjectPtr& i) + { + auto createdAronDict = std::make_shared<aron::data::Dict>(); + createdAron = createdAronDict; + QTreeWidgetItem* el = parentItem->child(index); + + unsigned int x = 0; + for (const auto& [key, value] : i->getMemberTypes()) + { + SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor v(el, x++); + aron::type::visit(v, value); + + if (v.createdAron) + { + createdAronDict->addElement(key, v.createdAron); + } + } + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::DictPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::NDArrayPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::MatrixPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::QuaternionPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PositionPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::OrientationPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PosePtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ImagePtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PointCloudPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::IntEnumPtr& i) + { + // TODO + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::IntPtr& i) + { + auto createdAronInt = std::make_shared<aron::data::Int>(); + createdAron = createdAronInt; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + if (str.empty()) + { + createdAronInt->setValue(0); + return; + } + + int val = std::stoi(str); + createdAronInt->setValue(val); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::LongPtr& i) + { + auto createdAronLong = std::make_shared<aron::data::Long>(); + createdAron = createdAronLong; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + if (str.empty()) + { + createdAronLong->setValue(0); + return; + } + + long val = std::stol(str); + createdAronLong->setValue(val); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::FloatPtr& i) + { + auto createdAronFloat = std::make_shared<aron::data::Float>(); + createdAron = createdAronFloat; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + if (str.empty()) + { + createdAronFloat->setValue(0.0); + return; + } + + float val = std::stof(str); + createdAronFloat->setValue(val); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::DoublePtr& i) + { + auto createdAronDouble = std::make_shared<aron::data::Double>(); + createdAron = createdAronDouble; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + if (str.empty()) + { + createdAronDouble->setValue(0.0); + return; + } + + float val = std::stod(str); + createdAronDouble->setValue(val); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::BoolPtr& i) + { + auto createdAronBool = std::make_shared<aron::data::Bool>(); + createdAron = createdAronBool; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + if (str.empty() || str == "false" || str == "no") + { + createdAronBool->setValue(false); + return; + } + + if (str == "true" || str == "yes") + { + createdAronBool->setValue(true); + return; + } + + bool val = std::stoi(str); + createdAronBool->setValue(val); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::StringPtr& i) + { + auto createdAronString = std::make_shared<aron::data::String>(); + createdAron = createdAronString; + QTreeWidgetItem* el = parentItem->child(index); + + std::string str = el->text(1).toStdString(); + createdAronString->setValue(str); + } + + void + SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::TimePtr& i) + { + auto l = std::make_shared<aron::type::Long>(); + visitLong(l); + } + + void SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitUnknown(Input&) + { + ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type to an aron data object."; + } +} + +namespace armarx +{ + SkillManagerMonitorWidgetController::SkillManagerMonitorWidgetController() + { + widget.setupUi(getWidget()); + connect(widget.pushButtonRefreshProvidedSkills, &QPushButton::clicked, + this, &SkillManagerMonitorWidgetController::refreshSkills); + + connect(widget.pushButtonExecuteSkill, &QPushButton::clicked, + this, &SkillManagerMonitorWidgetController::executeSkill); + connect(widget.pushButtonStopSkill, &QPushButton::clicked, + this, &SkillManagerMonitorWidgetController::stopSkill); + + connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged, + this, &SkillManagerMonitorWidgetController::skillSelectionChanged); + + connect(widget.treeWidgetSkillDetails, &QTreeWidget::itemDoubleClicked, + this, &SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked); + } + + SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController() + { + + } + + void SkillManagerMonitorWidgetController::onInitComponent() + { + usingProxy(observerName); + } + + + void SkillManagerMonitorWidgetController::onConnectComponent() + { getProxy(observer, observerName); + widget.groupBoxSkills->setTitle(QString::fromStdString(observerName)); + widget.treeWidgetSkillDetails->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers); + } + + void SkillManagerMonitorWidgetController::onDisconnectComponent() + { + // reset all + skills.clear(); + widget.treeWidgetSkills->clear(); + widget.treeWidgetSkillDetails->clear(); + skillsArgumentsTreeWidgetItem = nullptr; + selectedSkill.providerName = ""; + selectedSkill.skillName = ""; + } + + void SkillManagerMonitorWidgetController::refreshSkills() + { + // get all skills + skills.clear(); + for (const auto& [providerName, provider] : observer->getSkillProviders()) + { + SkillProviderData providerData; + providerData.providerName = providerName; + providerData.skillDescriptions = provider->getSkills(); + skills.insert(std::make_pair(providerName, providerData)); + } + + // put skills into tree view + widget.treeWidgetSkills->clear(); + for (const auto& [providerName, provider] : skills) + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkills); + it->setText(0, QString::fromStdString(providerName)); + for (const auto& [name, sk] : provider.skillDescriptions) + { + auto itsk = new QTreeWidgetItem(it); + it->addChild(itsk); + itsk->setText(0, QString::fromStdString(name)); + } + } + } + + void SkillManagerMonitorWidgetController::executeSkill() + { + if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) + { + return; + } + + const auto& prv = skills.at(selectedSkill.providerName); + if (!prv.skillDescriptions.count(selectedSkill.skillName)) + { + return; + } + + const auto& skillDescription = prv.skillDescriptions.at(selectedSkill.skillName); + skills::SkillParametrization params; + params.skillName = selectedSkill.skillName; + + // create argument aron (if there is an accepted type set) + if (skillsArgumentsTreeWidgetItem) + { + auto aron_accepted_type = std::make_shared<aron::type::Object>(*skillDescription.acceptedType); + + SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor v(skillsArgumentsTreeWidgetItem, 0); + aron::type::visit(v, aron_accepted_type); + + auto aron_args = aron::data::Dict::DynamicCastAndCheck(v.createdAron); + params.params = aron_args->toAronDictPtr(); + } + + ARMARX_INFO << "Executing skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName; + observer->executeSkill(selectedSkill.providerName, params); + } + + void SkillManagerMonitorWidgetController::stopSkill() + { + if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) + { + return; + } + + const auto& prv = skills.at(selectedSkill.providerName); + if (!prv.skillDescriptions.count(selectedSkill.skillName)) + { + return; + } + + // TODO + ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName; + //observer->abortSkill(skills.selectedSkill); + } + + void SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*) + { + widget.groupBoxSkillDetails->setEnabled(false); + + if (!current) + { + // gui has died? + return; + } + + if (!current->parent()) + { + return; + } + + SelectedSkill newSelectedSkill; + + // setup selected skill + newSelectedSkill.providerName = current->parent()->text(0).toStdString(); + newSelectedSkill.skillName = current->text(0).toStdString(); + + // setup groupBox + widget.groupBoxSkillDetails->setTitle(QString::fromStdString(newSelectedSkill.providerName + "/" + newSelectedSkill.skillName)); + widget.groupBoxSkillDetails->setEnabled(true); + + if (newSelectedSkill.providerName == selectedSkill.providerName and newSelectedSkill.skillName == selectedSkill.skillName) + { + return; + } + + selectedSkill = newSelectedSkill; + + // setup table view + widget.treeWidgetSkillDetails->clear(); + skillsArgumentsTreeWidgetItem = nullptr; + + auto skillDesc = skills.at(selectedSkill.providerName).skillDescriptions.at(selectedSkill.skillName); + + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Name"), QString::fromStdString(skillDesc.name)}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Robot"), QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Description"), QString::fromStdString(skillDesc.documentation)}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Timeout"), QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + if (skillDesc.acceptedType) + { + auto aron_args = std::make_shared<aron::type::Object>(*skillDesc.acceptedType); + + skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Arguments")}); + + SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor v(skillsArgumentsTreeWidgetItem); + aron::type::visit(v, aron_args); + + if (v.createdQWidgetItem) + { + skillsArgumentsTreeWidgetItem->addChild(v.createdQWidgetItem); + } + } + else + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("No args")}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + } + + void SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column) + { + if (column == 1) + { + widget.treeWidgetSkillDetails->editItem(item, column); + } + } +} + diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h new file mode 100644 index 000000000..48ace9548 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -0,0 +1,195 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::gui-plugins::SkillManagerMonitorWidgetController + * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ +#pragma once + +#include <stack> +#include <ArmarXCore/core/system/ImportExportComponent.h> + +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> + +#include <RobotAPI/interface/skills/SkillMemoryInterface.h> + +#include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h> + + +#include <RobotAPI/libraries/aron/core/type/variant/All.h> +#include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> + +namespace armarx +{ + class ARMARXCOMPONENT_IMPORT_EXPORT + SkillManagerMonitorWidgetController: + public armarx::ArmarXComponentWidgetControllerTemplate < SkillManagerMonitorWidgetController > + { + Q_OBJECT + + public: + + // Convert aron type to tree widget + class SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor : + public armarx::aron::type::ConstVariantVisitor + { + public: + QTreeWidgetItem* parentItem; + QTreeWidgetItem* createdQWidgetItem; + + SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor() = delete; + SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor(QTreeWidgetItem* i) : + parentItem(i) + {} + + void createSimpleTreeViewWidget(Input& i); + + void visitAronVariant(const aron::type::ObjectPtr&) override; + void visitAronVariant(const aron::type::DictPtr& i) override; + void visitAronVariant(const aron::type::PairPtr& i) override; + void visitAronVariant(const aron::type::TuplePtr& i) override; + void visitAronVariant(const aron::type::ListPtr& i) override; + void visitAronVariant(const aron::type::NDArrayPtr& i) override; + void visitAronVariant(const aron::type::MatrixPtr& i) override; + void visitAronVariant(const aron::type::QuaternionPtr& i) override; + void visitAronVariant(const aron::type::PositionPtr& i) override; + void visitAronVariant(const aron::type::OrientationPtr& i) override; + void visitAronVariant(const aron::type::PosePtr& i) override; + void visitAronVariant(const aron::type::ImagePtr& i) override; + void visitAronVariant(const aron::type::PointCloudPtr& i) override; + void visitAronVariant(const aron::type::IntEnumPtr& i) override; + void visitAronVariant(const aron::type::IntPtr& i) override; + void visitAronVariant(const aron::type::LongPtr& i) override; + void visitAronVariant(const aron::type::FloatPtr& i) override; + void visitAronVariant(const aron::type::DoublePtr& i) override; + void visitAronVariant(const aron::type::BoolPtr& i) override; + void visitAronVariant(const aron::type::StringPtr& i) override; + void visitAronVariant(const aron::type::TimePtr& i) override; + void visitUnknown(Input&) override; + }; + + + // Conversion from TreeView to aron data + class SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor : + public armarx::aron::type::ConstVariantVisitor + { + public: + QTreeWidgetItem* parentItem; + int index; + aron::data::VariantPtr createdAron; + + SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor() = delete; + SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor(QTreeWidgetItem* i, int x) : + parentItem(i), index(x) + {} + + void visitAronVariant(const aron::type::ObjectPtr&) override; + void visitAronVariant(const aron::type::DictPtr&) override; + void visitAronVariant(const aron::type::PairPtr&) override; + void visitAronVariant(const aron::type::TuplePtr&) override; + void visitAronVariant(const aron::type::ListPtr&) override; + void visitAronVariant(const aron::type::NDArrayPtr&) override; + void visitAronVariant(const aron::type::MatrixPtr&) override; + void visitAronVariant(const aron::type::QuaternionPtr&) override; + void visitAronVariant(const aron::type::PositionPtr&) override; + void visitAronVariant(const aron::type::OrientationPtr&) override; + void visitAronVariant(const aron::type::PosePtr&) override; + void visitAronVariant(const aron::type::ImagePtr&) override; + void visitAronVariant(const aron::type::PointCloudPtr&) override; + void visitAronVariant(const aron::type::IntEnumPtr&) override; + void visitAronVariant(const aron::type::IntPtr&) override; + void visitAronVariant(const aron::type::LongPtr&) override; + void visitAronVariant(const aron::type::FloatPtr&) override; + void visitAronVariant(const aron::type::DoublePtr&) override; + void visitAronVariant(const aron::type::BoolPtr&) override; + void visitAronVariant(const aron::type::StringPtr&) override; + void visitAronVariant(const aron::type::TimePtr&) override; + void visitUnknown(Input&) override; + }; + + + /// Controller Constructor + explicit SkillManagerMonitorWidgetController(); + /// Controller destructor + virtual ~SkillManagerMonitorWidgetController(); + + void loadSettings(QSettings* settings) override; + void saveSettings(QSettings* settings) override; + QPointer<QDialog> getConfigDialog(QWidget* parent) override; + void configured() override; + + /** + * Returns the Widget name displayed in the ArmarXGui to create an + * instance of this class. + */ + static QString GetWidgetName() + { + return "Skills.Manager"; + } + + void onInitComponent() override; + void onConnectComponent() override; + void onDisconnectComponent() override; + + private slots: + void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); + + void stopSkill(); + void executeSkill(); + + void refreshSkills(); + + void onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column); + + private: + /** + * Widget Form + */ + Ui::SkillManagerMonitorWidget widget; + QPointer<SimpleConfigDialog> dialog; + + std::string observerName = "SkillManager"; + skills::SkillManagerInterfacePrx observer = nullptr; + + struct SelectedSkill + { + std::string providerName; + std::string skillName; + }; + + struct SkillProviderData + { + std::string providerName; + skills::SkillDescriptionMap skillDescriptions; + }; + + // Data taken from observer + std::map<std::string, SkillProviderData> skills = {}; + + // User Input + SelectedSkill selectedSkill; + + // Helper to get the treeWidgetItem easily + QTreeWidgetItem* skillsArgumentsTreeWidgetItem = nullptr; + }; +} + + diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt deleted file mode 100644 index 8552f06fc..000000000 --- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -#set(LIB_NAME "SkillObserverMonitorGuiPlugin") -#armarx_set_target("${LIB_NAME}") - -#armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available") - -# do not rename this variable, it is used in armarx_gui_library()... -#set(SOURCES SkillObserverMonitorWidgetController.cpp) -#set(HEADERS SkillObserverMonitorWidgetController.h) -#set(GUI_UIS SkillObserverMonitorWidget.ui) - -# Add more libraries you depend on here, e.g. ${QT_LIBRARIES}. -#set(COMPONENT_LIBS RobotAPIInterfaces SimpleConfigDialog) - -#if(ArmarXGui_FOUND) -# armarx_gui_plugin("${LIB_NAME}" "${SOURCES}" "" "${GUI_UIS}" "" "${COMPONENT_LIBS}") -#endif() diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp deleted file mode 100644 index f2295a435..000000000 --- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * This file is part of ArmarX. - * - * ArmarX is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ArmarX is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * \package RobotAPI::gui-plugins::SkillObserverMonitorWidgetController - * \author Raphael Grimm ( raphael dot grimm at kit dot edu ) - * \date 2020 - * \copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#include <string> - -#include <ArmarXCore/util/CPPUtility/Iterator.h> - -#include "SkillObserverMonitorWidgetController.h" - -//config -namespace armarx -{ - /*QPointer<QDialog> SkillObserverMonitorWidgetController::getConfigDialog(QWidget* parent) - { - if (!dialog) - { - dialog = new SimpleConfigDialog(parent); - //dialog->addProxyFinder<skills::SkillObserverInterfacePrx>("SkillObserver", "", "Skill*"); - } - return qobject_cast<SimpleConfigDialog*>(dialog); - } - void SkillObserverMonitorWidgetController::configured() - { - skills.observerName = dialog->getProxyName("SkillObserver"); - } - void SkillObserverMonitorWidgetController::loadSettings(QSettings* settings) - { - skills.observerName = settings->value("SkillObserver", "SkillObserver").toString().toStdString(); - } - - void SkillObserverMonitorWidgetController::saveSettings(QSettings* settings) - { - settings->setValue("SkillObserver", QString::fromStdString(skills.observerName)); - } -} -//other -namespace armarx -{ - SkillObserverMonitorWidgetController::SkillObserverMonitorWidgetController() - { - widget.setupUi(getWidget()); - connect(widget.pushButtonRefreshProvidedSkills, &QPushButton::clicked, - this, &SkillObserverMonitorWidgetController::refreshProvidedSkills); - connect(widget.pushButtonStartSkill, &QPushButton::clicked, - this, &SkillObserverMonitorWidgetController::startSkill); - connect(widget.pushButtonStopSkill, &QPushButton::clicked, - this, &SkillObserverMonitorWidgetController::stopSkill); - connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged, - this, &SkillObserverMonitorWidgetController::skillSelectionChanged); - } - - - SkillObserverMonitorWidgetController::~SkillObserverMonitorWidgetController() - { - - } - - void SkillObserverMonitorWidgetController::onInitComponent() - { - usingProxy(skills.observerName); - } - - - void SkillObserverMonitorWidgetController::onConnectComponent() - { - //getProxy(skills.observer, skills.observerName); - } - - void SkillObserverMonitorWidgetController::refreshProvidedSkills() - { - //skills.skills = skills.observer->getSkills(); - skills.providerIndex.clear(); - widget.treeWidgetSkills->clear(); - for (const auto& [i, pr] : MakeIndexedContainer(skills.skills)) - { - skills.providerIndex[pr.providerName] = i; - auto it = new QTreeWidgetItem(widget.treeWidgetSkills); - widget.treeWidgetSkills->addTopLevelItem(it); - it->setText(0, QString::fromStdString(pr.providerName)); - for (const auto& [name, sk] : pr.skills) - { - auto itsk = new QTreeWidgetItem(it); - it->addChild(itsk); - itsk->setText(0, QString::fromStdString(name)); - } - } - } - - void SkillObserverMonitorWidgetController::startSkill() - { - if (skills.idxActiveProvider < 0 || skills.idxActiveProvider > static_cast<int>(skills.skills.size())) - { - return; - } - const auto& prv = skills.skills.at(skills.idxActiveProvider); - if (!prv.skills.count(skills.selectedSkill)) - { - return; - } - skills::SkillParametrization param; - param.skillName = skills.selectedSkill; - prv.provider->executeSkill(param); - } - - void SkillObserverMonitorWidgetController::stopSkill() - { - if (skills.idxActiveProvider < 0 || skills.idxActiveProvider > static_cast<int>(skills.skills.size())) - { - return; - } - const auto& prv = skills.skills.at(skills.idxActiveProvider); - if (!prv.skills.count(skills.selectedSkill)) - { - return; - } - prv.provider->abortSkill(skills.selectedSkill); - } - - void SkillObserverMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*) - { - skills.idxActiveProvider = -1; - widget.groupBoxSkillDetails->setEnabled(false); - - if (!current->parent()) - { - return; - } - skills.idxActiveProvider = skills.providerIndex.at(current->parent()->text(0).toStdString()); - skills.selectedSkill = current->text(0).toStdString(); - widget.groupBoxSkillDetails->setEnabled(true); - }*/ -} - diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h deleted file mode 100644 index bca23983f..000000000 --- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of ArmarX. - * - * ArmarX is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ArmarX is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * @package RobotAPI::gui-plugins::SkillObserverMonitorWidgetController - * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) - * @date 2020 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ -#pragma once - -#include <ArmarXCore/core/system/ImportExportComponent.h> - -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> -#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> -#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> - -#include <RobotAPI/interface/skills/SkillMemoryInterface.h> - -#include <RobotAPI/gui-plugins/SkillObserverMonitor/ui_SkillObserverMonitorWidget.h> - -namespace armarx -{ - /** - \page RobotAPI-GuiPlugins-SkillObserverMonitor SkillObserverMonitor - \brief The SkillObserverMonitor allows visualizing ... - - \image html SkillObserverMonitor.png - The user can - - API Documentation \ref SkillObserverMonitorWidgetController - - \see SkillObserverMonitorGuiPlugin - */ - - - /** - * \class SkillObserverMonitorGuiPlugin - * \ingroup ArmarXGuiPlugins - * \brief SkillObserverMonitorGuiPlugin brief description - * - * Detailed description - */ - - /** - * \class SkillObserverMonitorWidgetController - * \brief SkillObserverMonitorWidgetController brief one line description - * - * Detailed description - */ - /*class ARMARXCOMPONENT_IMPORT_EXPORT - SkillObserverMonitorWidgetController: - public armarx::ArmarXComponentWidgetControllerTemplate < SkillObserverMonitorWidgetController > - { - Q_OBJECT - - public: - /// Controller Constructor - explicit SkillObserverMonitorWidgetController(); - /// Controller destructor - virtual ~SkillObserverMonitorWidgetController(); - - void loadSettings(QSettings* settings) override; - void saveSettings(QSettings* settings) override; - QPointer<QDialog> getConfigDialog(QWidget* parent) override; - void configured() override;*/ - - /** - * Returns the Widget name displayed in the ArmarXGui to create an - * instance of this class. - */ - /*static QString GetWidgetName() - { - return "Skills.ObserverMonitor"; - } - - /// \see armarx::Component::onInitComponent() - void onInitComponent() override; - - /// \see armarx::Component::onConnectComponent() - void onConnectComponent() override; - - private slots: - void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); - void stopSkill(); - void startSkill(); - void refreshProvidedSkills(); - - private:*/ - /** - * Widget Form - */ - /*Ui::SkillObserverMonitorWidget widget; - QPointer<SimpleConfigDialog> dialog; - struct SkillData - { - std::string observerName; - //skills::SkillObserverInterfacePrx observer; - skills::ProviderSkillsSeq skills; - std::map<std::string, int> providerIndex; - int idxActiveProvider = -1; - std::string selectedSkill; - }; - SkillData skills; - };*/ -} - - diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt index 77cca5e95..638e9737b 100644 --- a/source/RobotAPI/interface/CMakeLists.txt +++ b/source/RobotAPI/interface/CMakeLists.txt @@ -137,7 +137,7 @@ set(SLICE_FILES components/ObstacleAvoidance/DSObstacleAvoidanceInterface.ice components/ObstacleAvoidance/DynamicObstacleManagerInterface.ice - skills/SkillObserverInterface.ice + skills/SkillManagerInterface.ice skills/StatechartListenerInterface.ice skills/SkillMemoryInterface.ice skills/SkillProviderInterface.ice diff --git a/source/RobotAPI/interface/skills/SkillObserverInterface.ice b/source/RobotAPI/interface/skills/SkillManagerInterface.ice similarity index 77% rename from source/RobotAPI/interface/skills/SkillObserverInterface.ice rename to source/RobotAPI/interface/skills/SkillManagerInterface.ice index 81d6c4212..48c538cc6 100644 --- a/source/RobotAPI/interface/skills/SkillObserverInterface.ice +++ b/source/RobotAPI/interface/skills/SkillManagerInterface.ice @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package RobotAPI::ArmarXObjects::SkillObserver + * @package RobotAPI::ArmarXObjects::SkillManager * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) * @date 2020 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt @@ -28,12 +28,16 @@ module armarx { module skills { - interface SkillObserverInterface + interface SkillManagerInterface // rename to manager { void addProvider(string providerName, SkillProviderInterface* provider); void removeProvider(string providerName); + SkillProviderMap getSkillProviders(); void executeSkill(string providerName, SkillParametrization skill); + + // used for callbacks from providers to update their skill execution status + void updateStatusForSkill(string providerName, SkillStatus statusUpdate); }; } } diff --git a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice index 51d516b22..8025d4cdb 100644 --- a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice +++ b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package RobotAPI::ArmarXObjects::SkillObserver + * @package RobotAPI::ArmarXObjects::SkillManager * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) * @date 2020 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt @@ -25,7 +25,7 @@ #include <ArmarXCore/interface/core/Profiler.ice> #include <RobotAPI/interface/skills/SkillProviderInterface.ice> -#include <RobotAPI/interface/skills/SkillObserverInterface.ice> +#include <RobotAPI/interface/skills/SkillManagerInterface.ice> #include <RobotAPI/interface/skills/StatechartListenerInterface.ice> #include <RobotAPI/interface/armem/server/MemoryInterface.ice> @@ -33,7 +33,7 @@ module armarx { module skills { - interface SkillMemoryInterface extends armem::server::MemoryInterface, StatechartListenerInterface, SkillObserverInterface + interface SkillMemoryInterface extends armem::server::MemoryInterface, StatechartListenerInterface, SkillManagerInterface { }; } diff --git a/source/RobotAPI/interface/skills/SkillProviderInterface.ice b/source/RobotAPI/interface/skills/SkillProviderInterface.ice index 8e710ed82..24c4f4e4e 100644 --- a/source/RobotAPI/interface/skills/SkillProviderInterface.ice +++ b/source/RobotAPI/interface/skills/SkillProviderInterface.ice @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package RobotAPI::ArmarXObjects::SkillObserver + * @package RobotAPI::ArmarXObjects::SkillManager * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) * @date 2020 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt @@ -34,9 +34,11 @@ module armarx struct SkillDescription { string name; - string robot; - string documentation; - aron::type::dto::AronObject acceptedType; + StringList robots; + string documentation; // rename to what? + long timeoutMs; // Millisecs + + aron::type::dto::AronObject acceptedType; // the name of the object is irrelevant and only used in GUI }; dictionary<string, SkillDescription> SkillDescriptionMap; @@ -48,35 +50,37 @@ module armarx Scheduled, RunningButWaitingForDependencies, Running, + + // terminating values Failed, Succeeded, Aborted }; }; + interface SkillManagerInterface; + struct SkillParametrization + { + string skillName; + aron::data::dto::Dict params; + }; + struct SkillStatus { Execution::Status status; - aron::data::dto::Dict usedParams; - aron::data::dto::Dict returnValue; - string message; - string error; + SkillParametrization usedParameterization; + aron::data::dto::Dict returnValue; // can be anything + //string message; + //string error; }; dictionary<string, SkillStatus> SkillStatusMap; - - struct SkillParametrization - { - string name; - aron::data::dto::Dict params; - }; - interface SkillProviderInterface { SkillDescriptionMap getSkills(); - SkillStatusMap getSkillExecutionStatus(); - void executeSkill(SkillParametrization skill); + SkillStatus getSkillExecutionStatus(string name); + void executeSkill(SkillParametrization skill, SkillManagerInterface* callbackInterface); // use nullptr if you do not want to have callbacks SkillStatus abortSkill(string skill); }; diff --git a/source/RobotAPI/interface/skills/StatechartListenerInterface.ice b/source/RobotAPI/interface/skills/StatechartListenerInterface.ice index 2081d8e56..abcd88398 100644 --- a/source/RobotAPI/interface/skills/StatechartListenerInterface.ice +++ b/source/RobotAPI/interface/skills/StatechartListenerInterface.ice @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * - * @package RobotAPI::ArmarXObjects::SkillObserver + * @package RobotAPI::ArmarXObjects::SkillManager * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) * @date 2020 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt diff --git a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt index bec7daa0d..19e4c5a56 100644 --- a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt @@ -16,20 +16,22 @@ armarx_add_library( ./aron_conversions.cpp ./server/StatechartListenerComponentPlugin.cpp - ./server/SkillObserverComponentPlugin.cpp + ./server/SkillManagerComponentPlugin.cpp ./server/segment/StatechartListenerSegment.cpp ./server/segment/ExecutableSkillLibrarySegment.cpp ./server/segment/SkillExecutionRequestSegment.cpp + ./server/segment/SkillEventSegment.cpp ./client/SkillProviderComponentPlugin.cpp HEADERS ./aron_conversions.h ./server/StatechartListenerComponentPlugin.h - ./server/SkillObserverComponentPlugin.h + ./server/SkillManagerComponentPlugin.h ./server/segment/StatechartListenerSegment.h ./server/segment/ExecutableSkillLibrarySegment.h ./server/segment/SkillExecutionRequestSegment.h + ./server/segment/SkillEventSegment.h ./client/SkillProviderComponentPlugin.h ) diff --git a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml index 46af4143e..838960afb 100644 --- a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml +++ b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml @@ -16,8 +16,10 @@ The memory should look like the following: <String /> </ObjectChild> - <ObjectChild key='robot'> - <String /> + <ObjectChild key='robots'> + <List> + <String /> + </List> </ObjectChild> <ObjectChild key='documentation'> @@ -49,5 +51,22 @@ The memory should look like the following: <!-- ToDo: add params wih any type --> </Object> + <Object name='armarx::skills::arondto::SkillExecutionEvent'> + <ObjectChild key='providerName'> + <String /> + </ObjectChild> + + <ObjectChild key='skillName'> + <String /> + </ObjectChild> + + <ObjectChild key='status'> + <String /> + </ObjectChild> + + <!-- ToDo: add params with any type --> + <!-- ToDo: add result with any type --> + </Object> + </GenerateTypes> </AronTypeDefinition> diff --git a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp index d47ca065f..35b128e53 100644 --- a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp @@ -2,6 +2,8 @@ #include <ArmarXCore/core/Component.h> +#include <RobotAPI/libraries/aron/core/data/variant/primitive/All.h> + namespace armarx::plugins { void SkillProviderComponentPlugin::preOnInitComponent() @@ -19,13 +21,13 @@ namespace armarx::plugins { auto& p = parent<SkillProviderComponentPluginUser>(); std::string providerName = p.getName(); - skillObserver->addProvider(providerName, skillProvider); + SkillManager->addProvider(providerName, skillProvider); } void SkillProviderComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) { std::string prefix = "skill."; - properties->component(skillObserver, "SkillMemory", prefix + "SkillObserver", "The name of the SkillObserver (or SkillMemory) proxy."); + properties->component(SkillManager, "SkillMemory", prefix + "SkillManager", "The name of the SkillManager (or SkillMemory) proxy."); } } @@ -40,6 +42,7 @@ namespace armarx void SkillProviderComponentPluginUser::addSkill(const skills::SkillImplementationPtr& fun, const skills::SkillDescription& desc) { std::lock_guard l(skillsMutex); + std::string providerName = getName(); std::string skillName = desc.name; if (skillImplementations.find(skillName) != skillImplementations.end()) @@ -49,7 +52,7 @@ namespace armarx } ARMARX_DEBUG << "Adding skill " << skillName << " to list"; - SkillImplementationWrapper skill(fun, desc); + SkillImplementationWrapper skill(fun, providerName, desc); skillImplementations.insert({skillName, skill}); } @@ -70,22 +73,19 @@ namespace armarx return skillDesciptions; } - skills::SkillStatusMap SkillProviderComponentPluginUser::getSkillExecutionStatus(const Ice::Current ¤t) + skills::SkillStatus SkillProviderComponentPluginUser::getSkillExecutionStatus(const std::string& skill, const Ice::Current ¤t) { std::lock_guard l(skillsMutex); - skills::SkillStatusMap skillStatus; - for (const auto& [key, skillImplementation] : skillImplementations) - { - std::lock_guard l(skillImplementation.skillStatusMutex); - skillStatus.insert({key, skillImplementation.status}); - } - return skillStatus; + auto& skillImplementation = skillImplementations.at(skill); + + std::lock_guard l2(skillImplementation.skillStatusMutex); + return skillImplementation.status; } - void SkillProviderComponentPluginUser::executeSkill(const skills::SkillParametrization& params, const Ice::Current ¤t) + void SkillProviderComponentPluginUser::executeSkill(const skills::SkillParametrization& params, const skills::SkillManagerInterfacePrx& callbackInterface, const Ice::Current ¤t) { std::lock_guard l(skillsMutex); - std::string skillName = params.name; + std::string skillName = params.skillName; ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0); auto& impl = skillImplementations.at(skillName); @@ -96,31 +96,38 @@ namespace armarx } // update input params - impl.status.usedParams = params.params; + impl.reset(); + impl.callbackInterface = callbackInterface; + impl.status.usedParameterization = params; // recreate thread and execute skill - impl.stop = false; impl.task = std::thread{ [&] { impl.execute(); } }; } skills::SkillStatus SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, const Ice::Current ¤t) { std::lock_guard l(skillsMutex); - if (skillImplementations.count(skillName)) + ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0); + auto& impl = skillImplementations.at(skillName); + impl.stop = true; + if (impl.task.joinable()) { - auto& impl = skillImplementations.at(skillName); - impl.stop = true; - if (impl.task.joinable()) - { - impl.task.join(); - - std::lock_guard l(impl.skillStatusMutex); - impl.status.status = skills::Execution::Aborted; - } + impl.task.join(); - return skillImplementations.at(skillName).status; + std::lock_guard l(impl.skillStatusMutex); + impl.status.status = skills::Execution::Aborted; } - return {}; + + return skillImplementations.at(skillName).status; + } + + void SkillProviderComponentPluginUser::SkillImplementationWrapper::reset() + { + std::lock_guard l(skillStatusMutex); + stop = false; + status.status = skills::Execution::Status::Idle; + status.returnValue = nullptr; + skillStarted = 0; } void SkillProviderComponentPluginUser::SkillImplementationWrapper::execute() @@ -128,10 +135,26 @@ namespace armarx ARMARX_INFO_S << "Executing skill: " << description.name; try { + // set scheduled and reset skill + { + std::lock_guard l(skillStatusMutex); + status.status = skills::Execution::Scheduled; + + // do callback + if (callbackInterface) + { + callbackInterface->updateStatusForSkill(providerName, status); + } + } + // wait for dependencies { std::lock_guard l(skillStatusMutex); status.status = skills::Execution::RunningButWaitingForDependencies; + if (callbackInterface) + { + callbackInterface->updateStatusForSkill(providerName, status); + } } if (stop) return; @@ -140,33 +163,78 @@ namespace armarx if (initialized != skills::SkillImplementation::Status::Succeeded) { - status.error = "Could not initialize the skill."; - { - std::lock_guard l(skillStatusMutex); - status.status = skills::Execution::Failed; - } + // create message to return + auto returnDict = std::make_shared<aron::data::Dict>(); + auto message = std::make_shared<aron::data::String>("Could not initialize the skill."); + returnDict->addElement("message", message); + status.returnValue = returnDict->toAronDictPtr(); + + throw armarx::LocalException("The Skill '"+description.name+"' failed during initialization."); } // execute { std::lock_guard l(skillStatusMutex); status.status = skills::Execution::Running; + if (callbackInterface) + { + callbackInterface->updateStatusForSkill(providerName, status); + } } if (stop) return; - auto params = std::make_shared<aron::data::Dict>(status.usedParams); - auto result = skill->execute(params); + aron::data::DictPtr aron_params = nullptr; + if (status.usedParameterization.params) // check if params are set. + { + aron_params = std::make_shared<aron::data::Dict>(status.usedParameterization.params); + } + else + { + if (description.acceptedType) + { + throw armarx::LocalException("The Skill '"+description.name+"' requires a type but no params are NULL."); + } + } + + auto updateCallback = [&](const aron::data::DictPtr& update) + { + if (update) + { + status.returnValue = update->toAronDictPtr(); + callbackInterface->updateStatusForSkill(providerName, status); + } + }; + auto result = skill->execute(aron_params, updateCallback); if (stop) return; { + if (result == skills::SkillImplementation::Status::Failed) + { + throw armarx::LocalException("The Skill '"+description.name+"' failed during execution."); + } + if (result == skills::SkillImplementation::Status::TimeoutReached) + { + throw armarx::LocalException("The Skill '"+description.name+"' reached timeout during execution."); + } + std::lock_guard l(skillStatusMutex); - status.status = ((result == skills::SkillImplementation::Status::Succeeded) ? skills::Execution::Succeeded : skills::Execution::Failed); + status.status = skills::Execution::Succeeded; + if (callbackInterface) + { + callbackInterface->updateStatusForSkill(providerName, status); + } } } - catch (...) + catch (const std::exception& ex) { + ARMARX_WARNING_S << "Skill " << description.name << " died with exception:\n" << ex.what(); + std::lock_guard l(skillStatusMutex); status.status = skills::Execution::Failed; + if (callbackInterface) + { + callbackInterface->updateStatusForSkill(providerName, status); + } } } } diff --git a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h index 666ee05e1..8f5cc81fb 100644 --- a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h +++ b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h @@ -10,7 +10,7 @@ #include <ArmarXCore/core/services/tasks/RunningTask.h> -#include <RobotAPI/interface/skills/SkillObserverInterface.h> +#include <RobotAPI/interface/skills/SkillManagerInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> namespace armarx::plugins @@ -28,7 +28,7 @@ namespace armarx::plugins void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; private: - skills::SkillObserverInterfacePrx skillObserver; + skills::SkillManagerInterfacePrx SkillManager; skills::SkillProviderInterfacePrx skillProvider; }; } @@ -40,6 +40,8 @@ namespace armarx class SkillImplementation { public: + using CallbackT = std::function<void(const aron::data::DictPtr&)>; + enum class Status { Succeeded, @@ -52,34 +54,19 @@ namespace armarx return Status::Succeeded; } - virtual Status execute(const aron::data::DictPtr&) + /// Override this method with the actual implementation. The callback is for status updates + virtual Status execute(const aron::data::DictPtr& params, const CallbackT& callback) { ARMARX_WARNING_S << "You have to override this method!"; return Status::Succeeded; } - void reset() + /// Use this if you do not need a callback + Status execute(const aron::data::DictPtr& params) { - skillStarted = 0; - } - - protected: - bool isTimeoutReached() const - { - if (timeoutMs < 0) - { - return false; - } - - auto now = IceUtil::Time::now().toMilliSeconds(); - return (now - skillStarted) >= timeoutMs; + auto fun = [](const aron::data::DictPtr&) {}; + return execute(params, fun); } - - public: - long timeoutMs = -1; - - protected: - long skillStarted = 0; }; class LambdaSkillImplementation : public SkillImplementation @@ -90,7 +77,7 @@ namespace armarx LambdaSkillImplementation() = delete; LambdaSkillImplementation(const FunT& f) : fun(f) {}; - SkillImplementation::Status execute(const aron::data::DictPtr& data) override + SkillImplementation::Status execute(const aron::data::DictPtr& data, const CallbackT& callback) override { bool res = fun(data); return res ? Status::Succeeded : Status::Failed; @@ -112,35 +99,56 @@ namespace armarx public: struct SkillImplementationWrapper { - skills::SkillDescription description; - skills::SkillImplementationPtr skill; + // fixed values. Do not change after skill instantiation + const std::string providerName; + const skills::SkillDescription description; + const skills::SkillImplementationPtr skill; - // Current execution status + // Current execution status. Changes during execution skills::SkillStatus status; - // Task + // Used callback interface. May change on start + skills::SkillManagerInterfacePrx callbackInterface = nullptr; + + // Info + long skillStarted = 0; + + // Task information. task is recreated every time the skill restarts mutable std::mutex skillStatusMutex; std::atomic_bool stop = false; std::thread task; - SkillImplementationWrapper(const skills::SkillImplementationPtr& fun, const skills::SkillDescription& desc) : - description(desc), skill(fun) + SkillImplementationWrapper(const skills::SkillImplementationPtr& fun, const std::string& providerName, const skills::SkillDescription& desc) : + providerName(providerName), description(desc), skill(fun) { - status.status = skills::Execution::Status::Idle; + reset(); } SkillImplementationWrapper(const SkillImplementationWrapper& s) : - SkillImplementationWrapper(s.skill, s.description) + SkillImplementationWrapper(s.skill, s.providerName, s.description) {} void execute(); + void reset(); + + private: + bool isTimeoutReached() const + { + if (description.timeoutMs < 0) + { + return false; + } + + auto now = IceUtil::Time::now().toMilliSeconds(); + return (now - skillStarted) >= description.timeoutMs; + } }; SkillProviderComponentPluginUser(); skills::SkillDescriptionMap getSkills(const Ice::Current ¤t) override; - skills::SkillStatusMap getSkillExecutionStatus(const Ice::Current ¤t) override; - void executeSkill(const skills::SkillParametrization &skill, const Ice::Current ¤t) override; + skills::SkillStatus getSkillExecutionStatus(const std::string& skill, const Ice::Current ¤t) override; + void executeSkill(const skills::SkillParametrization &skill, const skills::SkillManagerInterfacePrx& callbackInterface, const Ice::Current ¤t) override; skills::SkillStatus abortSkill(const std::string &skill, const Ice::Current ¤t) override; protected: diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp new file mode 100644 index 000000000..ee2445911 --- /dev/null +++ b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp @@ -0,0 +1,65 @@ +#include "SkillManagerComponentPlugin.h" + +#include <ArmarXCore/core/Component.h> + +namespace armarx::plugins +{ + void SkillManagerComponentPlugin::preOnInitComponent() + {} + + void SkillManagerComponentPlugin::preOnConnectComponent() + {} + + void SkillManagerComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + {} +} + + +namespace armarx +{ + SkillManagerComponentPluginUser::SkillManagerComponentPluginUser() + { + addPlugin(plugin); + } + + void SkillManagerComponentPluginUser::addProvider(const std::string& providerName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current&) + { + std::lock_guard l(skillProviderMapMutex); + if (skillProviderMap.find(providerName) == skillProviderMap.end()) + { + ARMARX_INFO << "Adding a provider with name '" << providerName << "'."; + skillProviderMap.insert({providerName, provider}); + } + } + + void SkillManagerComponentPluginUser::removeProvider(const std::string& providerName, const Ice::Current&) + { + std::lock_guard l(skillProviderMapMutex); + if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + { + skillProviderMap.erase(it); + } + } + + skills::SkillProviderMap SkillManagerComponentPluginUser::getSkillProviders(const Ice::Current&) + { + return skillProviderMap; + } + + void SkillManagerComponentPluginUser::executeSkill(const std::string& providerName, const skills::SkillParametrization& params, const Ice::Current&) + { + if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + { + auto myPrx = getProxy<skills::SkillManagerInterfacePrx>(getName()); + it->second->executeSkill(params, myPrx); + } + throw LocalException("Could not execute a skill of provider '" + providerName + "' because the provider does not exist."); + } + + void SkillManagerComponentPluginUser::updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current&) + { + (void) providerName; + (void) statusUpdate; + // If you want to use the status, implement this method! + } +} diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h similarity index 62% rename from source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h rename to source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h index cbd2e60e6..8e976fbf0 100644 --- a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h +++ b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h @@ -5,11 +5,11 @@ #include <ArmarXCore/core/ComponentPlugin.h> #include <ArmarXCore/core/ManagedIceObject.h> -#include <RobotAPI/interface/skills/SkillObserverInterface.h> +#include <RobotAPI/interface/skills/SkillManagerInterface.h> namespace armarx::plugins { - class SkillObserverComponentPlugin : public ComponentPlugin + class SkillManagerComponentPlugin : public ComponentPlugin { public: using ComponentPlugin::ComponentPlugin; @@ -24,19 +24,22 @@ namespace armarx::plugins namespace armarx { - class SkillObserverComponentPluginUser : + class SkillManagerComponentPluginUser : virtual public ManagedIceObject, - virtual public skills::SkillObserverInterface + virtual public skills::SkillManagerInterface { public: - SkillObserverComponentPluginUser(); + SkillManagerComponentPluginUser(); void addProvider(const std::string&, const skills::SkillProviderInterfacePrx& provider, const Ice::Current ¤t) override; void removeProvider(const std::string&, const Ice::Current ¤t) override; + skills::SkillProviderMap getSkillProviders(const Ice::Current ¤t) override; void executeSkill(const std::string&, const skills::SkillParametrization& params, const Ice::Current ¤t) override; + void updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current ¤t) override; + private: - armarx::plugins::SkillObserverComponentPlugin* plugin = nullptr; + armarx::plugins::SkillManagerComponentPlugin* plugin = nullptr; protected: std::mutex skillProviderMapMutex; diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp deleted file mode 100644 index 479fd5843..000000000 --- a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "SkillObserverComponentPlugin.h" - -#include <ArmarXCore/core/Component.h> - -namespace armarx::plugins -{ - void SkillObserverComponentPlugin::preOnInitComponent() - {} - - void SkillObserverComponentPlugin::preOnConnectComponent() - {} - - void SkillObserverComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) - {} -} - - -namespace armarx -{ - SkillObserverComponentPluginUser::SkillObserverComponentPluginUser() - { - addPlugin(plugin); - } - - void SkillObserverComponentPluginUser::addProvider(const std::string& providerName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current ¤t) - { - std::lock_guard l(skillProviderMapMutex); - if (skillProviderMap.find(providerName) == skillProviderMap.end()) - { - ARMARX_INFO << "Adding a provider with name '" << providerName << "'."; - skillProviderMap.insert({providerName, provider}); - } - } - - void SkillObserverComponentPluginUser::removeProvider(const std::string& providerName, const Ice::Current ¤t) - { - std::lock_guard l(skillProviderMapMutex); - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) - { - skillProviderMap.erase(it); - } - } - - void SkillObserverComponentPluginUser::executeSkill(const std::string& providerName, const skills::SkillParametrization& params, const Ice::Current ¤t) - { - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) - { - it->second->executeSkill(params); - } - throw LocalException("Could not execute a skill of provider '" + providerName + "' because the provider does not exist."); - } -} diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp index 8b9d00133..d5bd93058 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp +++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp @@ -35,7 +35,7 @@ namespace armarx::skills::segment skillDescription.name = desc.name; skillDescription.documentation = desc.documentation; skillDescription.iceInfo = skillProvider->ice_toString(); - skillDescription.robot = desc.robot; + skillDescription.robots = desc.robots; if (desc.acceptedType) { aron::type::VariantPtr t = aron::type::Variant::FromAronDTO(*desc.acceptedType); @@ -54,12 +54,15 @@ namespace armarx::skills::segment } } - void ExecutableSkillLibraryProviderSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const aron::data::DictPtr& params) + void ExecutableSkillLibraryProviderSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params) { skills::SkillParametrization parameterization; - parameterization.name = req.skillName; - parameterization.params = params->toAronDictPtr(); - skillProvider->executeSkill(parameterization); // ToDo: put in thread? + parameterization.skillName = req.skillName; + if (params) // may be null + { + parameterization.params = params->toAronDictPtr(); + } + skillProvider->executeSkill(parameterization, callbackInterface); } ExecutableSkillLibraryCoreSegment::ExecutableSkillLibraryCoreSegment(armem::server::MemoryToIceAdapter& iceMemory): @@ -86,20 +89,25 @@ namespace armarx::skills::segment } else { - ARMARX_WARNING << "Could not insert a skillProvider '"<<providerSegmentName<<"' to the segment '" << getCoreSegment().id().str() << "'. This may leave the skillObserver and the memory unsynchronized."; + ARMARX_WARNING << "Could not insert a skillProvider '"<<providerSegmentName<<"' to the segment '" << getCoreSegment().id().str() << "'. This may leave the SkillManager and the memory unsynchronized."; } } + SkillProviderInterfacePrx ExecutableSkillLibraryCoreSegment::getSkillProvider(const std::string& providerName) const + { + return providerSegments.at(providerName).skillProvider; + } + void ExecutableSkillLibraryCoreSegment::removeSkillProvider(const std::string& providerName) { providerSegments.erase(providerName); } - void ExecutableSkillLibraryCoreSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const aron::data::DictPtr& params) + void ExecutableSkillLibraryCoreSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params) { if (const auto& it = providerSegments.find(req.providerName); it != providerSegments.end()) { - it->second.directlyExecuteSkill(req, params); + it->second.directlyExecuteSkill(req, callbackInterface, params); } } diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h index 2f8652067..dd2dba322 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h +++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h @@ -25,9 +25,9 @@ namespace armarx::skills::segment void defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix); void init(); - void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const aron::data::DictPtr& params); + void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params); - private: + public: SkillProviderInterfacePrx skillProvider; }; @@ -45,8 +45,9 @@ namespace armarx::skills::segment void init(); void addSkillProvider(const std::string& providerName, const SkillProviderInterfacePrx& provider); + SkillProviderInterfacePrx getSkillProvider(const std::string& providerName) const; void removeSkillProvider(const std::string& providerName); - void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const aron::data::DictPtr& params); + void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params); size_t size() const; diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp new file mode 100644 index 000000000..012a2c0ad --- /dev/null +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp @@ -0,0 +1,27 @@ +#include "SkillEventSegment.h" + +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> +#include <SimoxUtility/algorithm/string.h> + +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> + +#include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h> + +namespace armarx::skills::segment +{ + + SkillEventCoreSegment::SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory): + Base(iceMemory, CoreSegmentName) + { + } + + void SkillEventCoreSegment::defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix) + { + // No properties! (meaning no name and no max size) + } + + void SkillEventCoreSegment::init() + { + Base::init(); + } +} diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h new file mode 100644 index 000000000..7867bc934 --- /dev/null +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h @@ -0,0 +1,31 @@ +#pragma once + +#include <thread> + +// Base Class +#include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h> + +// ArmarX +#include <RobotAPI/interface/skills/SkillProviderInterface.h> + +#include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h> + +namespace armarx::skills::segment +{ + class SkillEventCoreSegment : + public armem::server::segment::SpecializedCoreSegment + { + using Base = armem::server::segment::SpecializedCoreSegment; + + public: + static constexpr const char* CoreSegmentName = "SkillEvent"; + + SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory); + + void defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix); + void init(); + + private: + std::map<std::string, std::map<std::string, std::thread>> pollers; + }; +} diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp index 158e8c5e1..a4a02d913 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp @@ -12,7 +12,7 @@ namespace armarx::skills::segment { SkillExecutionRequestProviderSegment::SkillExecutionRequestProviderSegment(const std::string& provName, const SkillProviderInterfacePrx& prx, armem::server::MemoryToIceAdapter& iceMemory): - Base(iceMemory, provName, SkillExecutionRequestCoreSegment::CoreSegmentName, skills::arondto::SkillExecutionRequest::toAronType()) + Base(iceMemory, provName, SkillExecutionRequestCoreSegment::CoreSegmentName/*, skills::arondto::SkillExecutionRequest::toAronType()*/) { } @@ -27,7 +27,7 @@ namespace armarx::skills::segment } SkillExecutionRequestCoreSegment::SkillExecutionRequestCoreSegment(armem::server::MemoryToIceAdapter& iceMemory): - Base(iceMemory, CoreSegmentName, skills::arondto::SkillExecutionRequest::toAronType()) + Base(iceMemory, CoreSegmentName/*, skills::arondto::SkillExecutionRequest::toAronType()*/) { } diff --git a/source/RobotAPI/libraries/aron/core/type/variant/Variant.h b/source/RobotAPI/libraries/aron/core/type/variant/Variant.h index faaf06cdc..ab996582c 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/Variant.h +++ b/source/RobotAPI/libraries/aron/core/type/variant/Variant.h @@ -33,6 +33,7 @@ // #include <SimoxUtility/algorithm/string.h> // ArmarX +#include <RobotAPI/libraries/aron/core/Path.h> #include <RobotAPI/libraries/aron/core/Exception.h> #include <RobotAPI/interface/aron.h> #include <RobotAPI/libraries/aron/core/Descriptor.h> diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp index 1ba76b626..3919bf844 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp @@ -37,7 +37,7 @@ namespace armarx::aron::type Dict::Dict(const type::dto::Dict& o, const Path& path) : detail::ContainerVariant<type::dto::Dict, Dict>(o, type::Descriptor::eDict, path), - acceptedType(FromAronDTO(*o.acceptedType)) + acceptedType(FromAronDTO(*o.acceptedType, path.withAcceptedType())) { } diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp index 2f65cb75b..807d64fed 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp @@ -36,7 +36,7 @@ namespace armarx::aron::type List::List(const type::dto::List& o, const Path& path) : detail::ContainerVariant<type::dto::List, List>(o, type::Descriptor::eList, path), - acceptedType(FromAronDTO(*o.acceptedType)) + acceptedType(FromAronDTO(*o.acceptedType, path.withAcceptedType())) { } diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp index d252ae8fc..52eb6ed43 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp @@ -47,9 +47,10 @@ namespace armarx::aron::type Object::Object(const type::dto::AronObject& o, const Path& path) : detail::ContainerVariant<type::dto::AronObject, Object>(o, type::Descriptor::eObject, path) { + setObjectName(o.objectName); for (const auto& [key, t] : o.elementTypes) { - memberTypes[key] = FromAronDTO(*t); + memberTypes[key] = FromAronDTO(*t, path.withElement(key)); } } @@ -155,7 +156,7 @@ namespace armarx::aron::type type::dto::AronObjectPtr Object::toObjectDTO() const { - // TODO: Shall we allow empty objects? + // TODO: Shall we allow empty objects? For now yes! //if(acceptedTypeNavigators.empty()) //{ // throw exception::AronExceptionWithPathInfo("ObjectNavigator", "getResult", "No accepted types set", getPath()); diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h index 50ce062d4..4c2f58738 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h @@ -45,7 +45,7 @@ namespace armarx::aron::type { public: // constructors - Object(const std::string&, const std::map<std::string, VariantPtr>&, const Path& = Path()); + Object(const std::string&, const std::map<std::string, VariantPtr>& = {}, const Path& = Path()); Object(const type::dto::AronObject&, const Path& = Path()); // public member functions diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp index d1cebcd3d..48e0c6f4d 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp @@ -39,8 +39,8 @@ namespace armarx::aron::type Pair::Pair(const type::dto::Pair& o, const Path& path) : detail::ContainerVariant<type::dto::Pair, Pair>(o, type::Descriptor::ePair, path), - acceptedType1(FromAronDTO(*o.acceptedType1)), - acceptedType2(FromAronDTO(*o.acceptedType2)) + acceptedType1(FromAronDTO(*o.acceptedType1, path.withAcceptedTypeIndex(0))), + acceptedType2(FromAronDTO(*o.acceptedType2, path.withAcceptedTypeIndex(1))) { } diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp index e189a85c7..9fdca45e7 100644 --- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp +++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp @@ -42,9 +42,10 @@ namespace armarx::aron::type Tuple::Tuple(const type::dto::Tuple& o, const Path& path) : detail::ContainerVariant<type::dto::Tuple, Tuple>(o, type::Descriptor::eTuple, path) { + unsigned int i = 0; for (const auto& t : o.elementTypes) { - acceptedTypes.push_back(FromAronDTO(*t)); + acceptedTypes.push_back(FromAronDTO(*t, path.withAcceptedTypeIndex(i++))); } } diff --git a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp index ae5b60e7f..241a1ec27 100644 --- a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp +++ b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp @@ -45,6 +45,154 @@ namespace armarx::aron::type return GetDescriptor(n); } + void ConstVariantVisitor::visitObject(Input& i) + { + auto aron = type::Object::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitDict(Input& i) + { + auto aron = type::Dict::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitPair(Input& i) + { + auto aron = type::Pair::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitTuple(Input& i) + { + auto aron = type::Tuple::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitList(Input& i) + { + auto aron = type::List::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitMatrix(Input& i) + { + auto aron = type::Matrix::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitNDArray(Input& i) + { + auto aron = type::NDArray::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitOrientation(Input& i) + { + auto aron = type::Orientation::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitPosition(Input& i) + { + auto aron = type::Position::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitPose(Input& i) + { + auto aron = type::Pose::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitQuaternion(Input & i) + { + auto aron = type::Quaternion::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitImage(Input& i) + { + auto aron = type::Image::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitPointCloud(Input& i) + { + auto aron = type::PointCloud::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitIntEnum(Input& i) + { + auto aron = type::IntEnum::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitInt(Input& i) + { + auto aron = type::Int::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitLong(Input& i) + { + auto aron = type::Long::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitFloat(Input& i) + { + auto aron = type::Float::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitDouble(Input& i) + { + auto aron = type::Double::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitBool(Input& i) + { + auto aron = type::Bool::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitString(Input& i) + { + auto aron = type::String::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitTime(Input& i) + { + auto aron = type::Time::DynamicCastAndCheck(i); + visitAronVariant(aron); + } + + void ConstVariantVisitor::visitAronVariant(const type::ObjectPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::DictPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::PairPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::TuplePtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::ListPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::NDArrayPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::MatrixPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::QuaternionPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::PositionPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::OrientationPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::PosePtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::ImagePtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::PointCloudPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::IntEnumPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::IntPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::LongPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::FloatPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::DoublePtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::BoolPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::StringPtr&) {} + void ConstVariantVisitor::visitAronVariant(const type::TimePtr&) {} + /**************************************************************************** * RecursiveVariantVisitor ***************************************************************************/ diff --git a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h index 4f08dca8f..355b3fee2 100644 --- a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h +++ b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h @@ -40,6 +40,53 @@ namespace armarx::aron::type static type::Descriptor GetDescriptor(Input& n); type::Descriptor getDescriptor(Input& n) override; virtual ~ConstVariantVisitor() = default; + + // Already implemented so that they cast the input and call specilized method below + // Override if you do not want to use the specialized methods + void visitObject(Input&) override; + void visitDict(Input&) override; + void visitPair(Input&) override; + void visitTuple(Input&) override; + void visitList(Input&) override; + void visitMatrix(Input&) override; + void visitNDArray(Input&) override; + void visitQuaternion(Input&) override; + void visitOrientation(Input&) override; + void visitPosition(Input&) override; + void visitPose(Input&) override; + void visitImage(Input&) override; + void visitPointCloud(Input&) override; + void visitIntEnum(Input&) override; + void visitInt(Input&) override; + void visitLong(Input&) override; + void visitFloat(Input&) override; + void visitDouble(Input&) override; + void visitBool(Input&) override; + void visitString(Input&) override; + void visitTime(Input&) override; + + // Use these if you do not want to cast manually + virtual void visitAronVariant(const type::ObjectPtr&); + virtual void visitAronVariant(const type::DictPtr&); + virtual void visitAronVariant(const type::ListPtr&); + virtual void visitAronVariant(const type::PairPtr&); + virtual void visitAronVariant(const type::TuplePtr&); + virtual void visitAronVariant(const type::MatrixPtr&); + virtual void visitAronVariant(const type::NDArrayPtr&); + virtual void visitAronVariant(const type::QuaternionPtr&); + virtual void visitAronVariant(const type::OrientationPtr&); + virtual void visitAronVariant(const type::PositionPtr&); + virtual void visitAronVariant(const type::PosePtr&); + virtual void visitAronVariant(const type::PointCloudPtr&); + virtual void visitAronVariant(const type::ImagePtr&); + virtual void visitAronVariant(const type::IntEnumPtr&); + virtual void visitAronVariant(const type::IntPtr&); + virtual void visitAronVariant(const type::LongPtr&); + virtual void visitAronVariant(const type::TimePtr&); + virtual void visitAronVariant(const type::FloatPtr&); + virtual void visitAronVariant(const type::DoublePtr&); + virtual void visitAronVariant(const type::BoolPtr&); + virtual void visitAronVariant(const type::StringPtr&); }; /** -- GitLab