From 2a819538e63c3ea865f305377792fc9fdede36e7 Mon Sep 17 00:00:00 2001 From: Fabian Peller <fabian.peller-konrad@kit.edu> Date: Fri, 16 Jun 2023 09:05:38 +0200 Subject: [PATCH] skill updates for profiles and for being able to simlatenously execute skills --- .../server/SkillsMemory/SkillsMemory.cpp | 83 ++-- .../armem/server/SkillsMemory/SkillsMemory.h | 42 +- .../SkillManagerMonitorWidget.ui | 177 +++++---- .../SkillManagerMonitorWidgetController.cpp | 202 +++++----- .../SkillManagerMonitorWidgetController.h | 5 +- .../skills/SkillManagerInterface.ice | 67 +++- .../interface/skills/SkillMemoryInterface.ice | 9 +- .../skills/SkillProviderInterface.ice | 38 +- .../server/segment/SkillEventSegment.cpp | 53 +-- .../server/segment/SkillEventSegment.h | 11 +- .../manager/SkillManagerComponentPlugin.cpp | 255 ++++++++----- .../manager/SkillManagerComponentPlugin.h | 36 +- .../libraries/skills/provider/SkillID.cpp | 49 ++- .../libraries/skills/provider/SkillID.h | 13 +- .../skills/provider/SkillParameterization.cpp | 6 +- .../skills/provider/SkillParameterization.h | 10 +- .../provider/SkillProviderComponentPlugin.cpp | 71 ++-- .../provider/SkillProviderComponentPlugin.h | 15 +- .../libraries/skills/provider/SkillProxy.h | 3 - .../skills/provider/SkillStatusUpdate.cpp | 361 ++++++++++++++---- .../skills/provider/SkillStatusUpdate.h | 134 ++++++- .../detail/SkillImplementationWrapper.cpp | 220 +++++++---- .../detail/SkillImplementationWrapper.h | 26 +- 23 files changed, 1251 insertions(+), 635 deletions(-) diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp index 75882cf47..7ebd7960d 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp @@ -27,19 +27,19 @@ #include <ArmarXCore/core/ArmarXManager.h> #include <ArmarXCore/core/ArmarXObjectScheduler.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include <ArmarXCore/core/time/TimeUtil.h> #include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/time/TimeUtil.h> #include <RobotAPI/libraries/armem/core/error.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem_skills/aron_conversions.h> -#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> namespace armarx { - SkillsMemory::SkillsMemory(): + SkillsMemory::SkillsMemory() : ReadWritePluginUser(), StatechartListenerComponentPluginUser(), SkillManagerComponentPluginUser(), @@ -50,10 +50,11 @@ namespace armarx { } - - armarx::PropertyDefinitionsPtr SkillsMemory::createPropertyDefinitions() + armarx::PropertyDefinitionsPtr + SkillsMemory::createPropertyDefinitions() { - armarx::PropertyDefinitionsPtr defs = new ComponentPropertyDefinitions(getConfigIdentifier()); + armarx::PropertyDefinitionsPtr defs = + new ComponentPropertyDefinitions(getConfigIdentifier()); const std::string prefix = "mem."; statechartListenerProviderSegment.defineProperties(defs, prefix + "statechartlistener."); @@ -64,14 +65,14 @@ namespace armarx return defs; } - - std::string SkillsMemory::getDefaultName() const + std::string + SkillsMemory::getDefaultName() const { return "SkillMemory"; } - - void SkillsMemory::onInitComponent() + void + SkillsMemory::onInitComponent() { statechartListenerProviderSegment.init(); executableSkillCoreSegment.init(); @@ -79,24 +80,23 @@ namespace armarx skillEventCoreSegment.init(); } - - void SkillsMemory::onConnectComponent() + void + SkillsMemory::onConnectComponent() { } - - void SkillsMemory::onDisconnectComponent() + void + SkillsMemory::onDisconnectComponent() { - } - - void SkillsMemory::onExitComponent() + void + SkillsMemory::onExitComponent() { } - - armem::data::CommitResult SkillsMemory::commit(const armem::data::Commit& commit, const Ice::Current& current) + armem::data::CommitResult + SkillsMemory::commit(const armem::data::Commit& commit, const Ice::Current& current) { // 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 @@ -107,13 +107,15 @@ namespace armarx for (const auto& up : commit.updates) { - if (up.entityID.coreSegmentName == skills::segment::SkillExecutionRequestCoreSegment::CoreSegmentName) + if (up.entityID.coreSegmentName == + skills::segment::SkillExecutionRequestCoreSegment::CoreSegmentName) { for (const auto& instance : up.instancesData) { ARMARX_CHECK_NOT_NULL(instance); - skills::manager::dto::SkillExecutionRequest exInfo = skillExecutionRequestCoreSegment.convertCommit(instance); + skills::manager::dto::SkillExecutionRequest exInfo = + skillExecutionRequestCoreSegment.convertCommit(instance); SkillManagerComponentPluginUser::executeSkill(exInfo, current); } } @@ -122,7 +124,9 @@ namespace armarx return result; } - void SkillsMemory::addProvider(const skills::manager::dto::ProviderInfo& info, const Ice::Current ¤t) + void + SkillsMemory::addProvider(const skills::manager::dto::ProviderInfo& info, + const Ice::Current& current) { SkillManagerComponentPluginUser::addProvider(info, current); @@ -130,7 +134,8 @@ namespace armarx executableSkillCoreSegment.addSkillProvider(info); } - void SkillsMemory::removeProvider(const std::string& skillProviderName, const Ice::Current ¤t) + void + SkillsMemory::removeProvider(const std::string& skillProviderName, const Ice::Current& current) { executableSkillCoreSegment.removeSkillProvider(skillProviderName); @@ -138,36 +143,52 @@ namespace armarx SkillManagerComponentPluginUser::removeProvider(skillProviderName, current); } - skills::provider::dto::SkillStatusUpdate SkillsMemory::executeSkill(const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current ¤t) + skills::manager::dto::SkillStatusUpdate + SkillsMemory::executeSkill(const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current& current) { skills::manager::dto::SkillExecutionRequest requestCopy = info; if (requestCopy.skillId.providerName == "*") { // sanitize the provider name if set to 'any' - requestCopy.skillId.providerName = getFirstProviderNameThatHasSkill(requestCopy.skillId.skillName); + requestCopy.skillId.providerName = + getFirstProviderNameThatHasSkill(requestCopy.skillId.skillName); } skillExecutionRequestCoreSegment.addSkillExecutionRequest(requestCopy); return SkillManagerComponentPluginUser::executeSkill(requestCopy, current); } - void SkillsMemory::updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, const Ice::Current ¤t) + void + SkillsMemory::updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, + const std::string& providerName, + const Ice::Current& current) { - skillEventCoreSegment.addSkillUpdateEvent(update); + skillEventCoreSegment.addSkillUpdateEvent(update, providerName); } - + skills::provider::dto::SkillStatusUpdateList + SkillsMemory::getLatestSkillExecutionStatuses(int n, const Ice::Current& current) + { + return {}; + } /* * Statechart stuff */ - void SkillsMemory::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& x, const Ice::Current&) + void + SkillsMemory::reportStatechartTransitionWithParameters( + const ProfilerStatechartTransitionWithParameters& x, + const Ice::Current&) { statechartListenerProviderSegment.reportStatechartTransitionWithParameters(x); } - void SkillsMemory::reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList& x, const Ice::Current&) + void + SkillsMemory::reportStatechartTransitionWithParametersList( + const ProfilerStatechartTransitionWithParametersList& x, + const Ice::Current&) { statechartListenerProviderSegment.reportStatechartTransitionWithParametersList(x); } -} +} // namespace armarx diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h index 91506c16f..d0b92b485 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h @@ -30,16 +30,14 @@ #include <ArmarXCore/observers/ObserverObjectFactories.h> #include <RobotAPI/interface/skills/SkillMemoryInterface.h> - -#include <RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h> -#include <RobotAPI/libraries/armem_skills/server/StatechartListenerComponentPlugin.h> #include <RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h> - #include <RobotAPI/libraries/armem_skills/aron/Statechart.aron.generated.h> -#include <RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.h> +#include <RobotAPI/libraries/armem_skills/server/StatechartListenerComponentPlugin.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> +#include <RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.h> +#include <RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.h> +#include <RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h> namespace armarx { @@ -63,27 +61,37 @@ namespace armarx virtual public SkillManagerComponentPluginUser { public: - SkillsMemory(); /// @see armarx::ManagedIceObject::getDefaultName() std::string getDefaultName() const override; // Override StatechartListener - void reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters&, const Ice::Current&) override; - void reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList&, const Ice::Current&) override; + void + reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters&, + const Ice::Current&) override; + void reportStatechartTransitionWithParametersList( + const ProfilerStatechartTransitionWithParametersList&, + const Ice::Current&) override; // Override SkillManager to add memory functions - void addProvider(const skills::manager::dto::ProviderInfo& info, const Ice::Current ¤t) override; - void removeProvider(const std::string&, const Ice::Current ¤t) override; - skills::provider::dto::SkillStatusUpdate executeSkill(const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current ¤t) override; - void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& statusUpdate, const Ice::Current ¤t) override; + void addProvider(const skills::manager::dto::ProviderInfo& info, + const Ice::Current& current) override; + void removeProvider(const std::string&, const Ice::Current& current) override; + skills::manager::dto::SkillStatusUpdate + executeSkill(const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current& current) override; + void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& statusUpdate, + const std::string& providerName, + const Ice::Current& current) override; + skills::provider::dto::SkillStatusUpdateList + getLatestSkillExecutionStatuses(int n, const Ice::Current& current) override; // WritingInterface interface - armem::data::CommitResult commit(const armem::data::Commit& commit, const Ice::Current&) override; + armem::data::CommitResult commit(const armem::data::Commit& commit, + const Ice::Current&) override; protected: - /// @see armarx::ManagedIceObject::onInitComponent() void onInitComponent() override; @@ -101,12 +109,12 @@ namespace armarx private: - static constexpr const char* MemoryName = "Skill"; struct Properties { }; + Properties p; skills::segment::StatechartListenerProviderSegment statechartListenerProviderSegment; @@ -114,4 +122,4 @@ namespace armarx skills::segment::SkillEventCoreSegment skillEventCoreSegment; skills::segment::SkillExecutionRequestCoreSegment skillExecutionRequestCoreSegment; }; -} +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui index 7c25a1b84..70005fd88 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui @@ -20,8 +20,38 @@ <string>SkillManagerMonitorWidget</string> </property> <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> + <item row="3" column="0"> + <widget class="QCheckBox" name="autoUpdateCheckBox"> + <property name="text"> + <string>Auto Update</string> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="QPushButton" name="refreshNowPushButton"> + <property name="text"> + <string>Refresh Now</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Update Frequency:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="4" column="0" colspan="4"> <widget class="QSplitter" name="splitter_2"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -34,25 +64,49 @@ <property name="childrenCollapsible"> <bool>false</bool> </property> - <widget class="QGroupBox" name="groupBoxActiveSkills"> + <widget class="QGroupBox" name="groupBoxSkillExecutions"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="title"> - <string>Active Skills</string> + <string>Executions</string> </property> <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="0"> - <widget class="QListWidget" name="listWidgetActiveSkills"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <item row="1" column="0" colspan="3"> + <widget class="QTreeWidget" name="treeWidget"> + <column> + <property name="text"> + <string>ID</string> + </property> + </column> + <column> + <property name="text"> + <string>Skill</string> + </property> + </column> + <column> + <property name="text"> + <string>Scheduled</string> + </property> + </column> + <column> + <property name="text"> + <string>Started</string> + </property> + </column> + <column> + <property name="text"> + <string>Finished</string> + </property> + </column> + <column> + <property name="text"> + <string>Executor</string> + </property> + </column> </widget> </item> </layout> @@ -78,16 +132,6 @@ <string>Manager</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="3" column="1"> - <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Update Frequency:</string> - </property> - </widget> - </item> <item row="4" column="0" colspan="3"> <widget class="QTreeWidget" name="treeWidgetSkills"> <column> @@ -100,30 +144,14 @@ <string>HasType</string> </property> </column> - <column> - <property name="text"> - <string>State</string> - </property> - </column> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="autoUpdateCheckBox"> - <property name="text"> - <string>Auto Update</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QPushButton" name="refreshNowPushButton"> - <property name="text"> - <string>Refresh Now</string> - </property> </widget> </item> </layout> </widget> <widget class="QGroupBox" name="groupBoxSkillDetails"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -134,7 +162,35 @@ <string>Skill Details</string> </property> <layout class="QGridLayout" name="gridLayout_2"> - <item row="1" column="0" colspan="4"> + <item row="8" column="3"> + <widget class="QPushButton" name="pushButtonExecuteSkill"> + <property name="text"> + <string>Request Execution</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QPushButton" name="pushButtonPaste"> + <property name="text"> + <string>Set args from clipboard</string> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QPushButton" name="pushButtonStopSkill"> + <property name="text"> + <string>Stop current skill</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QPushButton" name="pushButtonReset"> + <property name="text"> + <string>Reset args</string> + </property> + </widget> + </item> + <item row="3" column="0" colspan="4"> <widget class="QTreeWidget" name="treeWidgetSkillDetails"> <property name="contextMenuPolicy"> <enum>Qt::CustomContextMenu</enum> @@ -164,34 +220,6 @@ </column> </widget> </item> - <item row="6" column="3"> - <widget class="QPushButton" name="pushButtonExecuteSkill"> - <property name="text"> - <string>Request Execution</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButtonPaste"> - <property name="text"> - <string>Set from clipboard</string> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QPushButton" name="pushButtonStopSkill"> - <property name="text"> - <string>Stop current skill</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QPushButton" name="pushButtonReset"> - <property name="text"> - <string>Reset args</string> - </property> - </widget> - </item> <item row="0" column="1"> <widget class="QPushButton" name="pushButtonCopy"> <property name="text"> @@ -199,6 +227,15 @@ </property> </widget> </item> + <item row="1" column="1" colspan="3"> + <widget class="QComboBox" name="profileComboBox"> + <item> + <property name="text"> + <string><No Profile></string> + </property> + </item> + </widget> + </item> </layout> </widget> </widget> diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp index c3dcb38aa..70fdd6812 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -82,14 +82,15 @@ namespace armarx { widget.setupUi(getWidget()); - widget.doubleSpinBoxUpdateFreq->setValue(5.0); - widget.doubleSpinBoxUpdateFreq->setMinimum(0); - widget.doubleSpinBoxUpdateFreq->setMaximum(100); + double default_hz = 2; + widget.doubleSpinBoxUpdateFreq->setValue(default_hz); + widget.doubleSpinBoxUpdateFreq->setMinimum(0.5); + widget.doubleSpinBoxUpdateFreq->setMaximum(20); widget.doubleSpinBoxUpdateFreq->setSingleStep(0.5); widget.doubleSpinBoxUpdateFreq->setSuffix(" Hz"); refreshSkillsResultTimer = new QTimer(this); - refreshSkillsResultTimer->setInterval(1000 / 2); // Keep this stable. + updateTimerFrequency(); refreshSkillsResultTimer->start(); connect(widget.doubleSpinBoxUpdateFreq, @@ -99,7 +100,7 @@ namespace armarx connect(refreshSkillsResultTimer, &QTimer::timeout, this, - &SkillManagerMonitorWidgetController::refreshSkillsPeriodically); + &SkillManagerMonitorWidgetController::refreshSkillsAndExecutions); connect(widget.pushButtonCopy, &QPushButton::clicked, @@ -175,28 +176,21 @@ namespace armarx } void - SkillManagerMonitorWidgetController::refreshSkillsPeriodically() + SkillManagerMonitorWidgetController::refreshSkillsAndExecutions() { if (widget.autoUpdateCheckBox->isChecked()) { refreshSkills(); + refreshExecutions(); } } void SkillManagerMonitorWidgetController::refreshSkills() { - static std::map<skills::provider::dto::Execution::Status, std::string> - ExecutionStatus2String = { - {skills::provider::dto::Execution::Status::Aborted, "Aborted"}, - {skills::provider::dto::Execution::Status::Failed, "Failed"}, - {skills::provider::dto::Execution::Status::Idle, "Not yet started"}, - {skills::provider::dto::Execution::Status::Running, "Running"}, - {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}, - {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}}; - if (!manager) { + // check if null return; } @@ -204,9 +198,10 @@ namespace armarx // remove non-existing ones try { - ARMARX_DEBUG << "GET REMOVED PROVIDERS AND REMOVE FROM MAP"; - std::scoped_lock l(skillMutex); + std::scoped_lock l(updateMutex); + auto managerSkills = manager->getSkillDescriptions(); + std::vector<std::string> removedProviders; for (auto it = skills.begin(); it != skills.end();) { @@ -225,21 +220,18 @@ namespace armarx } // add new ones - ARMARX_DEBUG << "GET NEW PROVIDERS AND ADD THEM TO MAP"; std::vector<std::string> newProviders; for (const auto& [providerName, providerSkills] : managerSkills) { if (skills.find(providerName) == skills.end()) { - ARMARX_DEBUG << "ADD " << providerName; skills.insert(std::make_pair(providerName, providerSkills)); newProviders.push_back(providerName); } } - /* CHECK TREE VIEW */ + /* UPDATE TREE VIEW */ // remove providers from tree - ARMARX_DEBUG << "REMOVE PROVIDERS FROM TREE VIEW"; int i = 0; while (i < widget.treeWidgetSkills->topLevelItemCount()) { @@ -249,7 +241,6 @@ namespace armarx item->text(0).toStdString()); it != removedProviders.end()) { - ARMARX_DEBUG << "REMOVE PROVIDER " << *it; delete widget.treeWidgetSkills->takeTopLevelItem(i); } else @@ -259,7 +250,6 @@ namespace armarx } // add new providers - ARMARX_DEBUG << "ADD NEW PROVIDERS TO TREE VIEW"; for (const auto& [providerName, providerSkills] : skills) { if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); @@ -269,87 +259,105 @@ namespace armarx item->setText(0, QString::fromStdString(providerName)); for (const auto& [name, sk] : providerSkills) { - ARMARX_DEBUG << "ADD PROVIDER " << *it; auto itsk = new QTreeWidgetItem(item); item->addChild(itsk); itsk->setText(0, QString::fromStdString(name)); } } } + } + catch (...) + { + // perhaps the manager died during the method? + } + } - // update status and active skills window - ARMARX_DEBUG << "UPDATE STATI AND ACTIVE SKILL"; - std::map<skills::SkillID, std::string> activeSkillsAndPrefixes; - auto managerStatuses = manager->getSkillExecutionStatuses(); - for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i) - { - try - { - QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); - auto providerName = item->text(0).toStdString(); - - ARMARX_DEBUG << "UPDATE STATI FOR PROVIDER " << providerName; - auto allStatusesForProvider = managerStatuses.at(providerName); - - for (int j = 0; j < item->childCount(); ++j) - { - QTreeWidgetItem* skillItem = item->child(j); - skills::SkillID currentSkillId(providerName, - skillItem->text(0).toStdString()); - - ARMARX_DEBUG << "UPDATE STATI FOR SKILL " << currentSkillId.skillName; - auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName); - skillItem->setText(2, - QString::fromStdString(ExecutionStatus2String.at( - statusForSkill.header.status))); - - if (not statusForSkill.header.executorName - .empty()) // it means that the skill was called by someone - { - ARMARX_DEBUG << "ADD SKILL TO ACTIVE " << currentSkillId.skillName; - activeSkillsAndPrefixes.insert( - {currentSkillId, statusForSkill.header.executorName}); - } - } - } - catch (...) - { - // Perhaps the skill provider died after the check at the beginning of this method - continue; - } - } + void + SkillManagerMonitorWidgetController::refreshExecutions() + { + static std::map<skills::provider::dto::Execution::Status, std::string> + ExecutionStatus2String = { + // Terminating + {skills::provider::dto::Execution::Status::Aborted, "Aborted"}, + {skills::provider::dto::Execution::Status::Failed, "Failed"}, + {skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}, - // finally update the view of active skills - ARMARX_DEBUG << "UPDATE ACTIVE SKILLS"; - widget.listWidgetActiveSkills->clear(); - for (const auto& [id, prefix] : activeSkillsAndPrefixes) - { - auto prefixedStr = id.toString(prefix); - bool longest = true; - for ( - const auto& [id2, prefix2] : - activeSkillsAndPrefixes) // check if there is a deeper skill currently executing - { - auto prefixedStr2 = id.toString(prefix2); - if (prefixedStr == prefixedStr2) - { - continue; - } + // Others + {skills::provider::dto::Execution::Status::Idle, "Not yet started"}, + {skills::provider::dto::Execution::Status::Running, "Running"}, + {skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}}; - if (simox::alg::starts_with(prefixedStr2, prefixedStr)) - { - longest = false; - break; - } - } + if (!manager) + { + // check if null + return; + } - if (longest) - { - widget.listWidgetActiveSkills->addItem( - QString::fromStdString(id.toString() + ": " + id.toString(prefix))); - } - } + try + { + // std::scoped_lock l(updateMutex); + + // auto managerStatuses = manager->getSkillExecutionStatuses(); + + // // update status and active skills window + // std::map<skills::SkillID, std::string> activeSkillsAndPrefixes; + // for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i) + // { + // QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); + // auto providerName = item->text(0).toStdString(); + + + // auto allStatusesForProvider = managerStatuses.at(providerName); + + // for (int j = 0; j < item->childCount(); ++j) + // { + // QTreeWidgetItem* skillItem = item->child(j); + // skills::SkillID currentSkillId(providerName, skillItem->text(0).toStdString()); + + // auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName); + // skillItem->setText(2, + // QString::fromStdString(ExecutionStatus2String.at( + // statusForSkill.header.status))); + + // if (not statusForSkill.header.executorName + // .empty()) // it means that the skill was called by someone + // { + // activeSkillsAndPrefixes.insert( + // {currentSkillId, statusForSkill.header.executorName}); + // } + // } + // } + + // widget.listWidgetActiveSkills->clear(); + // for (const auto& [id, prefix] : activeSkillsAndPrefixes) + // { + // auto prefixedStr = id.toString(prefix); + // bool longest = true; + // for ( + // const auto& [id2, prefix2] : + // activeSkillsAndPrefixes) // check if there is a deeper skill currently executing + // { + // auto prefixedStr2 = id.toString(prefix2); + // if (prefixedStr == prefixedStr2) + // { + // continue; + // } + + // if (simox::alg::starts_with(prefixedStr2, prefixedStr)) + // { + // longest = false; + // break; + // } + // } + + // if (longest) + // { + // widget.listWidgetActiveSkills->addItem( + // QString::fromStdString(id.toString() + ": " + id.toString(prefix))); + // } + // } } + catch (...) { // perhaps the manager died during the method? @@ -364,7 +372,7 @@ namespace armarx return; } - std::scoped_lock l(skillMutex); + std::scoped_lock l(updateMutex); const auto& skillDescriptions = skills.at(selectedSkill.providerName); if (!skillDescriptions.count(selectedSkill.skillName)) { @@ -391,7 +399,7 @@ namespace armarx void SkillManagerMonitorWidgetController::stopSkill() { - std::scoped_lock l(skillMutex); + std::scoped_lock l(updateMutex); if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) { return; @@ -412,7 +420,7 @@ namespace armarx SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*) { - std::scoped_lock l(skillMutex); + std::scoped_lock l(updateMutex); widget.groupBoxSkillDetails->setEnabled(false); if (!current) @@ -487,7 +495,7 @@ namespace armarx {QString::fromStdString("Arguments")}); auto aron_args = aron::type::Object::FromAronObjectDTO(skillDesc.acceptedType); auto default_args = - nullptr; //aron::data::Dict::FromAronDictDTO(skillDesc.defaultParams); TODO! + nullptr; //aron::data::Dict::FromAronDictDTO(skillDesc.defaultParams); TODO! fabian.peller aronTreeWidgetController = std::make_shared<AronTreeWidgetController>( widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args); diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h index f1ad1bb72..d6e93d978 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -81,7 +81,8 @@ namespace armarx void updateTimerFrequency(); void refreshSkills(); - void refreshSkillsPeriodically(); + void refreshExecutions(); + void refreshSkillsAndExecutions(); void copyCurrentConfig(); void pasteCurrentConfig(); @@ -108,7 +109,7 @@ namespace armarx }; // Data taken from observer (snapshot of it) - mutable std::mutex skillMutex; + mutable std::mutex updateMutex; skills::manager::dto::SkillDescriptionMapMap skills = {}; // User Input diff --git a/source/RobotAPI/interface/skills/SkillManagerInterface.ice b/source/RobotAPI/interface/skills/SkillManagerInterface.ice index 088d28561..17a07d8bc 100644 --- a/source/RobotAPI/interface/skills/SkillManagerInterface.ice +++ b/source/RobotAPI/interface/skills/SkillManagerInterface.ice @@ -32,13 +32,52 @@ module armarx { module dto { - // Inputs + // A skill ID. Must be unique within one SkillManager + struct SkillID + { + string providerName; + string skillName; + }; + + // The minimum information that is needed to uniquely identifying a past skill execution + struct SkillExecutionID + { + SkillID skillId; // the id of the skill + string + executorName; // the name of the component/lib/skill that called the execution of the skill + armarx::core::time::dto::DateTime + executionStartedTime; // The time a skill was triggered + }; + + // Status updates of a skill (similar to the status update of the providers except the skillID) + struct SkillStatusUpdateHeader + { + SkillExecutionID executionId; + aron::data::dto::Dict usedParams; // the used parameterization + callback::dti::SkillProviderCallbackInterface* + usedCallbackInterface; // the used callback interface. Probably a prx to the manager + provider::dto::Execution::Status status; // the current status of the skill + }; + + // (similar to the status update of the providers except the skillID) + struct SkillStatusUpdate + { + SkillStatusUpdateHeader header; + aron::data::dto::Dict + data; // data, attached to the status update. If send via a callback, this data may be used by the callback interface + }; + + sequence<SkillStatusUpdate> SkillStatusUpdateList; + struct SkillExecutionRequest { + SkillID + skillId; // The id of a skill to request. Note that the skill or provider name can be regexes. string executorName; // Who called the request - provider::dto::SkillID skillId; // The id of a skill to request. Note that the skill or provider name can be regexes. - aron::data::dto::Dict params; // the parameters for the skill. Can be nullptr if the skill does not require parameters + aron::data::dto::Dict + params; // the parameters for the skill. Can be nullptr if the skill does not require parameters }; + struct ProviderInfo { string providerName; @@ -48,24 +87,32 @@ module armarx // Provider data types dictionary<string, provider::dto::SkillDescriptionMap> SkillDescriptionMapMap; - dictionary<string, provider::dto::SkillStatusUpdateMap> SkillStatusUpdateMapMap; } module dti { - interface SkillManagerInterface extends callback::dti::SkillProviderCallbackInterface + interface SkillManagerInterface extends + callback::dti::SkillProviderCallbackInterface { - // There is by design no method to get the ProviderInfo. You should only communicate with the manager + // !! There is by design no method to get the ProviderInfo. You should only communicate with the manager !! void addProvider(dto::ProviderInfo providerInfo); + void removeProvider(string providerName); - dto::SkillDescriptionMapMap getSkillDescriptions(); - dto::SkillStatusUpdateMapMap getSkillExecutionStatuses(); + dto::SkillDescriptionMapMap + getSkillDescriptions(); // get all skilldescriptions from all providers - provider::dto::SkillStatusUpdate executeSkill(dto::SkillExecutionRequest skillExecutionInfo); - void abortSkill(string providerName, string skillName); + dto::SkillStatusUpdate + getSkillExecutionStatus(dto::SkillExecutionID executionId); + + dto::SkillStatusUpdateList + getSkillExecutionStatuses(); // returns the current executions from all providers + dto::SkillStatusUpdate + executeSkill(dto::SkillExecutionRequest skillExecutionInfo); + + void abortSkill(string providerName, string skillName); }; } } diff --git a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice index c8e3212ef..09e5db871 100644 --- a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice +++ b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice @@ -24,10 +24,10 @@ #include <ArmarXCore/interface/core/Profiler.ice> -#include <RobotAPI/interface/skills/SkillProviderInterface.ice> +#include <RobotAPI/interface/armem/server/MemoryInterface.ice> #include <RobotAPI/interface/skills/SkillManagerInterface.ice> +#include <RobotAPI/interface/skills/SkillProviderInterface.ice> #include <RobotAPI/interface/skills/StatechartListenerInterface.ice> -#include <RobotAPI/interface/armem/server/MemoryInterface.ice> module armarx { @@ -35,8 +35,11 @@ module armarx { module dti { - interface SkillMemoryInterface extends armem::server::MemoryInterface, dti::StatechartListenerInterface, manager::dti::SkillManagerInterface + interface SkillMemoryInterface extends armem::server::MemoryInterface, + dti::StatechartListenerInterface, manager::dti::SkillManagerInterface { + provider::dto::SkillStatusUpdateList getLatestSkillExecutionStatuses( + int n); // returns latest n statusupdates of all providers }; } } diff --git a/source/RobotAPI/interface/skills/SkillProviderInterface.ice b/source/RobotAPI/interface/skills/SkillProviderInterface.ice index b7aad029e..300054875 100644 --- a/source/RobotAPI/interface/skills/SkillProviderInterface.ice +++ b/source/RobotAPI/interface/skills/SkillProviderInterface.ice @@ -22,6 +22,8 @@ #pragma once +#include <ArmarXCore/interface/core/time.ice> + #include <RobotAPI/interface/aron.ice> @@ -51,13 +53,6 @@ module armarx { sequence<string> StringList; - // A skill ID. Must be unique within one SkillManager - struct SkillID - { - string providerName; - string skillName; - }; - // A parameterization profile struct SkillProfile { @@ -100,23 +95,31 @@ module armarx { enum Status { - Idle, // a skill can only be idled if it has never been scheduled + Idle, Scheduled, Running, - // terminating values + // terminating values, after execution a skill goes back to idle Failed, Succeeded, Aborted }; } - // Status updates of a skill - struct SkillStatusUpdateHeader + // The minimum information that is needed to uniquely identifying a past skill execution + struct SkillExecutionID { - SkillID skillId; // the id of the skill + string skillName; // the name of the skill string executorName; // the name of the component/lib/skill that called the execution of the skill + armarx::core::time::dto::DateTime + executionStartedTime; // The time a skill was triggered + }; + + // Status updates of a skill + struct SkillStatusUpdateHeader + { + SkillExecutionID executionId; aron::data::dto::Dict usedParams; // the used parameterization callback::dti::SkillProviderCallbackInterface* usedCallbackInterface; // the used callback interface. Probably a prx to the manager @@ -130,7 +133,7 @@ module armarx data; // data, attached to the status update. If send via a callback, this data may be used by the callback interface }; - dictionary<string, SkillStatusUpdate> SkillStatusUpdateMap; + sequence<SkillStatusUpdate> SkillStatusUpdateList; } module dti @@ -139,8 +142,10 @@ module armarx { dto::SkillDescription getSkillDescription(string name); dto::SkillDescriptionMap getSkillDescriptions(); - dto::SkillStatusUpdate getSkillExecutionStatus(string name); - dto::SkillStatusUpdateMap getSkillExecutionStatuses(); + dto::SkillStatusUpdate + getSkillExecutionStatus(dto::SkillExecutionID executionId); + dto::SkillStatusUpdateList + getSkillExecutionStatuses(); // returns all current skill executions chronologically // execute skill will ALWAYS fully execute the skill and wait, until the skill is finished. // Use the _begin() method, if you want to call a skill async @@ -167,7 +172,8 @@ module armarx interface SkillProviderCallbackInterface { // used for callbacks from providers to update their skill execution status - void updateStatusForSkill(provider::dto::SkillStatusUpdate statusUpdate); + void updateStatusForSkill(provider::dto::SkillStatusUpdate statusUpdate, + string providerName); } } } diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp index 1fa0989e8..8eb81c164 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp @@ -1,49 +1,58 @@ #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/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h> +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> +#include <RobotAPI/libraries/skills/provider/SkillStatusUpdate.h> namespace armarx::skills::segment { - SkillEventCoreSegment::SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory): - Base(iceMemory, CoreSegmentName, armarx::skills::arondto::SkillExecutionRequest::ToAronType()) + SkillEventCoreSegment::SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory) : + Base(iceMemory, + CoreSegmentName, + armarx::skills::arondto::SkillExecutionRequest::ToAronType()) { } - void SkillEventCoreSegment::defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix) + void + SkillEventCoreSegment::defineProperties(PropertyDefinitionsPtr defs, const std::string& prefix) { // No properties! (meaning no name and no max size) } - void SkillEventCoreSegment::init() + void + SkillEventCoreSegment::init() { Base::init(); } - void SkillEventCoreSegment::addSkillUpdateEvent(const skills::provider::dto::SkillStatusUpdate& update) + void + SkillEventCoreSegment::addSkillUpdateEvent( + const skills::provider::dto::SkillStatusUpdate& update, + const std::string& providerName) { // add update for skill to memory - static std::map<armarx::skills::provider::dto::Execution::Status, std::string> ExecutionStatus2String = { - {armarx::skills::provider::dto::Execution::Status::Idle, "Idle"}, - {armarx::skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}, - {armarx::skills::provider::dto::Execution::Status::Running, "Running"}, - {armarx::skills::provider::dto::Execution::Status::Aborted, "Aborted"}, - {armarx::skills::provider::dto::Execution::Status::Failed, "Failed"}, - {armarx::skills::provider::dto::Execution::Status::Succeeded, "Succeeded"} - }; + static std::map<armarx::skills::provider::dto::Execution::Status, std::string> + ExecutionStatus2String = { + {armarx::skills::provider::dto::Execution::Status::Idle, "Idle"}, + {armarx::skills::provider::dto::Execution::Status::Scheduled, "Scheduled"}, + {armarx::skills::provider::dto::Execution::Status::Running, "Running"}, + {armarx::skills::provider::dto::Execution::Status::Aborted, "Aborted"}, + {armarx::skills::provider::dto::Execution::Status::Failed, "Failed"}, + {armarx::skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}}; + + auto up = skills::SkillStatusUpdate::FromIce(update, providerName); // create commit about new update armarx::skills::arondto::SkillExecutionEvent event; - event.providerName = update.header.skillId.providerName; - event.skillName = update.header.skillId.skillName; + event.providerName = up.executionId.skillId.providerName; + event.skillName = up.executionId.skillId.skillName; event.status = ExecutionStatus2String.at(update.header.status); - event.params = aron::data::Dict::FromAronDictDTO(update.header.usedParams); - event.data = aron::data::Dict::FromAronDictDTO(update.data); + event.params = up.usedParameterization.usedInputParams; + event.data = up.data; armem::MemoryID commitId = id(); commitId.providerSegmentName = event.providerName; @@ -55,9 +64,9 @@ namespace armarx::skills::segment auto& entityUpdate = comm.add(); entityUpdate.confidence = 1.0; entityUpdate.referencedTime = armem::Time::Now(); - entityUpdate.instancesData = { aron }; + entityUpdate.instancesData = {aron}; entityUpdate.entityID = commitId; iceMemory.commit(comm); } -} +} // namespace armarx::skills::segment diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h index 93df4bf7a..7d67fc2d6 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h @@ -8,13 +8,11 @@ // ArmarX #include <RobotAPI/interface/skills/SkillManagerInterface.h> #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 + class SkillEventCoreSegment : public armem::server::segment::SpecializedCoreSegment { using Base = armem::server::segment::SpecializedCoreSegment; @@ -23,11 +21,12 @@ namespace armarx::skills::segment SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory); - void defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix); + void defineProperties(PropertyDefinitionsPtr defs, const std::string& prefix); void init(); - void addSkillUpdateEvent(const skills::provider::dto::SkillStatusUpdate& update); + void addSkillUpdateEvent(const skills::provider::dto::SkillStatusUpdate& update, + const std::string& providerName); private: }; -} +} // namespace armarx::skills::segment diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp index 2908d2e77..5fbc2e925 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp @@ -1,8 +1,12 @@ #include "SkillManagerComponentPlugin.h" #include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/time/DateTime.h> +#include <ArmarXCore/core/time/ice_conversions.h> -#include "../error/Exception.h" +#include <RobotAPI/libraries/skills/error/Exception.h> +#include <RobotAPI/libraries/skills/provider/SkillID.h> +#include <RobotAPI/libraries/skills/provider/SkillStatusUpdate.h> namespace armarx::plugins { @@ -68,6 +72,7 @@ namespace armarx std::string SkillManagerComponentPluginUser::getFirstProviderNameThatHasSkill(const std::string& skillName) { + // NON LOCKING! WE ASSERT THAT THE CALLER HOLDS LOCK for (const auto& [providerName, providerPrx] : skillProviderMap) { auto allSkills = providerPrx->getSkillDescriptions(); @@ -85,12 +90,16 @@ namespace armarx using SkillProviderInterfacePrxMap = std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx>; - skills::provider::dto::SkillStatusUpdate + skills::manager::dto::SkillStatusUpdate SkillManagerComponentPluginUser::executeSkill( const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current&) { + std::unique_lock l(skillProviderMapMutex); + std::string providerName = "INVALID PROVIDER NAME"; + + // TODO: Really support regexes! if (info.skillId.providerName == "*") { providerName = getFirstProviderNameThatHasSkill(info.skillId.skillName); @@ -100,68 +109,61 @@ namespace armarx providerName = info.skillId.providerName; } - SkillProviderInterfacePrxMap skillProviderMap; - { - std::scoped_lock l(skillProviderMapMutex); - skillProviderMap = this->skillProviderMap; - } - bool remove = false; if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) { - const auto& n = it->first; - const auto& s = it->second; + const auto& provider = it->second; + + if (!provider) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << providerName << "'. Removing it from skills."; + skillProviderMap.erase(it); + + throw skills::error::SkillException( + __PRETTY_FUNCTION__, + "Skill execution failed. Could not execute a skill of provider '" + + providerName + "' because the provider does not exist."); + } try { - if (s) - { - skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; - getProxy(myPrx, -1); + skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; + getProxy(myPrx, -1); - skills::provider::dto::SkillExecutionRequest exInfo; - exInfo.skillName = info.skillId.skillName; - exInfo.executorName = info.executorName; - exInfo.callbackInterface = myPrx; - exInfo.params = info.params; + skills::provider::dto::SkillExecutionRequest exInfo; + exInfo.skillName = info.skillId.skillName; + exInfo.executorName = info.executorName; + exInfo.callbackInterface = myPrx; + exInfo.params = info.params; - return s->executeSkill(exInfo); - } - else - { - remove = true; - } + auto async = provider->begin_executeSkill(exInfo); + l.unlock(); // allow parallel e.g. stopping + auto up = provider->end_executeSkill(async); + + // convert to manager view + return skills::SkillStatusUpdate::FromIce(up, providerName).toIce(); } catch (...) { - remove = true; - } - + ARMARX_WARNING << __PRETTY_FUNCTION__ + << ": Found disconnected or buggy skill provider '" << providerName + << "' during execution. Removing it from skills."; + skillProviderMap.erase(it); - if (remove) - { - std::scoped_lock l(skillProviderMapMutex); - // No copy! - SkillProviderInterfacePrxMap& skillProviderMap = this->skillProviderMap; - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) - { - ARMARX_WARNING << __PRETTY_FUNCTION__ - << ": Found disconnected or buggy skill provider '" << n - << "' during execution. Removing it from skills."; - it = skillProviderMap.erase(it); - } + throw skills::error::SkillException( + __PRETTY_FUNCTION__, + "Skill execution failed. Could not execute a skill of provider '" + + providerName + "' because the provider does not exist."); } } else { - ARMARX_ERROR << "Could not execute a skill of provider '" + providerName + - "' because the provider does not exist."; throw skills::error::SkillException( __PRETTY_FUNCTION__, "Skill execution failed. Could not execute a skill of provider '" + providerName + "' because the provider does not exist."); } - return {}; // Never happens } void @@ -169,32 +171,30 @@ namespace armarx const std::string& skillName, const Ice::Current& current) { - SkillProviderInterfacePrxMap skillProviderMap; - { - std::scoped_lock l(skillProviderMapMutex); - skillProviderMap = this->skillProviderMap; - } - + std::unique_lock l(skillProviderMapMutex); if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) { - const auto& n = it->first; - const auto& s = it->second; + const auto& providerName = it->first; + const auto& provider = it->second; + + if (!provider) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << providerName << "'. Removing it from skills."; + skillProviderMap.erase(it); + return; + } + try { - if (s) - { - s->abortSkill(skillName); - } - else - { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << n << "'. Removing it from skills on next execute."; - } + auto async = provider->begin_abortSkill(skillName); + l.unlock(); // allow parallel e.g. stopping + return provider->end_abortSkill(async); } catch (...) { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" << n - << "'. Removing it from skills on next execute."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" + << providerName << "'. Removing it from skills on next execute."; } } } @@ -202,9 +202,11 @@ namespace armarx void SkillManagerComponentPluginUser::updateStatusForSkill( const skills::provider::dto::SkillStatusUpdate& statusUpdate, + const std::string& providerName, const Ice::Current&) { (void)statusUpdate; + (void)providerName; // If you want to use the status, implement this method! } @@ -216,62 +218,127 @@ namespace armarx std::scoped_lock l(skillProviderMapMutex); for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) { - const auto& n = it->first; - const auto& s = it->second; + const auto& providerName = it->first; + const auto& provider = it->second; + + if (!provider) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << providerName << "'. Removing it from skills."; + it = skillProviderMap.erase(it); + continue; + } + try { - if (s) - { - skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions(); - ret.insert({n, m}); - ++it; - } - else - { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << n << "'. Removing it from skills."; - it = skillProviderMap.erase(it); - } + skills::provider::dto::SkillDescriptionMap m = provider->getSkillDescriptions(); + ret.insert({providerName, m}); + ++it; } catch (...) { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" << n - << "'. Removing it from skills."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" + << providerName << "'. Removing it from skills."; it = skillProviderMap.erase(it); } } return ret; } - skills::manager::dto::SkillStatusUpdateMapMap + skills::manager::dto::SkillStatusUpdate + SkillManagerComponentPluginUser::getSkillExecutionStatus( + const skills::manager::dto::SkillExecutionID& executionId, + const Ice::Current& current) + { + skills::SkillExecutionId execId = skills::SkillExecutionId::FromIce(executionId); + + std::unique_lock l(skillProviderMapMutex); + if (auto it = skillProviderMap.find(execId.skillId.providerName); + it != skillProviderMap.end()) + { + const auto& providerName = it->first; + const auto& provider = it->second; + + if (!provider) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << providerName << "'. Removing it from skills."; + skillProviderMap.erase(it); + + throw skills::error::SkillException(__PRETTY_FUNCTION__, + "Skill execution failed. Could not query a " + "status update of a skill of provider '" + + providerName + + "' because the provider does not exist."); + } + + try + { + auto async = provider->begin_getSkillExecutionStatus(execId.toIceProviderView()); + l.unlock(); // allow parallel e.g. stopping + auto up = provider->end_getSkillExecutionStatus(async); + + // convert to manager view + return skills::SkillStatusUpdate::FromIce(up, providerName).toIce(); + } + catch (...) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ + << ": Found disconnected or buggy skill provider '" << providerName + << "' during execution. Removing it from skills."; + skillProviderMap.erase(it); + + throw skills::error::SkillException(__PRETTY_FUNCTION__, + "Skill execution failed. Could not query a " + "status update of a skill of provider '" + + providerName + + "' because the provider does not exist."); + } + } + else + { + // no actove skill. Return idle + skills::SkillStatusUpdate idle; + idle.executionId = execId; + return idle.toIce(); + } + } + + skills::manager::dto::SkillStatusUpdateList SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& current) { - skills::manager::dto::SkillStatusUpdateMapMap ret; + skills::manager::dto::SkillStatusUpdateList ret; std::scoped_lock l(skillProviderMapMutex); for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) { - const auto& n = it->first; - const auto& s = it->second; + const auto& providerName = it->first; + const auto& provider = it->second; + + if (!provider) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << providerName << "'. Removing it from skills."; + it = skillProviderMap.erase(it); + continue; + } + try { - if (s) - { - skills::provider::dto::SkillStatusUpdateMap m = s->getSkillExecutionStatuses(); - ret.insert({n, m}); - it++; - } - else + skills::provider::dto::SkillStatusUpdateList m = + provider->getSkillExecutionStatuses(); + + for (const auto& up : m) { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << n << "'. Removing it from skills."; - it = skillProviderMap.erase(it); + // convert provider view to manager view + ret.push_back(skills::SkillStatusUpdate::FromIce(up, providerName).toIce()); } + it++; } catch (...) { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" << n - << "'. Removing it from skills."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" + << providerName << "'. Removing it from skills."; it = skillProviderMap.erase(it); } } diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h index 7b14adf04..cd3a576de 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h @@ -20,26 +20,40 @@ namespace armarx::plugins void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; }; -} +} // namespace armarx::plugins namespace armarx { class SkillManagerComponentPluginUser : - virtual public ManagedIceObject, - virtual public skills::manager::dti::SkillManagerInterface + virtual public ManagedIceObject, + virtual public skills::manager::dti::SkillManagerInterface { public: SkillManagerComponentPluginUser(); - void addProvider(const skills::manager::dto::ProviderInfo& providerInfo, const Ice::Current ¤t) override; - void removeProvider(const std::string&, const Ice::Current ¤t) override; + void addProvider(const skills::manager::dto::ProviderInfo& providerInfo, + const Ice::Current& current) override; + void removeProvider(const std::string&, const Ice::Current& current) override; - skills::provider::dto::SkillStatusUpdate executeSkill(const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current ¤t) override; - void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, const Ice::Current ¤t) override; - void abortSkill(const std::string& providerName, const std::string& skillName, const Ice::Current ¤t) override; + skills::manager::dto::SkillStatusUpdate + executeSkill(const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current& current) override; + void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, + const std::string& providerName, + const Ice::Current& current) override; + void abortSkill(const std::string& providerName, + const std::string& skillName, + const Ice::Current& current) override; - skills::manager::dto::SkillDescriptionMapMap getSkillDescriptions(const Ice::Current ¤t) override; - skills::manager::dto::SkillStatusUpdateMapMap getSkillExecutionStatuses(const Ice::Current ¤t) override; + skills::manager::dto::SkillDescriptionMapMap + getSkillDescriptions(const Ice::Current& current) override; + + skills::manager::dto::SkillStatusUpdate + getSkillExecutionStatus(const skills::manager::dto::SkillExecutionID& executionId, + const Ice::Current& current) override; + + skills::manager::dto::SkillStatusUpdateList + getSkillExecutionStatuses(const Ice::Current& current) override; protected: std::string getFirstProviderNameThatHasSkill(const std::string& skillName); @@ -51,4 +65,4 @@ namespace armarx std::mutex skillProviderMapMutex; std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx> skillProviderMap; }; -} +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillID.cpp b/source/RobotAPI/libraries/skills/provider/SkillID.cpp index 07c6248b2..a384261f8 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillID.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillID.cpp @@ -4,42 +4,63 @@ namespace armarx { namespace skills { - SkillID::SkillID(const std::string& providerName, const std::string& skillName) : providerName(providerName), skillName(skillName) + SkillID::SkillID(const std::string& providerName, const std::string& skillName) : + providerName(providerName), skillName(skillName) { - if (simox::alg::contains(providerName, NAME_SEPARATOR) || simox::alg::contains(skillName, NAME_SEPARATOR)) + if (simox::alg::contains(providerName, NAME_SEPARATOR) || + simox::alg::contains(skillName, NAME_SEPARATOR)) { - throw error::SkillException(__PRETTY_FUNCTION__, std::string("A skill provider or a skill contains the blacklisted token '") + NAME_SEPARATOR + "'."); + throw error::SkillException( + __PRETTY_FUNCTION__, + std::string("A skill provider or a skill contains the blacklisted token '") + + NAME_SEPARATOR + "'."); } - if (simox::alg::contains(providerName, PREFIX_SEPARATOR) || simox::alg::contains(skillName, PREFIX_SEPARATOR)) + if (simox::alg::contains(providerName, PREFIX_SEPARATOR) || + simox::alg::contains(skillName, PREFIX_SEPARATOR)) { - throw error::SkillException(__PRETTY_FUNCTION__, std::string("A skill provider or a skill contains the blacklisted token '") + PREFIX_SEPARATOR + "'."); + throw error::SkillException( + __PRETTY_FUNCTION__, + std::string("A skill provider or a skill contains the blacklisted token '") + + PREFIX_SEPARATOR + "'."); } } - bool SkillID::operator==(const SkillID& other) const + bool + SkillID::operator==(const SkillID& other) const { - return toString() == other.toString(); + return providerName == other.providerName && skillName == other.skillName; } - bool SkillID::operator<(const SkillID& other) const + bool + SkillID::operator!=(const SkillID& other) const + { + return not(*this == other); + } + + bool + SkillID::operator<(const SkillID& other) const { return toString() < other.toString(); } - provider::dto::SkillID SkillID::toIce() const + manager::dto::SkillID + SkillID::toIce() const { return {providerName, skillName}; } - std::string SkillID::toString(const std::string& prefix) const + std::string + SkillID::toString(const std::string& prefix) const { - return (prefix.empty() ? std::string("") : (prefix + PREFIX_SEPARATOR)) + providerName + NAME_SEPARATOR + skillName; + return (prefix.empty() ? std::string("") : (prefix + PREFIX_SEPARATOR)) + providerName + + NAME_SEPARATOR + skillName; } - } + } // namespace skills - std::ostream& skills::operator<<(std::ostream& os, const SkillID& id) + std::ostream& + skills::operator<<(std::ostream& os, const SkillID& id) { return os << "'" << id.toString() << "'"; } -} +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillID.h b/source/RobotAPI/libraries/skills/provider/SkillID.h index 320a6e946..3eb1fd6f4 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillID.h +++ b/source/RobotAPI/libraries/skills/provider/SkillID.h @@ -5,10 +5,10 @@ #include <SimoxUtility/algorithm/string.h> -#include "../error/Exception.h" - +#include <RobotAPI/interface/skills/SkillManagerInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -#include <RobotAPI/interface/skills/SkillProviderInterface.h> + +#include "../error/Exception.h" namespace armarx { @@ -27,12 +27,13 @@ namespace armarx SkillID(const std::string& providerName, const std::string& skillName); bool operator==(const SkillID& other) const; + bool operator!=(const SkillID& other) const; bool operator<(const SkillID& other) const; - provider::dto::SkillID toIce() const; + manager::dto::SkillID toIce() const; std::string toString(const std::string& prefix = "") const; }; std::ostream& operator<<(std::ostream& os, const SkillID& id); - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp b/source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp index f977b2ac5..d0ec681e2 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp @@ -4,9 +4,5 @@ namespace armarx { namespace skills { - aron::data::dto::DictPtr SkillParameterization::toIce() const - { - return aron::data::Dict::ToAronDictDTO(usedInputParams); - } } -} +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillParameterization.h b/source/RobotAPI/libraries/skills/provider/SkillParameterization.h index 72ec6d2eb..65261a5cb 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillParameterization.h +++ b/source/RobotAPI/libraries/skills/provider/SkillParameterization.h @@ -12,10 +12,8 @@ namespace armarx { struct SkillParameterization { - aron::data::DictPtr usedInputParams = nullptr; - callback::dti::SkillProviderCallbackInterfacePrx usedCallbackInterface = nullptr; - - aron::data::dto::DictPtr toIce() const; + aron::data::DictPtr usedInputParams = nullptr; + callback::dti::SkillProviderCallbackInterfacePrx usedCallbackInterface = nullptr; }; - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp index c76da1410..e4ca565aa 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp @@ -29,8 +29,6 @@ namespace armarx::plugins { impl.skill->manager = manager; impl.skill->providerName = providerName; - - impl.statusUpdate.skillId = {providerName, skillName}; } // register self to manager @@ -80,17 +78,9 @@ namespace armarx::plugins } std::string skillName = skill->description.skillName; - if (connected) // TODO: fix so that skills can be added anytime!!! - { - ARMARX_WARNING << "The SkillProvider already registered to a manager. The skill '" + - skillName + - "' therefore cannot be added anymore. Please only add skills in " - "the onInit method."; - return; - } // lock skills map - const std::unique_lock l(skillsMutex); + const std::unique_lock l(skillImplementationsMapMutex); if (skillImplementations.find(skillName) != skillImplementations.end()) { ARMARX_WARNING << "Try to add a skill '" + skillName + @@ -100,7 +90,14 @@ namespace armarx::plugins ARMARX_INFO << "Adding skill and set owning provider name" << skillName; auto s = skillImplementations.emplace(skillName, std::move(skill)); - s.first->second.statusUpdate.skillId = skills::SkillID(parent().getName(), skillName); + + if (connected) + { + // if skill is added after onConnect we have to set the proxies manually. + std::string providerName = parent().getName(); + s.first->second.skill->manager = manager; + s.first->second.skill->providerName = providerName; + } } skills::detail::SkillImplementationWrapper& @@ -108,19 +105,23 @@ namespace armarx::plugins { ARMARX_CHECK_GREATER(skillImplementations.count(name), 0) << "Skill '" + name + "' not found."; - const std::unique_lock l(skillsMutex); + const std::unique_lock l(skillImplementationsMapMutex); return skillImplementations.at(name); } - skills::provider::dto::SkillStatusUpdateMap + skills::provider::dto::SkillStatusUpdateList SkillProviderComponentPlugin::getSkillExecutionStatuses() const { - skills::provider::dto::SkillStatusUpdateMap skillUpdates; - const std::unique_lock l(skillsMutex); + skills::provider::dto::SkillStatusUpdateList skillUpdates; + const std::unique_lock l(skillImplementationsMapMutex); for (const auto& [key, impl] : skillImplementations) { - const std::shared_lock l2(impl.skillStatusMutex); - skillUpdates.insert({key, impl.statusUpdate.toIce()}); + const std::shared_lock l2(impl.skillStatusesMutex); + for (const auto& [execId, up] : impl.statusUpdates) + { + (void)execId; + skillUpdates.push_back(up.toIceProviderView()); + } } return skillUpdates; } @@ -129,7 +130,7 @@ namespace armarx::plugins SkillProviderComponentPlugin::getSkillDescriptions() const { skills::provider::dto::SkillDescriptionMap skillDesciptions; - const std::unique_lock l(skillsMutex); + const std::unique_lock l(skillImplementationsMapMutex); for (const auto& [key, impl] : skillImplementations) { skillDesciptions.insert({key, impl.skill->description.toIce()}); @@ -175,16 +176,29 @@ namespace armarx } skills::provider::dto::SkillStatusUpdate - SkillProviderComponentPluginUser::getSkillExecutionStatus(const std::string& skill, - const Ice::Current& /*unused*/) + SkillProviderComponentPluginUser::getSkillExecutionStatus( + const skills::provider::dto::SkillExecutionID& executionId, + const Ice::Current& /*unused*/) { - auto& skillWrapper = plugin->getSkill(skill); + auto execId = skills::SkillExecutionId::FromIce(executionId, getName()); + + auto& skillWrapper = plugin->getSkill(executionId.skillName); - const std::shared_lock l(skillWrapper.skillStatusMutex); - return skillWrapper.statusUpdate.toIce(); + const std::shared_lock l(skillWrapper.skillStatusesMutex); + if (auto it = skillWrapper.statusUpdates.find(execId); + it != skillWrapper.statusUpdates.end()) + { + return it->second.toIceProviderView(); + } + else + { + skills::SkillStatusUpdate idle; + idle.executionId = execId; + return idle.toIceProviderView(); + } } - skills::provider::dto::SkillStatusUpdateMap + skills::provider::dto::SkillStatusUpdateList SkillProviderComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& /*unused*/) { return plugin->getSkillExecutionStatuses(); @@ -196,7 +210,7 @@ namespace armarx const skills::provider::dto::SkillExecutionRequest& info, const Ice::Current& /*unused*/) { - // The skill will be executed in a different thread + // The skill will be executed in a seperate thread std::thread execution; // setup input args for skill execution @@ -215,7 +229,7 @@ namespace armarx { // execute waits until the previous execution finishes. auto x = wrapper.setupAndExecuteSkill(info.executorName, usedParameterization); - ret = x.toIce(); + ret = x.toIceProviderView(); }); } // release lock. We don't know how long the skill needs to finish and we have to release the lock for being able to abort the execution @@ -227,7 +241,8 @@ namespace armarx } void - SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, const Ice::Current& /*unused*/) + SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, + const Ice::Current& /*unused*/) { auto& wrapper = plugin->getSkill(skillName); wrapper.skill->notifySkillToStopASAP(); diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h index 6b74dd1e2..d6bfe6e05 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h @@ -1,11 +1,11 @@ #pragma once +#include <experimental/memory> #include <functional> #include <queue> #include <shared_mutex> #include <thread> #include <type_traits> -#include <experimental/memory> #include <ArmarXCore/core/ComponentPlugin.h> #include <ArmarXCore/core/ManagedIceObject.h> @@ -23,10 +23,12 @@ // Helper wrapper for execution #include "detail/SkillImplementationWrapper.h" + namespace armarx { class SkillProviderComponentPluginUser; // forward declaration } + namespace armarx::plugins { class SkillProviderComponentPlugin : public ComponentPlugin @@ -61,15 +63,16 @@ namespace armarx::plugins return static_cast<T*>(skillPtr); } + skills::provider::dto::SkillStatusUpdateList getSkillExecutionStatuses() const; + skills::provider::dto::SkillDescriptionMap getSkillDescriptions() const; + private: skills::detail::SkillImplementationWrapper& getSkill(const std::string& name); - skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses() const; - skills::provider::dto::SkillDescriptionMap getSkillDescriptions() const; skills::manager::dti::SkillManagerInterfacePrx manager; skills::provider::dti::SkillProviderInterfacePrx myPrx; - mutable std::shared_mutex skillsMutex; + mutable std::mutex skillImplementationsMapMutex; bool connected = false; std::map<std::string, skills::detail::SkillImplementationWrapper> skillImplementations; @@ -93,9 +96,9 @@ namespace armarx skills::provider::dto::SkillDescriptionMap getSkillDescriptions(const Ice::Current& current = Ice::Current()) override; skills::provider::dto::SkillStatusUpdate - getSkillExecutionStatus(const std::string& skill, + getSkillExecutionStatus(const skills::provider::dto::SkillExecutionID& executionId, const Ice::Current& current = Ice::Current()) override; - skills::provider::dto::SkillStatusUpdateMap + skills::provider::dto::SkillStatusUpdateList getSkillExecutionStatuses(const Ice::Current& current = Ice::Current()) override; skills::provider::dto::SkillStatusUpdate diff --git a/source/RobotAPI/libraries/skills/provider/SkillProxy.h b/source/RobotAPI/libraries/skills/provider/SkillProxy.h index 32058b174..c9ea3f09f 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProxy.h +++ b/source/RobotAPI/libraries/skills/provider/SkillProxy.h @@ -41,9 +41,6 @@ namespace armarx const std::string& profileName, const aron::data::DictPtr& params = nullptr); - - void abortSkill(const std::string& executorName); - private: const manager::dti::SkillManagerInterfacePrx& manager; diff --git a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp b/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp index 18c4b8647..8a7ac2ab5 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp @@ -4,7 +4,8 @@ namespace armarx { namespace skills { - SkillStatus toSkillStatus(const ActiveOrTerminatedSkillStatus& d) + SkillStatus + toSkillStatus(const ActiveOrTerminatedSkillStatus& d) { switch (d) { @@ -20,7 +21,8 @@ namespace armarx throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - SkillStatus toSkillStatus(const TerminatedSkillStatus& d) + SkillStatus + toSkillStatus(const TerminatedSkillStatus& d) { switch (d) { @@ -34,72 +36,76 @@ namespace armarx throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - void toIce(provider::dto::Execution::Status& ret, const SkillStatus& status) + void + toIce(provider::dto::Execution::Status& ret, const SkillStatus& status) { - switch(status) + switch (status) { case SkillStatus::Idle: - ret = provider::dto::Execution::Status::Idle; + ret = provider::dto::Execution::Status::Idle; return; case SkillStatus::Scheduled: - ret = provider::dto::Execution::Status::Scheduled; + ret = provider::dto::Execution::Status::Scheduled; return; case SkillStatus::Running: - ret = provider::dto::Execution::Status::Running; + ret = provider::dto::Execution::Status::Running; return; case SkillStatus::Failed: - ret = provider::dto::Execution::Status::Failed; + ret = provider::dto::Execution::Status::Failed; return; case SkillStatus::Succeeded: - ret = provider::dto::Execution::Status::Succeeded; + ret = provider::dto::Execution::Status::Succeeded; return; case SkillStatus::Aborted: - ret = provider::dto::Execution::Status::Aborted; + ret = provider::dto::Execution::Status::Aborted; return; } throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - void toIce(provider::dto::Execution::Status& ret, const ActiveOrTerminatedSkillStatus& status) + void + toIce(provider::dto::Execution::Status& ret, const ActiveOrTerminatedSkillStatus& status) { - switch(status) + switch (status) { case ActiveOrTerminatedSkillStatus::Running: - ret = provider::dto::Execution::Status::Running; + ret = provider::dto::Execution::Status::Running; return; case ActiveOrTerminatedSkillStatus::Failed: - ret = provider::dto::Execution::Status::Failed; + ret = provider::dto::Execution::Status::Failed; return; case ActiveOrTerminatedSkillStatus::Succeeded: - ret = provider::dto::Execution::Status::Succeeded; + ret = provider::dto::Execution::Status::Succeeded; return; case ActiveOrTerminatedSkillStatus::Aborted: - ret = provider::dto::Execution::Status::Aborted; + ret = provider::dto::Execution::Status::Aborted; return; } throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - void toIce(provider::dto::Execution::Status& ret, const TerminatedSkillStatus& status) + void + toIce(provider::dto::Execution::Status& ret, const TerminatedSkillStatus& status) { - switch(status) + switch (status) { case TerminatedSkillStatus::Failed: - ret = provider::dto::Execution::Status::Failed; + ret = provider::dto::Execution::Status::Failed; return; case TerminatedSkillStatus::Succeeded: - ret = provider::dto::Execution::Status::Succeeded; + ret = provider::dto::Execution::Status::Succeeded; return; case TerminatedSkillStatus::Aborted: - ret = provider::dto::Execution::Status::Aborted; + ret = provider::dto::Execution::Status::Aborted; return; } throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - void fromIce(const provider::dto::Execution::Status& status, TerminatedSkillStatus& ret) + void + fromIce(const provider::dto::Execution::Status& status, TerminatedSkillStatus& ret) { - switch(status) + switch (status) { case provider::dto::Execution::Status::Idle: [[fallthrough]]; @@ -108,138 +114,331 @@ namespace armarx case provider::dto::Execution::Status::Running: break; case provider::dto::Execution::Status::Failed: - ret = TerminatedSkillStatus::Failed; + ret = TerminatedSkillStatus::Failed; return; case provider::dto::Execution::Status::Succeeded: - ret = TerminatedSkillStatus::Succeeded; + ret = TerminatedSkillStatus::Succeeded; return; case provider::dto::Execution::Status::Aborted: - ret = TerminatedSkillStatus::Aborted; + ret = TerminatedSkillStatus::Aborted; return; } - throw error::SkillException(__PRETTY_FUNCTION__, "You entered an invalid execution status type to convert to a terminating status."); + throw error::SkillException( + __PRETTY_FUNCTION__, + "You entered an invalid execution status type to convert to a terminating status."); } - void fromIce(const provider::dto::Execution::Status& status, ActiveOrTerminatedSkillStatus& ret) + void + fromIce(const provider::dto::Execution::Status& status, ActiveOrTerminatedSkillStatus& ret) { - switch(status) + switch (status) { case provider::dto::Execution::Status::Idle: [[fallthrough]]; case provider::dto::Execution::Status::Scheduled: break; case provider::dto::Execution::Status::Running: - ret = ActiveOrTerminatedSkillStatus::Running; + ret = ActiveOrTerminatedSkillStatus::Running; return; case provider::dto::Execution::Status::Failed: - ret = ActiveOrTerminatedSkillStatus::Failed; + ret = ActiveOrTerminatedSkillStatus::Failed; return; case provider::dto::Execution::Status::Succeeded: - ret = ActiveOrTerminatedSkillStatus::Succeeded; + ret = ActiveOrTerminatedSkillStatus::Succeeded; return; case provider::dto::Execution::Status::Aborted: - ret = ActiveOrTerminatedSkillStatus::Aborted; + ret = ActiveOrTerminatedSkillStatus::Aborted; return; } - throw error::SkillException(__PRETTY_FUNCTION__, "You entered an invalid execution status type to convert to a terminating status."); + throw error::SkillException( + __PRETTY_FUNCTION__, + "You entered an invalid execution status type to convert to a terminating status."); } - void fromIce(const provider::dto::Execution::Status& status, SkillStatus& ret) + void + fromIce(const provider::dto::Execution::Status& status, SkillStatus& ret) { - switch(status) + switch (status) { case provider::dto::Execution::Status::Idle: - ret = SkillStatus::Idle; + ret = SkillStatus::Idle; return; case provider::dto::Execution::Status::Scheduled: - ret = SkillStatus::Scheduled; + ret = SkillStatus::Scheduled; return; case provider::dto::Execution::Status::Running: - ret = SkillStatus::Running; + ret = SkillStatus::Running; return; case provider::dto::Execution::Status::Failed: - ret = SkillStatus::Failed; + ret = SkillStatus::Failed; return; case provider::dto::Execution::Status::Succeeded: - ret = SkillStatus::Succeeded; + ret = SkillStatus::Succeeded; return; case provider::dto::Execution::Status::Aborted: - ret = SkillStatus::Aborted; + ret = SkillStatus::Aborted; return; } throw error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } + skills::manager::dto::SkillExecutionID + SkillExecutionId::toIce() const + { + skills::manager::dto::SkillExecutionID ret; + ret.skillId.skillName = skillId.skillName; + ret.skillId.providerName = skillId.providerName; + ret.executorName = executorName; + armarx::core::time::toIce(ret.executionStartedTime, executionStartedTime); + return ret; + } + skills::provider::dto::SkillExecutionID + SkillExecutionId::toIceProviderView() const + { + skills::provider::dto::SkillExecutionID ret; + ret.skillName = skillId.skillName; + ret.executorName = executorName; + armarx::core::time::toIce(ret.executionStartedTime, executionStartedTime); + return ret; + } + void + SkillExecutionId::fromIce(const skills::manager::dto::SkillExecutionID& i) + { + skillId.skillName = i.skillId.skillName; + skillId.providerName = i.skillId.providerName; + executorName = i.executorName; + armarx::core::time::fromIce(i.executionStartedTime, executionStartedTime); + } - provider::dto::SkillStatusUpdate TerminatedSkillStatusUpdate::toIce() const + void + SkillExecutionId::fromIce(const skills::provider::dto::SkillExecutionID& i, + const std::string& providerName) { - provider::dto::SkillStatusUpdate ret; - ret.header.skillId = skillId.toIce(); - ret.header.executorName = executorName; - ret.data = aron::data::Dict::ToAronDictDTO(data); - skills::toIce(ret.header.status, status); + skillId.skillName = i.skillName; + skillId.providerName = providerName; + executorName = i.executorName; + armarx::core::time::fromIce(i.executionStartedTime, executionStartedTime); + } + + SkillExecutionId + SkillExecutionId::FromIce(const skills::manager::dto::SkillExecutionID& i) + { + SkillExecutionId ret; + ret.fromIce(i); + return ret; + } + + SkillExecutionId + SkillExecutionId::FromIce(const skills::provider::dto::SkillExecutionID& i, + const std::string& providerName) + { + SkillExecutionId ret; + ret.fromIce(i, providerName); + return ret; + } + + manager::dto::SkillStatusUpdate + SkillStatusUpdateBase::toIce() const + { + manager::dto::SkillStatusUpdate ret; + ret.header.executionId.skillId = executionId.skillId.toIce(); + ret.header.executionId.executorName = executionId.executorName; + armarx::core::time::toIce(ret.header.executionId.executionStartedTime, + executionId.executionStartedTime); + ret.header.usedParams = + aron::data::Dict::ToAronDictDTO(usedParameterization.usedInputParams); ret.header.usedCallbackInterface = usedParameterization.usedCallbackInterface; - ret.header.usedParams = usedParameterization.toIce(); + ret.data = aron::data::Dict::ToAronDictDTO(data); return ret; } - provider::dto::SkillStatusUpdate SkillStatusUpdate::toIce() const + provider::dto::SkillStatusUpdate + SkillStatusUpdateBase::toIceProviderView() const { provider::dto::SkillStatusUpdate ret; - ret.header.skillId = skillId.toIce(); - ret.header.executorName = executorName; + ret.header.executionId.skillName = executionId.skillId.skillName; + ret.header.executionId.executorName = executionId.executorName; + armarx::core::time::toIce(ret.header.executionId.executionStartedTime, + executionId.executionStartedTime); + ret.header.usedParams = + aron::data::Dict::ToAronDictDTO(usedParameterization.usedInputParams); + ret.header.usedCallbackInterface = usedParameterization.usedCallbackInterface; ret.data = aron::data::Dict::ToAronDictDTO(data); + return ret; + } + + void + SkillStatusUpdateBase::fromIce(const manager::dto::SkillStatusUpdate& update) + { + executionId.skillId = {update.header.executionId.skillId.providerName, + update.header.executionId.skillId.skillName}; + executionId.executorName = update.header.executionId.executorName; + armarx::core::time::fromIce(update.header.executionId.executionStartedTime, + executionId.executionStartedTime); + usedParameterization.usedInputParams = + armarx::aron::data::Dict::FromAronDictDTO(update.header.usedParams); + usedParameterization.usedCallbackInterface = update.header.usedCallbackInterface; + data = armarx::aron::data::Dict::FromAronDictDTO(update.data); + } + + void + SkillStatusUpdateBase::fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) + { + executionId.skillId = {providerName, update.header.executionId.skillName}; + executionId.executorName = update.header.executionId.executorName; + armarx::core::time::fromIce(update.header.executionId.executionStartedTime, + executionId.executionStartedTime); + usedParameterization.usedInputParams = + armarx::aron::data::Dict::FromAronDictDTO(update.header.usedParams); + usedParameterization.usedCallbackInterface = update.header.usedCallbackInterface; + data = armarx::aron::data::Dict::FromAronDictDTO(update.data); + } + + manager::dto::SkillStatusUpdate + TerminatedSkillStatusUpdate::toIce() const + { + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); skills::toIce(ret.header.status, status); - ret.header.usedCallbackInterface = usedParameterization.usedCallbackInterface; - ret.header.usedParams = usedParameterization.toIce(); return ret; } - provider::dto::SkillStatusUpdate ActiveOrTerminatedSkillStatusUpdate::toIce() const + provider::dto::SkillStatusUpdate + TerminatedSkillStatusUpdate::toIceProviderView() const { - provider::dto::SkillStatusUpdate ret; - ret.header.skillId = skillId.toIce(); - ret.header.executorName = executorName; - ret.data = aron::data::Dict::ToAronDictDTO(data); + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); skills::toIce(ret.header.status, status); - ret.header.usedCallbackInterface = usedParameterization.usedCallbackInterface; - ret.header.usedParams = usedParameterization.toIce(); return ret; } - TerminatedSkillStatusUpdate TerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update) + manager::dto::SkillStatusUpdate + SkillStatusUpdate::toIce() const + { + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); + skills::toIce(ret.header.status, status); + return ret; + } + + provider::dto::SkillStatusUpdate + SkillStatusUpdate::toIceProviderView() const + { + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); + skills::toIce(ret.header.status, status); + return ret; + } + + manager::dto::SkillStatusUpdate + ActiveOrTerminatedSkillStatusUpdate::toIce() const + { + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); + skills::toIce(ret.header.status, status); + return ret; + } + + provider::dto::SkillStatusUpdate + ActiveOrTerminatedSkillStatusUpdate::toIceProviderView() const + { + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); + skills::toIce(ret.header.status, status); + return ret; + } + + void + TerminatedSkillStatusUpdate::fromIce(const manager::dto::SkillStatusUpdate& update) + { + SkillStatusUpdateBase::fromIce(update); + skills::fromIce(update.header.status, status); + } + + void + TerminatedSkillStatusUpdate::fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) + { + SkillStatusUpdateBase::fromIce(update, providerName); + skills::fromIce(update.header.status, status); + } + + TerminatedSkillStatusUpdate + TerminatedSkillStatusUpdate::FromIce(const manager::dto::SkillStatusUpdate& update) + { + TerminatedSkillStatusUpdate ret; + ret.fromIce(update); + return ret; + } + + TerminatedSkillStatusUpdate + TerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) { TerminatedSkillStatusUpdate ret; - ret.skillId = {update.header.skillId.providerName, update.header.skillId.skillName}; - ret.executorName = update.header.executorName; - skills::fromIce(update.header.status, ret.status); - ret.usedParameterization = {aron::data::Dict::FromAronDictDTO(update.header.usedParams), update.header.usedCallbackInterface}; - ret.data = aron::data::Dict::FromAronDictDTO(update.data); + ret.fromIce(update, providerName); return ret; } - SkillStatusUpdate SkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update) + void + SkillStatusUpdate::fromIce(const manager::dto::SkillStatusUpdate& update) + { + SkillStatusUpdateBase::fromIce(update); + skills::fromIce(update.header.status, status); + } + + void + SkillStatusUpdate::fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) + { + SkillStatusUpdateBase::fromIce(update, providerName); + skills::fromIce(update.header.status, status); + } + + SkillStatusUpdate + SkillStatusUpdate::FromIce(const manager::dto::SkillStatusUpdate& update) + { + SkillStatusUpdate ret; + ret.fromIce(update); + return ret; + } + + SkillStatusUpdate + SkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) { SkillStatusUpdate ret; - ret.skillId = {update.header.skillId.providerName, update.header.skillId.skillName}; - ret.executorName = update.header.executorName; - skills::fromIce(update.header.status, ret.status); - ret.usedParameterization = {aron::data::Dict::FromAronDictDTO(update.header.usedParams), update.header.usedCallbackInterface}; - ret.data = aron::data::Dict::FromAronDictDTO(update.data); + ret.fromIce(update, providerName); + return ret; + } + + void + ActiveOrTerminatedSkillStatusUpdate::fromIce(const manager::dto::SkillStatusUpdate& update) + { + SkillStatusUpdateBase::fromIce(update); + skills::fromIce(update.header.status, status); + } + + void + ActiveOrTerminatedSkillStatusUpdate::fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) + { + SkillStatusUpdateBase::fromIce(update, providerName); + skills::fromIce(update.header.status, status); + } + + ActiveOrTerminatedSkillStatusUpdate + ActiveOrTerminatedSkillStatusUpdate::FromIce(const manager::dto::SkillStatusUpdate& update) + { + ActiveOrTerminatedSkillStatusUpdate ret; + ret.fromIce(update); return ret; } - ActiveOrTerminatedSkillStatusUpdate ActiveOrTerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update) + ActiveOrTerminatedSkillStatusUpdate + ActiveOrTerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName) { ActiveOrTerminatedSkillStatusUpdate ret; - ret.skillId = {update.header.skillId.providerName, update.header.skillId.skillName}; - ret.executorName = update.header.executorName; - skills::fromIce(update.header.status, ret.status); - ret.usedParameterization = {aron::data::Dict::FromAronDictDTO(update.header.usedParams), update.header.usedCallbackInterface}; - ret.data = aron::data::Dict::FromAronDictDTO(update.data); + ret.fromIce(update, providerName); return ret; } - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h b/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h index 6e1ec3c16..246577de4 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h +++ b/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h @@ -3,8 +3,11 @@ #include <string> #include <vector> -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> +#include <ArmarXCore/core/time/DateTime.h> +#include <ArmarXCore/core/time/ice_conversions.h> + #include <RobotAPI/interface/skills/SkillProviderInterface.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> #include "SkillID.h" #include "SkillParameterization.h" @@ -42,49 +45,144 @@ namespace armarx SkillStatus toSkillStatus(const TerminatedSkillStatus&); void toIce(provider::dto::Execution::Status& ret, const SkillStatus& status); - void toIce(provider::dto::Execution::Status& ret, const ActiveOrTerminatedSkillStatus& status); + void toIce(provider::dto::Execution::Status& ret, + const ActiveOrTerminatedSkillStatus& status); void toIce(provider::dto::Execution::Status& ret, const TerminatedSkillStatus& status); void fromIce(const provider::dto::Execution::Status& status, TerminatedSkillStatus& ret); - void fromIce(const provider::dto::Execution::Status& status, ActiveOrTerminatedSkillStatus& ret); + void fromIce(const provider::dto::Execution::Status& status, + ActiveOrTerminatedSkillStatus& ret); void fromIce(const provider::dto::Execution::Status& status, SkillStatus& ret); + struct SkillExecutionId + { + static const constexpr char* NOT_INITIALIZED = "NOT INITIALIZED YET"; + SkillID skillId = {NOT_INITIALIZED, NOT_INITIALIZED}; + std::string executorName = ""; + armarx::core::time::DateTime executionStartedTime = + armarx::core::time::DateTime::Invalid(); + + bool + operator==(const SkillExecutionId& other) const + { + if (skillId != other.skillId) + { + return false; + } + if (executionStartedTime != other.executionStartedTime) + { + return false; + } + if (executorName != other.executorName) + { + return false; + } + return true; + } + + bool + operator<(const SkillExecutionId& other) const + { + // We explicitly do not compare skillIds as we ONLY want to bring the executionids in some (temporal) order + return executionStartedTime < other.executionStartedTime; + } + + skills::manager::dto::SkillExecutionID toIce() const; + + skills::provider::dto::SkillExecutionID toIceProviderView() const; + + void fromIce(const skills::manager::dto::SkillExecutionID&); + + void fromIce(const skills::provider::dto::SkillExecutionID&, + const std::string& providerName); + + static SkillExecutionId FromIce(const skills::manager::dto::SkillExecutionID&); + + static SkillExecutionId FromIce(const skills::provider::dto::SkillExecutionID&, + const std::string& providerName); + }; + struct SkillStatusUpdateBase { // header - SkillID skillId = {"NOT INITIALIZED YET", "NOT INITIALIZED YET"}; - std::string executorName = ""; - SkillParameterization usedParameterization; + SkillExecutionId executionId; + SkillParameterization usedParameterization; // data - aron::data::DictPtr data = nullptr; + aron::data::DictPtr data = nullptr; + + manager::dto::SkillStatusUpdate toIce() const; + + provider::dto::SkillStatusUpdate toIceProviderView() const; + + void fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); + + void fromIce(const manager::dto::SkillStatusUpdate& update); }; // Will be returned after the execution of a skill struct TerminatedSkillStatusUpdate : public SkillStatusUpdateBase { - TerminatedSkillStatus status = TerminatedSkillStatus::Failed; + TerminatedSkillStatus status = TerminatedSkillStatus::Failed; + + manager::dto::SkillStatusUpdate toIce() const; + + provider::dto::SkillStatusUpdate toIceProviderView() const; + + void fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); - provider::dto::SkillStatusUpdate toIce() const; - static TerminatedSkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update); + void fromIce(const manager::dto::SkillStatusUpdate& update); + + static TerminatedSkillStatusUpdate + FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); + + static TerminatedSkillStatusUpdate + FromIce(const manager::dto::SkillStatusUpdate& update); }; // Will be returned from periodic skills which can still run struct ActiveOrTerminatedSkillStatusUpdate : public SkillStatusUpdateBase { - ActiveOrTerminatedSkillStatus status = ActiveOrTerminatedSkillStatus::Failed; + ActiveOrTerminatedSkillStatus status = ActiveOrTerminatedSkillStatus::Failed; + + manager::dto::SkillStatusUpdate toIce() const; + + provider::dto::SkillStatusUpdate toIceProviderView() const; + + void fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); + + void fromIce(const manager::dto::SkillStatusUpdate& update); - provider::dto::SkillStatusUpdate toIce() const; - static ActiveOrTerminatedSkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update); + static ActiveOrTerminatedSkillStatusUpdate + FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); + + static ActiveOrTerminatedSkillStatusUpdate + FromIce(const manager::dto::SkillStatusUpdate& update); }; // Will be used as status updates from skills to the callback interface struct SkillStatusUpdate : public SkillStatusUpdateBase { - SkillStatus status = SkillStatus::Idle; + SkillStatus status = SkillStatus::Idle; + + manager::dto::SkillStatusUpdate toIce() const; + + provider::dto::SkillStatusUpdate toIceProviderView() const; + + void fromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); + + void fromIce(const manager::dto::SkillStatusUpdate& update); + + static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update, + const std::string& providerName); - provider::dto::SkillStatusUpdate toIce() const; - static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update); + static SkillStatusUpdate FromIce(const manager::dto::SkillStatusUpdate& update); }; - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp index 81e91b131..32f8358c2 100644 --- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp +++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp @@ -4,40 +4,45 @@ namespace armarx { namespace skills::detail { - SkillImplementationWrapper::SkillImplementationWrapper(std::unique_ptr<skills::Skill>&& skill) : + SkillImplementationWrapper::SkillImplementationWrapper( + std::unique_ptr<skills::Skill>&& skill) : skill(std::move(skill)) { ARMARX_CHECK_NOT_NULL(this->skill); } - TerminatedSkillStatusUpdate SkillImplementationWrapper::setupAndExecuteSkill(const std::string& executorName, const skills::SkillParameterization parameterization) + TerminatedSkillStatusUpdate + SkillImplementationWrapper::setupAndExecuteSkill( + const std::string& executorName, + const skills::SkillParameterization parameterization) { - std::unique_lock l(executingMutex); - const std::string skillName = skill->description.skillName; ARMARX_INFO_S << "Executing skill: " << skillName; - // reset execution params. This func is also used to clean up once this method returns - auto resetExecParam = [&](){ - std::unique_lock l2(skillStatusMutex); // skill is not updating - //statusUpdate.status = skills::provider::dto::Execution::Status::Idle; I decided to not update the status to idle every time the skill stops. - statusUpdate.data = nullptr; - statusUpdate.executorName = ""; - }; + // we can safely assume that no two executions have the same timestamp + const skills::SkillExecutionId executionId = { + skill->getSkillId(), executorName, armarx::core::time::DateTime::Now()}; // set params and setup variables - auto setExecParams = [&](){ - std::lock_guard l(skillStatusMutex); - statusUpdate.usedParameterization = parameterization; - statusUpdate.executorName = executorName; - }; + { + std::unique_lock l(skillStatusesMutex); + statusUpdates[executionId] = + SkillStatusUpdate({{executionId, parameterization}, SkillStatus::Scheduled}); + } - resetExecParam(); - setExecParams(); + // reset execution params. This func is also used to clean up once this method returns + auto tidyUpStatusUpdates = [&]() + { + std::unique_lock l2(skillStatusesMutex); + statusUpdates.erase(executionId); + }; - auto& aron_params = parameterization.usedInputParams; - auto updateStatus = [&](const SkillStatus status, const aron::data::DictPtr& data = nullptr){ - std::lock_guard l(skillStatusMutex); + const auto& aron_params = parameterization.usedInputParams; + auto updateStatus = + [&](const SkillStatus status, const aron::data::DictPtr& data = nullptr) + { + std::unique_lock l(skillStatusesMutex); + auto& statusUpdate = statusUpdates[executionId]; statusUpdate.status = status; statusUpdate.data = data; @@ -45,11 +50,13 @@ namespace armarx if (callbackInterface) { - callbackInterface->updateStatusForSkill(statusUpdate.toIce()); + callbackInterface->updateStatusForSkill(statusUpdate.toIceProviderView(), + skill->getSkillId().providerName); } }; - auto createErrorMessage = [](const std::string& message){ + auto createErrorMessage = [](const std::string& message) + { auto obj = aron::make_dict(); auto m = aron::make_string(message, aron::Path({"errormessage"})); obj->addElement("errormessage", m); @@ -59,37 +66,54 @@ namespace armarx // Check params if (skill->description.acceptedType && not(aron_params)) { - std::string message = "SkillError 001: The Skill '" + skillName + "' requires a type but params are NULL."; + std::string message = "SkillError 001: The Skill '" + skillName + + "' requires a type but params are NULL."; ARMARX_ERROR_S << message; - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } - if (skill->description.acceptedType && aron_params && not(aron_params->fullfillsType(skill->description.acceptedType))) + if (skill->description.acceptedType && aron_params && + not(aron_params->fullfillsType(skill->description.acceptedType))) { - std::string message = "SkillError 002: The Skill '" + skillName + "' has a type and got parameters but the input does not match the type."; + std::string message = + "SkillError 002: The Skill '" + skillName + + "' has a type and got parameters but the input does not match the type."; ARMARX_ERROR_S << message; - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } // Check if skill is available with the given parameterization try { - if (not skill->isSkillAvailable(Skill::InitInput{.executorName = executorName, .params = aron_params})) + if (not skill->isSkillAvailable( + Skill::InitInput{.executorName = executorName, .params = aron_params})) { - std::string message = "SkillError 101: The Skill '" + skillName + "' is not available."; + std::string message = + "SkillError 101: The Skill '" + skillName + "' is not available."; ARMARX_WARNING << message; - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } } + catch (const std::exception& ex) { - std::string message = "SkillError 101e: An error occured during the check whether skill '" + skillName + "' is available. The error was: " + GetHandledExceptionString(); + std::string message = + "SkillError 101e: An error occured during the check whether skill '" + + skillName + "' is available. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } // set scheduled @@ -100,28 +124,39 @@ namespace armarx { skill->resetSkill(); } + catch (const std::exception& ex) { - std::string message = "SkillError 201e: An error occured during the reset of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); + std::string message = + "SkillError 201e: An error occured during the reset of skill '" + skillName + + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; updateStatus(SkillStatus::Failed); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } try { skill->waitForDependenciesOfSkill(); } + catch (const std::exception& ex) { - std::string message = "SkillError 301e: An error occured during waiting for skill dependencies of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); + std::string message = "SkillError 301e: An error occured during waiting for skill " + "dependencies of skill '" + + skillName + + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; updateStatus(SkillStatus::Failed); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } // execute. If the skill fails for some reason, from this point it will always execute its exit function. @@ -133,55 +168,79 @@ namespace armarx Skill::InitResult initRet = skill->initSkill({executorName, aron_params}); if (initRet.status != TerminatedSkillStatus::Succeeded) { - std::string message = "SkillError 401: The initialization of skill '" + skillName + "' did not succeed."; - skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value + std::string message = "SkillError 401: The initialization of skill '" + + skillName + "' did not succeed."; + skill->exitSkill( + {executorName, aron_params}); // try to exit skill. Ignore return value updateStatus(skills::toSkillStatus(initRet.status)); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, initRet.status}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + initRet.status}); } } + catch (const std::exception& ex) { - std::string message = "SkillError 401e: An error occured during the initialization of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); + std::string message = + "SkillError 401e: An error occured during the initialization of skill '" + + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value + skill->exitSkill( + {executorName, aron_params}); // try to exit skill. Ignore return value updateStatus(SkillStatus::Failed); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } + // Init succeeded! Skill::MainResult mainRet; try { - mainRet = skill->mainOfSkill({executorName, aron_params, [&updateStatus](const aron::data::DictPtr& update) - { - // during execution the statusUpdate.status is always RUNNING - updateStatus(SkillStatus::Running, update); - }}); + mainRet = skill->mainOfSkill({executorName, + aron_params, + [&updateStatus](const aron::data::DictPtr& update) + { + // during execution the statusUpdate.status is always RUNNING + updateStatus(SkillStatus::Running, update); + }}); if (mainRet.status != TerminatedSkillStatus::Succeeded) { - std::string message = "SkillError 501: The main method of skill '" + skillName + "' did not succeed."; - skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value + std::string message = "SkillError 501: The main method of skill '" + skillName + + "' did not succeed."; + skill->exitSkill( + {executorName, aron_params}); // try to exit skill. Ignore return value updateStatus(skills::toSkillStatus(mainRet.status)); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, mainRet.status}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + mainRet.status}); } } + catch (const std::exception& ex) { - std::string message = "SkillError 501e: An error occured during the main method of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); + std::string message = + "SkillError 501e: An error occured during the main method of skill '" + + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value + skill->exitSkill( + {executorName, aron_params}); // try to exit skill. Ignore return value updateStatus(SkillStatus::Failed); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } + // Main succeeded! try @@ -189,23 +248,33 @@ namespace armarx Skill::ExitResult exitRet = skill->exitSkill({executorName, aron_params}); if (exitRet.status != TerminatedSkillStatus::Succeeded) { - std::string message = "SkillError 601: The exit method of skill '" + skillName + "' did not succeed."; - skill->exitSkill({executorName, aron_params}); // try to exit skill. Ignore return value + std::string message = "SkillError 601: The exit method of skill '" + skillName + + "' did not succeed."; + skill->exitSkill( + {executorName, aron_params}); // try to exit skill. Ignore return value updateStatus(skills::toSkillStatus(exitRet.status)); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, exitRet.status}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + exitRet.status}); } } + catch (const std::exception& ex) { - std::string message = "SkillError 601e: An error occured during the exit method of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); + std::string message = + "SkillError 601e: An error occured during the exit method of skill '" + + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; updateStatus(SkillStatus::Failed); - resetExecParam(); - return TerminatedSkillStatusUpdate({{skill->getSkillId(), executorName, parameterization, createErrorMessage(message)}, TerminatedSkillStatus::Failed}); + tidyUpStatusUpdates(); + return TerminatedSkillStatusUpdate( + {{executionId, parameterization, createErrorMessage(message)}, + TerminatedSkillStatus::Failed}); } + // Exit succeeded! @@ -213,10 +282,11 @@ namespace armarx updateStatus(SkillStatus::Succeeded); // Tidy up - resetExecParam(); + tidyUpStatusUpdates(); // return result of main method - return {{skill->getSkillId(), executorName, parameterization, mainRet.data}, TerminatedSkillStatus::Succeeded}; + return {{executionId, parameterization, mainRet.data}, + TerminatedSkillStatus::Succeeded}; } - } -} + } // namespace skills::detail +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h index 982bcc366..32fafd353 100644 --- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h +++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h @@ -2,11 +2,11 @@ #include <shared_mutex> +#include <RobotAPI/interface/skills/SkillManagerInterface.h> + +#include "../Skill.h" #include "../SkillDescription.h" #include "../SkillStatusUpdate.h" -#include "../Skill.h" - -#include <RobotAPI/interface/skills/SkillManagerInterface.h> namespace armarx { @@ -20,22 +20,20 @@ namespace armarx // fixed values. Do not change after skill instantiation const std::unique_ptr<Skill> skill; - // Current execution status. Changes during execution + // Current execution statuses. Changes during execution // The status also holds the used parameterization - // skillName and providerName are const after registering the skill in a provider - mutable std::shared_mutex skillStatusMutex; - SkillStatusUpdate statusUpdate; - - // Task information - mutable std::shared_mutex executingMutex; + mutable std::shared_mutex skillStatusesMutex; + std::map<skills::SkillExecutionId, SkillStatusUpdate> statusUpdates; // ctor SkillImplementationWrapper(std::unique_ptr<skills::Skill>&& skill); // execute a skill. The parameterization is copied. T // the return type additionally contains the input configuration (similar to the status updates used in callbacks) - TerminatedSkillStatusUpdate setupAndExecuteSkill(const std::string& executorName, const skills::SkillParameterization); + TerminatedSkillStatusUpdate + setupAndExecuteSkill(const std::string& executorName, + const skills::SkillParameterization); }; - } - } -} + } // namespace detail + } // namespace skills +} // namespace armarx -- GitLab