diff --git a/scenarios/ArMemExample/config/ExampleMemory.cfg b/scenarios/ArMemExample/config/ExampleMemory.cfg index 251382f2af086afccf73924421ea31a2aad01017..274619e2d4d59a0921c674950c7dd6413b7535d1 100644 --- a/scenarios/ArMemExample/config/ExampleMemory.cfg +++ b/scenarios/ArMemExample/config/ExampleMemory.cfg @@ -145,19 +145,27 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates # ArmarX.ExampleMemory.mem.ltm.configuration: # Attributes: -# - Default: {} +# - Default: {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} # - Case sensitivity: yes # - Required: no -# ArmarX.ExampleMemory.mem.ltm.configuration = {} +# ArmarX.ExampleMemory.mem.ltm.configuration = {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} -# ArmarX.ExampleMemory.mem.ltm.enabled: +# ArmarX.ExampleMemory.mem.ltm.enable_querying: # Attributes: # - Default: false # - Case sensitivity: yes # - Required: no # - Possible values: {0, 1, false, no, true, yes} -# ArmarX.ExampleMemory.mem.ltm.enabled = false +# ArmarX.ExampleMemory.mem.ltm.enable_querying = false + + +# ArmarX.ExampleMemory.mem.ltm.mode: +# Attributes: +# - Default: DISABLED +# - Case sensitivity: yes +# - Required: no +# ArmarX.ExampleMemory.mem.ltm.mode = DISABLED # ArmarX.ExampleMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). diff --git a/scenarios/RobotSkillsMemory/RobotSkillsMemory.scx b/scenarios/RobotSkillsMemory/RobotSkillsMemory.scx index 9622c34e544899a5f2e81e01f5f6f7ad6744b013..84c9820b1df4a8304787c971df18f978d8096cd4 100644 --- a/scenarios/RobotSkillsMemory/RobotSkillsMemory.scx +++ b/scenarios/RobotSkillsMemory/RobotSkillsMemory.scx @@ -3,5 +3,7 @@ <application name="RemoteGuiProviderApp" instance="" package="ArmarXGui" nodeName="" enabled="true" iceAutoRestart="false"/> <application name="SkillsMemory" instance="" package="RobotAPI" nodeName="" enabled="true" iceAutoRestart="false"/> <application name="MemoryNameSystem" instance="" package="RobotAPI" nodeName="" enabled="true" iceAutoRestart="false"/> + <application name="DebugObserver" instance="" package="ArmarXCore" nodeName="" enabled="true" iceAutoRestart="false"/> + <application name="ArVizStorage" instance="" package="RobotAPI" nodeName="" enabled="true" iceAutoRestart="false"/> </scenario> diff --git a/scenarios/RobotSkillsMemory/config/MemoryNameSystem.cfg b/scenarios/RobotSkillsMemory/config/MemoryNameSystem.cfg index 7dd22218243ca4f9e67e843da8b42916f3b8568a..b8bc70a66ca7f32a628886ad1bf13e373f9750d3 100644 --- a/scenarios/RobotSkillsMemory/config/MemoryNameSystem.cfg +++ b/scenarios/RobotSkillsMemory/config/MemoryNameSystem.cfg @@ -18,7 +18,7 @@ # ArmarX.ApplicationName = "" -# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_USER_CONFIG_DIR is set, the cache path will be made relative to ARMARX_USER_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${HOME}/.armarx) +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) # Attributes: # - Default: mongo/.cache # - Case sensitivity: yes diff --git a/scenarios/RobotSkillsMemory/config/RemoteGuiProviderApp.cfg b/scenarios/RobotSkillsMemory/config/RemoteGuiProviderApp.cfg index 4fd690cefd94559b207493cf40e346a3e47f3b12..4b6abea40d72afd7d313ee47a9b191f3b26de30d 100644 --- a/scenarios/RobotSkillsMemory/config/RemoteGuiProviderApp.cfg +++ b/scenarios/RobotSkillsMemory/config/RemoteGuiProviderApp.cfg @@ -18,7 +18,7 @@ # ArmarX.ApplicationName = "" -# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_USER_CONFIG_DIR is set, the cache path will be made relative to ARMARX_USER_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${HOME}/.armarx) +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) # Attributes: # - Default: mongo/.cache # - Case sensitivity: yes diff --git a/scenarios/RobotSkillsMemory/config/SkillsMemory.cfg b/scenarios/RobotSkillsMemory/config/SkillsMemory.cfg index 33ff12f5046dad45169c1661741ff7216055c26d..57d1fbc563156ae096bdaad0324321323a1a0724 100644 --- a/scenarios/RobotSkillsMemory/config/SkillsMemory.cfg +++ b/scenarios/RobotSkillsMemory/config/SkillsMemory.cfg @@ -18,7 +18,7 @@ # ArmarX.ApplicationName = "" -# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_USER_CONFIG_DIR is set, the cache path will be made relative to ARMARX_USER_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${HOME}/.armarx) +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) # Attributes: # - Default: mongo/.cache # - Case sensitivity: yes @@ -117,88 +117,105 @@ # ArmarX.SecondsStartupDelay = 0 -# ArmarX.SkillsMemory.: +# ArmarX.SkillMemory.EnableProfiling: enable profiler which is used for logging performance events +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.SkillMemory.EnableProfiling = false + + +# ArmarX.SkillMemory.MinimumLoggingLevel: Local logging level only for this component +# Attributes: +# - Default: Undefined +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.SkillMemory.MinimumLoggingLevel = Undefined + + +# ArmarX.SkillMemory.ObjectName: Name of IceGrid well-known object # Attributes: # - Default: "" # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory. = "" +# ArmarX.SkillMemory.ObjectName = "" -# ArmarX.SkillsMemory.EnableProfiling: enable profiler which is used for logging performance events +# ArmarX.SkillMemory.StatechartCoreSegmentName: Name of the core segment for statecharts. # Attributes: -# - Default: false +# - Default: Statechart # - Case sensitivity: yes # - Required: no -# - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillsMemory.EnableProfiling = false +# ArmarX.SkillMemory.StatechartCoreSegmentName = Statechart -# ArmarX.SkillsMemory.MinimumLoggingLevel: Local logging level only for this component +# ArmarX.SkillMemory.TransitionsProviderSegmentName: Name of the provider segment for statechart transitions. # Attributes: -# - Default: Undefined +# - Default: Transitions # - Case sensitivity: yes # - Required: no -# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} -# ArmarX.SkillsMemory.MinimumLoggingLevel = Undefined +# ArmarX.SkillMemory.TransitionsProviderSegmentName = Transitions -# ArmarX.SkillsMemory.ObjectName: Name of IceGrid well-known object +# ArmarX.SkillMemory.mem.MemoryName: Name of this memory server. # Attributes: -# - Default: "" +# - Default: Skill # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.ObjectName = "" +# ArmarX.SkillMemory.mem.MemoryName = Skill -# ArmarX.SkillsMemory.mem.MemoryName: Name of this memory server. +# ArmarX.SkillMemory.mem.ltm.configuration: # Attributes: -# - Default: Skills +# - Default: {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.mem.MemoryName = Skills +# ArmarX.SkillMemory.mem.ltm.configuration = {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} -# ArmarX.SkillsMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). -# Set to false to use this memory as a stand-alone. +# ArmarX.SkillMemory.mem.ltm.enable_querying: # Attributes: -# - Default: true +# - Default: false # - Case sensitivity: yes # - Required: no # - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillsMemory.mns.MemoryNameSystemEnabled = true +# ArmarX.SkillMemory.mem.ltm.enable_querying = false -# ArmarX.SkillsMemory.mns.MemoryNameSystemName: Name of the Memory Name System (MNS) component. +# ArmarX.SkillMemory.mem.ltm.mode: # Attributes: -# - Default: MemoryNameSystem +# - Default: DISABLED # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.mns.MemoryNameSystemName = MemoryNameSystem +# ArmarX.SkillMemory.mem.ltm.mode = DISABLED -# ArmarX.SkillsMemory.tpc.pub.DebugObserver: Name of the `DebugObserver` topic to publish data to. +# ArmarX.SkillMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). +# Set to false to use this memory as a stand-alone. # Attributes: -# - Default: DebugObserver +# - Default: true # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.tpc.pub.DebugObserver = DebugObserver +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.SkillMemory.mns.MemoryNameSystemEnabled = true -# ArmarX.SkillsMemory.tpc.pub.MemoryListener: Name of the `MemoryListener` topic to publish data to. +# ArmarX.SkillMemory.mns.MemoryNameSystemName: Name of the Memory Name System (MNS) component. # Attributes: -# - Default: MemoryUpdates +# - Default: MemoryNameSystem # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.tpc.pub.MemoryListener = MemoryUpdates +# ArmarX.SkillMemory.mns.MemoryNameSystemName = MemoryNameSystem -# ArmarX.SkillsMemory.tpc.sub.ProfilerListener: Name of the ProfilerListenerInterface topics to subscribe. +# ArmarX.SkillMemory.tpc.sub.ProfilerListener: Name of the ProfilerListenerInterface topics to subscribe. # Attributes: # - Default: StateReportingTopic # - Case sensitivity: yes # - Required: no -# ArmarX.SkillsMemory.tpc.sub.ProfilerListener = StateReportingTopic +# ArmarX.SkillMemory.tpc.sub.ProfilerListener = StateReportingTopic # ArmarX.StartDebuggerOnCrash: If this application crashes (segmentation fault) qtcreator will attach to this process and start the debugger. diff --git a/scenarios/SkillProviderTest/config/SkillsMemory.cfg b/scenarios/SkillProviderTest/config/SkillsMemory.cfg index 8b2bf04855a21e5a8ca955da89ba3a309460241e..57d1fbc563156ae096bdaad0324321323a1a0724 100644 --- a/scenarios/SkillProviderTest/config/SkillsMemory.cfg +++ b/scenarios/SkillProviderTest/config/SkillsMemory.cfg @@ -169,19 +169,27 @@ # ArmarX.SkillMemory.mem.ltm.configuration: # Attributes: -# - Default: {} +# - Default: {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} # - Case sensitivity: yes # - Required: no -# ArmarX.SkillMemory.mem.ltm.configuration = {} +# ArmarX.SkillMemory.mem.ltm.configuration = {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} -# ArmarX.SkillMemory.mem.ltm.enabled: +# ArmarX.SkillMemory.mem.ltm.enable_querying: # Attributes: # - Default: false # - Case sensitivity: yes # - Required: no # - Possible values: {0, 1, false, no, true, yes} -# ArmarX.SkillMemory.mem.ltm.enabled = false +# ArmarX.SkillMemory.mem.ltm.enable_querying = false + + +# ArmarX.SkillMemory.mem.ltm.mode: +# Attributes: +# - Default: DISABLED +# - Case sensitivity: yes +# - Required: no +# ArmarX.SkillMemory.mem.ltm.mode = DISABLED # ArmarX.SkillMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp index 9b16109a96f01e951974f84c70f7e7b159558de5..65b94a3807343d850003a53bbdbabc438a2d4bcc 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp +++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp @@ -176,6 +176,24 @@ namespace armarx::skills::provider fooDesc); } + // Add another lambda example skill + { + skills::SkillDescription fooDesc; + fooDesc.acceptedType = nullptr; // accept everything + fooDesc.description = "This skill dies hard."; + fooDesc.skillName = "Die"; + fooDesc.timeout = armarx::core::time::Duration::MilliSeconds(1000); + addSkill( + [](const std::string& clientId, const aron::data::DictPtr&) + { + std::cout << "bye bye... segfaulting on purpose now!" << std::endl; + Skill* nullSkill = NULL; + nullSkill->getSkillId(); // DEAD! + return TerminatedSkillStatus::Succeeded; + }, + fooDesc); + } + // Add another example skill addSkill(std::make_unique<CallbackSkill>()); diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h index cbd795396941e1d004fd5f7fdf0fa946d70cb71e..2aad033f1f00a2523dd8dcf15b03979eab92b339 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h +++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h @@ -27,8 +27,8 @@ #include <ArmarXCore/core/Component.h> // RobotAPI -#include <RobotAPI/libraries/skills/provider/SkillProxy.h> #include <RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h> +#include <RobotAPI/libraries/skills/provider/SkillProxy.h> namespace armarx::skills::provider { @@ -55,7 +55,6 @@ namespace armarx::skills::provider Skill::MainResult main(const MainInput& in) final; }; - class TimeoutSkill : public PeriodicSkill { public: @@ -67,7 +66,6 @@ namespace armarx::skills::provider PeriodicSkill::StepResult step(const MainInput& in) final; }; - class CallbackSkill : public Skill { public: @@ -91,8 +89,8 @@ namespace armarx::skills::provider * Detailed description of class ExampleClient. */ class SkillProviderExample : - virtual public armarx::Component, - virtual public SkillProviderComponentPluginUser + virtual public armarx::Component, + virtual public SkillProviderComponentPluginUser { public: SkillProviderExample(); @@ -101,7 +99,6 @@ namespace armarx::skills::provider std::string getDefaultName() const override; protected: - armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; void onInitComponent() override; @@ -111,4 +108,4 @@ namespace armarx::skills::provider private: }; -} +} // namespace armarx::skills::provider diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp index 12f89e9aff7960b53e39e12bc920f70ea89917a8..85237f794613e4b2938b07462864172abebed457 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -188,133 +188,157 @@ namespace armarx /* CHECK OWN SKILLS LIST */ // remove non-existing ones - auto managerSkills = manager->getSkillDescriptions(); - std::vector<std::string> removedProviders; - for (auto it = skills.begin(); it != skills.end();) + try { - // TODO: iterate over skills, not just over providers! - std::string providerName = it->first; - if (managerSkills.find(providerName) == managerSkills.end()) + ARMARX_DEBUG << "GET REMOVED PROVIDERS AND REMOVE FROM MAP"; + std::scoped_lock l(skillMutex); + auto managerSkills = manager->getSkillDescriptions(); + std::vector<std::string> removedProviders; + for (auto it = skills.begin(); it != skills.end();) { - removedProviders.push_back(providerName); - it = skills.erase(it); - } - else - { - it++; + // TODO: iterate over skills, not just over providers! + std::string providerName = it->first; + if (managerSkills.find(providerName) == managerSkills.end()) + { + ARMARX_DEBUG << "REMOVE " << providerName; + removedProviders.push_back(providerName); + it = skills.erase(it); + } + else + { + it++; + } } - } - // add new ones - std::vector<std::string> newProviders; - for (const auto& [providerName, providerSkills] : managerSkills) - { - if (skills.find(providerName) == skills.end()) + // add new ones + ARMARX_DEBUG << "GET NEW PROVIDERS AND ADD THEM TO MAP"; + std::vector<std::string> newProviders; + for (const auto& [providerName, providerSkills] : managerSkills) { - skills.insert(std::make_pair(providerName, providerSkills)); - newProviders.push_back(providerName); + if (skills.find(providerName) == skills.end()) + { + ARMARX_DEBUG << "ADD " << providerName; + skills.insert(std::make_pair(providerName, providerSkills)); + newProviders.push_back(providerName); + } } - } - /* CHECK TREE VIEW */ - // remove providers from tree - int i = 0; - while (i < widget.treeWidgetSkills->topLevelItemCount()) - { - QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); - if (std::find(removedProviders.begin(), - removedProviders.end(), - item->text(0).toStdString()) != removedProviders.end()) + /* CHECK TREE VIEW */ + // remove providers from tree + ARMARX_DEBUG << "REMOVE PROVIDERS FROM TREE VIEW"; + int i = 0; + while (i < widget.treeWidgetSkills->topLevelItemCount()) { - delete widget.treeWidgetSkills->takeTopLevelItem(i); - } - else - { - ++i; + QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); + if (auto it = std::find(removedProviders.begin(), + removedProviders.end(), + item->text(0).toStdString()); + it != removedProviders.end()) + { + ARMARX_DEBUG << "REMOVE PROVIDER " << *it; + delete widget.treeWidgetSkills->takeTopLevelItem(i); + } + else + { + ++i; + } } - } - // add new providers - for (const auto& [providerName, providerSkills] : skills) - { - if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); - it != newProviders.end()) + // add new providers + ARMARX_DEBUG << "ADD NEW PROVIDERS TO TREE VIEW"; + for (const auto& [providerName, providerSkills] : skills) { - auto item = new QTreeWidgetItem(widget.treeWidgetSkills); - item->setText(0, QString::fromStdString(providerName)); - for (const auto& [name, sk] : providerSkills) + if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); + it != newProviders.end()) { - auto itsk = new QTreeWidgetItem(item); - item->addChild(itsk); - itsk->setText(0, QString::fromStdString(name)); + auto item = new QTreeWidgetItem(widget.treeWidgetSkills); + 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)); + } } } - } - // update status and active skills window - std::map<skills::SkillID, std::string> activeSkillsAndPrefixes; - auto managerStatuses = manager->getSkillExecutionStatuses(); - for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i) - { - try + // 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) { - 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) + try { - QTreeWidgetItem* skillItem = item->child(j); - skills::SkillID currentSkillId(providerName, skillItem->text(0).toStdString()); + QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); + auto providerName = item->text(0).toStdString(); - auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName); - skillItem->setText(2, - QString::fromStdString(ExecutionStatus2String.at( - statusForSkill.header.status))); + ARMARX_DEBUG << "UPDATE STATI FOR PROVIDER " << providerName; + auto allStatusesForProvider = managerStatuses.at(providerName); - if (not statusForSkill.header.executorName - .empty()) // it means that the skill was called by someone + for (int j = 0; j < item->childCount(); ++j) { - activeSkillsAndPrefixes.insert( - {currentSkillId, statusForSkill.header.executorName}); + 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; + } } - catch (const std::exception& e) - { - // Perhaps the skill provider died after the check at the beginning of this method - continue; - } - } - // finally update the view of 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 + // finally update the view of active skills + ARMARX_DEBUG << "UPDATE ACTIVE SKILLS"; + widget.listWidgetActiveSkills->clear(); + for (const auto& [id, prefix] : activeSkillsAndPrefixes) { - auto prefixedStr2 = id.toString(prefix2); - if (prefixedStr == prefixedStr2) + auto prefixedStr = id.toString(prefix); + bool longest = true; + for ( + const auto& [id2, prefix2] : + activeSkillsAndPrefixes) // check if there is a deeper skill currently executing { - continue; + auto prefixedStr2 = id.toString(prefix2); + if (prefixedStr == prefixedStr2) + { + continue; + } + + if (simox::alg::starts_with(prefixedStr2, prefixedStr)) + { + longest = false; + break; + } } - if (simox::alg::starts_with(prefixedStr2, prefixedStr)) + if (longest) { - longest = false; - break; + widget.listWidgetActiveSkills->addItem( + QString::fromStdString(id.toString() + ": " + id.toString(prefix))); } } - - if (longest) - { - widget.listWidgetActiveSkills->addItem( - QString::fromStdString(id.toString() + ": " + id.toString(prefix))); - } + } + catch (...) + { + // perhaps the manager died during the method? } } @@ -326,6 +350,7 @@ namespace armarx return; } + std::scoped_lock l(skillMutex); const auto& skillDescriptions = skills.at(selectedSkill.providerName); if (!skillDescriptions.count(selectedSkill.skillName)) { @@ -352,6 +377,7 @@ namespace armarx void SkillManagerMonitorWidgetController::stopSkill() { + std::scoped_lock l(skillMutex); if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty()) { return; @@ -372,6 +398,7 @@ namespace armarx SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*) { + std::scoped_lock l(skillMutex); widget.groupBoxSkillDetails->setEnabled(false); if (!current) diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h index 59fd812aa79732ad2af9d501f84adaf2628fab3a..e30b00cf03e892412a06d85ac29d0cea3ac61bc2 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -43,14 +43,12 @@ namespace armarx { - class ARMARXCOMPONENT_IMPORT_EXPORT - SkillManagerMonitorWidgetController: - public armarx::ArmarXComponentWidgetControllerTemplate < SkillManagerMonitorWidgetController > + class ARMARXCOMPONENT_IMPORT_EXPORT SkillManagerMonitorWidgetController : + public armarx::ArmarXComponentWidgetControllerTemplate<SkillManagerMonitorWidgetController> { Q_OBJECT public: - /// Controller Constructor explicit SkillManagerMonitorWidgetController(); /// Controller destructor @@ -65,7 +63,8 @@ namespace armarx * Returns the Widget name displayed in the ArmarXGui to create an * instance of this class. */ - static QString GetWidgetName() + static QString + GetWidgetName() { return "Skills.Manager"; } @@ -95,8 +94,8 @@ namespace armarx /** * Widget Form */ - Ui::SkillManagerMonitorWidget widget; - QPointer<SimpleConfigDialog> dialog; + Ui::SkillManagerMonitorWidget widget; + QPointer<SimpleConfigDialog> dialog; std::string observerName = "SkillManager"; skills::manager::dti::SkillManagerInterfacePrx manager = nullptr; @@ -108,6 +107,7 @@ namespace armarx }; // Data taken from observer (snapshot of it) + mutable std::mutex skillMutex; skills::manager::dto::SkillDescriptionMapMap skills = {}; // User Input @@ -126,6 +126,4 @@ namespace armarx // connected flag std::atomic_bool connected = false; }; -} - - +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp index 60a38b465ddb8bd9d6cbdac5ec4952606624880c..f0171437b9b4898a87a48fc2cc2e49d4a467e986 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp @@ -1,20 +1,26 @@ #include "SkillManagerComponentPlugin.h" #include <ArmarXCore/core/Component.h> + #include "../error/Exception.h" namespace armarx::plugins { - void SkillManagerComponentPlugin::preOnInitComponent() - {} - - void SkillManagerComponentPlugin::preOnConnectComponent() - {} + void + SkillManagerComponentPlugin::preOnInitComponent() + { + } - void SkillManagerComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) - {} -} + void + SkillManagerComponentPlugin::preOnConnectComponent() + { + } + void + SkillManagerComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + { + } +} // namespace armarx::plugins namespace armarx { @@ -23,7 +29,9 @@ namespace armarx addPlugin(plugin); } - void SkillManagerComponentPluginUser::addProvider(const skills::manager::dto::ProviderInfo& info, const Ice::Current&) + void + SkillManagerComponentPluginUser::addProvider(const skills::manager::dto::ProviderInfo& info, + const Ice::Current&) { std::lock_guard l(skillProviderMapMutex); if (skillProviderMap.find(info.providerName) == skillProviderMap.end()) @@ -33,13 +41,16 @@ namespace armarx } else { - ARMARX_INFO << "Trying to add a provider with name '" << info.providerName << "' but the provider already exists. " + ARMARX_INFO << "Trying to add a provider with name '" << info.providerName + << "' but the provider already exists. " << "Overwriting the old provider info."; skillProviderMap[info.providerName] = info.provider; } } - void SkillManagerComponentPluginUser::removeProvider(const std::string& providerName, const Ice::Current&) + void + SkillManagerComponentPluginUser::removeProvider(const std::string& providerName, + const Ice::Current&) { std::lock_guard l(skillProviderMapMutex); if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) @@ -49,11 +60,13 @@ namespace armarx } else { - ARMARX_INFO << "Trying to remove a provider with name '" << providerName << "' but it couldn't be found."; + ARMARX_INFO << "Trying to remove a provider with name '" << providerName + << "' but it couldn't be found."; } } - std::string SkillManagerComponentPluginUser::getFirstProviderNameThatHasSkill(const std::string& skillName) + std::string + SkillManagerComponentPluginUser::getFirstProviderNameThatHasSkill(const std::string& skillName) { for (const auto& [providerName, providerPrx] : skillProviderMap) { @@ -69,18 +82,30 @@ namespace armarx return "INVALID PROVIDER NAME"; } - skills::provider::dto::SkillStatusUpdate SkillManagerComponentPluginUser::executeSkill(const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current&) + using SkillProviderInterfacePrxMap = + std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx>; + + skills::provider::dto::SkillStatusUpdate + SkillManagerComponentPluginUser::executeSkill( + const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current&) { std::string providerName = "INVALID PROVIDER NAME"; if (info.skillId.providerName == "*") { providerName = getFirstProviderNameThatHasSkill(info.skillId.skillName); } - else if(not(info.skillId.providerName.empty())) + else if (not(info.skillId.providerName.empty())) { 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()) { @@ -108,24 +133,39 @@ namespace armarx 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 skill provider '" << n << "' during execution. Removing it from skills."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << n << "' during execution. Removing it from skills."; it = skillProviderMap.erase(it); } } } 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."); + 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 SkillManagerComponentPluginUser::abortSkill(const std::string& providerName, const std::string& skillName, const Ice::Current ¤t) + void + SkillManagerComponentPluginUser::abortSkill(const std::string& providerName, + const std::string& skillName, + const Ice::Current& current) { - std::scoped_lock l(skillProviderMapMutex); + SkillProviderInterfacePrxMap skillProviderMap; + { + std::scoped_lock l(skillProviderMapMutex); + skillProviderMap = this->skillProviderMap; + } + if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) { const auto& n = it->first; @@ -136,19 +176,23 @@ namespace armarx } else { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; - it = skillProviderMap.erase(it); + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << n << "'. Removing it from skills on next execute."; } } } - void SkillManagerComponentPluginUser::updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& statusUpdate, const Ice::Current&) + void + SkillManagerComponentPluginUser::updateStatusForSkill( + const skills::provider::dto::SkillStatusUpdate& statusUpdate, + const Ice::Current&) { - (void) statusUpdate; + (void)statusUpdate; // If you want to use the status, implement this method! } - skills::manager::dto::SkillDescriptionMapMap SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current ¤t) + skills::manager::dto::SkillDescriptionMapMap + SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current& current) { skills::manager::dto::SkillDescriptionMapMap ret; @@ -157,22 +201,33 @@ namespace armarx { const auto& n = it->first; const auto& s = it->second; - if (s) + try { - skills::provider::dto::SkillDescriptionMap m = s->getSkillDescriptions(); - ret.insert({n, m}); - ++it; + 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); + } } - else + catch (...) { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" << n + << "'. Removing it from skills."; it = skillProviderMap.erase(it); } } return ret; } - skills::manager::dto::SkillStatusUpdateMapMap SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current ¤t) + skills::manager::dto::SkillStatusUpdateMapMap + SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& current) { skills::manager::dto::SkillStatusUpdateMapMap ret; @@ -189,10 +244,11 @@ namespace armarx } else { - ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" << n << "'. Removing it from skills."; + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << n << "'. Removing it from skills."; it = skillProviderMap.erase(it); } } return ret; } -} +} // namespace armarx