diff --git a/scenarios/SkillProviderTest/config/SkillsMemory.cfg b/scenarios/SkillProviderTest/config/SkillsMemory.cfg index 57d1fbc563156ae096bdaad0324321323a1a0724..fc086fbe56a016013571883b41f8f8fb721f55b6 100644 --- a/scenarios/SkillProviderTest/config/SkillsMemory.cfg +++ b/scenarios/SkillProviderTest/config/SkillsMemory.cfg @@ -18,6 +18,15 @@ # ArmarX.ApplicationName = "" +# ArmarX.AutodiscoverPackages: If enabled, will discover all ArmarX packages based on the environment variables. Otherwise, the `DefaultPackages` and `AdditionalPackages` properties are used. +# Attributes: +# - Default: true +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.AutodiscoverPackages = true + + # 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 @@ -175,21 +184,13 @@ # ArmarX.SkillMemory.mem.ltm.configuration = {"SnapshotFrequencyFilter": { "WaitingTimeInMs": 1000}, "PngConverter": {}} -# ArmarX.SkillMemory.mem.ltm.enable_querying: +# ArmarX.SkillMemory.mem.ltm.enabled: # Attributes: # - Default: false # - Case sensitivity: yes # - Required: no # - Possible values: {0, 1, false, no, true, yes} -# 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.mem.ltm.enabled = false # ArmarX.SkillMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS). diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp index 7ebd7960d7db1239182b064aaa1b082a20bdbe41..00f5da8322d38c9acdbaf43207c5c159497fb688 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp @@ -135,42 +135,35 @@ namespace armarx } void - SkillsMemory::removeProvider(const std::string& skillProviderName, const Ice::Current& current) + SkillsMemory::removeProvider(const skills::manager::dto::ProviderID& provider, + const Ice::Current& current) { - executableSkillCoreSegment.removeSkillProvider(skillProviderName); + executableSkillCoreSegment.removeSkillProvider(provider.providerName); // remove skills from memory - SkillManagerComponentPluginUser::removeProvider(skillProviderName, current); + SkillManagerComponentPluginUser::removeProvider(provider, current); } 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); - } - - skillExecutionRequestCoreSegment.addSkillExecutionRequest(requestCopy); - return SkillManagerComponentPluginUser::executeSkill(requestCopy, current); + skillExecutionRequestCoreSegment.addSkillExecutionRequest(info); + return SkillManagerComponentPluginUser::executeSkill(info, current); } void SkillsMemory::updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, - const std::string& providerName, + const skills::provider::dto::ProviderID& providerId, const Ice::Current& current) { - skillEventCoreSegment.addSkillUpdateEvent(update, providerName); + skillEventCoreSegment.addSkillUpdateEvent(update, providerId.providerName); } - skills::provider::dto::SkillStatusUpdateList + skills::provider::dto::SkillStatusUpdateMap SkillsMemory::getLatestSkillExecutionStatuses(int n, const Ice::Current& current) { - return {}; + return {}; // TODO } /* diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h index d0b92b485024b7c80ab11b52d4ff28b9893aca23..da7e3df478f3a81d864868c5c489a73af45e15df 100644 --- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h +++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h @@ -77,14 +77,19 @@ namespace armarx // Override SkillManager to add memory functions void addProvider(const skills::manager::dto::ProviderInfo& info, const Ice::Current& current) override; - void removeProvider(const std::string&, const Ice::Current& current) override; + + void removeProvider(const skills::manager::dto::ProviderID& provider, + 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, + + void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, + const skills::provider::dto::ProviderID& id, const Ice::Current& current) override; - skills::provider::dto::SkillStatusUpdateList + + skills::provider::dto::SkillStatusUpdateMap getLatestSkillExecutionStatuses(int n, const Ice::Current& current) override; // WritingInterface interface diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp index 5e5fb58b7ea03440fa7eb69ae8ccd12bc3752cd5..401335868abd5fceddd0d57c05e689e618dbd3e8 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp +++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp @@ -2,11 +2,10 @@ #include "SkillProviderExample.h" +#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h> +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> #include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> #include <RobotAPI/libraries/aron/core/type/variant/primitive/String.h> -#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> - -#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h> namespace armarx::skills::provider { @@ -24,24 +23,20 @@ namespace armarx::skills::provider root_profile_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero()); //default_params.some_matrix = Eigen::Matrix3f::Zero(); - SkillProfile rootProfile{SkillProfile::ROOT_PROFILE_NAME, - SkillProfile::NO_PREDECESSOR, - root_profile_params.toAron()}; - - return SkillDescription{"HelloWorld", + return SkillDescription{{"HelloWorld"}, "This skill logs a message on ARMARX_IMPORTANT", - {{rootProfile.profileName, rootProfile}}, + root_profile_params.toAron(), armarx::core::time::Duration::MilliSeconds(1000), armarx::skills::Example::HelloWorldAcceptedType::ToAronType()}; } Skill::MainResult - HelloWorldSkill::main(const MainInput& in) + HelloWorldSkill::main() { ARMARX_IMPORTANT << "Hi, from the Hello World Skill.\n" << "I received the following data: \n" << aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON( - in.params) + parameters) .dump(2) << "\n" << "(executed at: " << IceUtil::Time::now() << ")"; @@ -55,7 +50,7 @@ namespace armarx::skills::provider SkillDescription ChainingSkill::GetSkillDescription() { - return SkillDescription{"ChainingSkill", + return SkillDescription{{"ChainingSkill"}, "This skill calls the HelloWorld skill three times.", {}, armarx::core::time::Duration::MilliSeconds(3000), @@ -63,7 +58,7 @@ namespace armarx::skills::provider } Skill::MainResult - ChainingSkill::main(const MainInput& in) + ChainingSkill::main() { armarx::skills::Example::HelloWorldAcceptedType exec1; armarx::skills::Example::HelloWorldAcceptedType exec2; @@ -90,7 +85,7 @@ namespace armarx::skills::provider SkillDescription TimeoutSkill::GetSkillDescription() { - return SkillDescription{"Timeout", + return SkillDescription{{"Timeout"}, "This fails with timeout reached", {}, armarx::core::time::Duration::MilliSeconds(1000), @@ -98,7 +93,7 @@ namespace armarx::skills::provider } PeriodicSkill::StepResult - TimeoutSkill::step(const MainInput& in) + TimeoutSkill::step() { // do heavy work std::this_thread::sleep_for(std::chrono::milliseconds(200)); @@ -113,7 +108,7 @@ namespace armarx::skills::provider SkillDescription CallbackSkill::GetSkillDescription() { - return SkillDescription{"ShowMeCallbacks", + return SkillDescription{{"ShowMeCallbacks"}, "This skill does shows callbacks", {}, armarx::core::time::Duration::MilliSeconds(1000), @@ -121,20 +116,21 @@ namespace armarx::skills::provider } Skill::MainResult - CallbackSkill::main(const MainInput& in) + CallbackSkill::main() { ARMARX_IMPORTANT << "Logging three updates via the callback"; auto up1 = std::make_shared<aron::data::Dict>(); up1->addElement("updateInfo", std::make_shared<aron::data::String>("Update 1")); - in.callback(up1); + + this->callback(skills::SkillStatus::Running, up1); auto up2 = std::make_shared<aron::data::Dict>(); up2->addElement("updateInfo", std::make_shared<aron::data::String>("Update 2")); - in.callback(up2); + this->callback(skills::SkillStatus::Running, up2); auto up3 = std::make_shared<aron::data::Dict>(); up3->addElement("updateInfo", std::make_shared<aron::data::String>("Update 3")); - in.callback(up3); + this->callback(skills::SkillStatus::Running, up3); return {TerminatedSkillStatus::Succeeded, nullptr}; } @@ -161,51 +157,31 @@ namespace armarx::skills::provider SkillProviderExample::onInitComponent() { // Add example skill - addSkill(std::make_unique<HelloWorldSkill>()); - - // Add another lambda example skill - { - skills::SkillDescription fooDesc; - fooDesc.acceptedType = nullptr; // accept everything - fooDesc.description = "This skill does exactly nothing."; - fooDesc.skillName = "Foo"; - fooDesc.timeout = armarx::core::time::Duration::MilliSeconds(1000); - addSkill( - [](const std::string& clientId, const aron::data::DictPtr&) - { - std::cout << "Hello from Foo. The skill was called from " << clientId << "." - << std::endl; - return TerminatedSkillStatus::Succeeded; - }, - fooDesc); - } + addSkillFactory(SkillFactory::ForSkillDescriptionGetter<HelloWorldSkill>()); // 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); + skills::SkillDescription fooDesc({"Foo"}, + "This skill does exactly nothing.", + nullptr, + armarx::core::time::Duration::MilliSeconds(1000), + nullptr); + addSkillFactory(fooDesc, + []() + { + std::cout << "Hello from Foo." << std::endl; + return TerminatedSkillStatus::Succeeded; + }); } // Add another example skill - addSkill(std::make_unique<CallbackSkill>()); + addSkillFactory(SkillFactory::ForSkillDescriptionGetter<CallbackSkill>()); // Add timeout skill - addSkill(std::make_unique<TimeoutSkill>()); + addSkillFactory(SkillFactory::ForSkillDescriptionGetter<TimeoutSkill>()); // chaining - addSkill(std::make_unique<ChainingSkill>()); + addSkillFactory(SkillFactory::ForSkillDescriptionGetter<ChainingSkill>()); } void diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h index 2aad033f1f00a2523dd8dcf15b03979eab92b339..ea8f114eb76453a4a23511d0aa24ba4b511d0eb8 100644 --- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h +++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h @@ -41,7 +41,7 @@ namespace armarx::skills::provider static SkillDescription GetSkillDescription(); private: - Skill::MainResult main(const MainInput& in) final; + Skill::MainResult main() final; }; class ChainingSkill : public Skill @@ -52,7 +52,7 @@ namespace armarx::skills::provider static SkillDescription GetSkillDescription(); private: - Skill::MainResult main(const MainInput& in) final; + Skill::MainResult main() final; }; class TimeoutSkill : public PeriodicSkill @@ -63,7 +63,7 @@ namespace armarx::skills::provider static SkillDescription GetSkillDescription(); private: - PeriodicSkill::StepResult step(const MainInput& in) final; + PeriodicSkill::StepResult step() final; }; class CallbackSkill : public Skill @@ -74,7 +74,7 @@ namespace armarx::skills::provider static SkillDescription GetSkillDescription(); private: - Skill::MainResult main(const MainInput& in) final; + Skill::MainResult main() final; }; /** diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp index d2a43c02ebcc3997b6e8bb3acf86e2445cf864c7..127db31f07149e430abb8442eb4383d5d9adc28d 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -24,7 +24,7 @@ #include <string> -#include <RobotAPI/libraries/skills/provider/Skill.h> +#include <RobotAPI/libraries/skills/core/Skill.h> #include "aronTreeWidget/visitors/AronTreeWidgetConverter.h" #include "aronTreeWidget/visitors/AronTreeWidgetCreator.h" @@ -41,7 +41,7 @@ #include "aronTreeWidget/Data.h" -//config +//configSk namespace armarx { QPointer<QDialog> @@ -202,15 +202,14 @@ namespace armarx auto managerSkills = manager->getSkillDescriptions(); - std::vector<std::string> removedProviders; + std::vector<armarx::skills::manager::dto::SkillID> removedSkills; for (auto it = skills.begin(); it != skills.end();) { - // TODO: iterate over skills, not just over providers! - std::string providerName = it->first; - if (managerSkills.find(providerName) == managerSkills.end()) + auto pid = it->first; + if (managerSkills.find(pid) == managerSkills.end()) { - ARMARX_DEBUG << "REMOVE " << providerName; - removedProviders.push_back(providerName); + ARMARX_DEBUG << "REMOVE " << pid; + removedSkills.push_back(pid); it = skills.erase(it); } else @@ -220,13 +219,13 @@ namespace armarx } // add new ones - std::vector<std::string> newProviders; - for (const auto& [providerName, providerSkills] : managerSkills) + std::vector<armarx::skills::manager::dto::SkillID> newSkills; + for (const auto& [skillID, providerSkills] : managerSkills) { - if (skills.find(providerName) == skills.end()) + if (skills.find(skillID) == skills.end()) { - skills.insert(std::make_pair(providerName, providerSkills)); - newProviders.push_back(providerName); + skills.insert(std::make_pair(skillID, providerSkills)); + newSkills.push_back(skillID); } } @@ -236,10 +235,9 @@ namespace armarx while (i < widget.treeWidgetSkills->topLevelItemCount()) { QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i); - if (auto it = std::find(removedProviders.begin(), - removedProviders.end(), - item->text(0).toStdString()); - it != removedProviders.end()) + if (auto it = std::find( + removedSkills.begin(), removedSkills.end(), item->text(0).toStdString()); + it != removedSkills.end()) { delete widget.treeWidgetSkills->takeTopLevelItem(i); } @@ -252,8 +250,8 @@ namespace armarx // add new providers for (const auto& [providerName, providerSkills] : skills) { - if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); - it != newProviders.end()) + if (auto it = std::find(newSkills.begin(), newSkills.end(), providerName); + it != newSkills.end()) { auto item = new QTreeWidgetItem(widget.treeWidgetSkills); item->setText(0, QString::fromStdString(providerName)); @@ -282,9 +280,10 @@ namespace armarx {skills::SkillStatus::Succeeded, "Succeeded"}, // Others - {skills::SkillStatus::Idle, "Not yet started"}, + {skills::SkillStatus::Constructing, "Under construction"}, {skills::SkillStatus::Running, "Running"}, - {skills::SkillStatus::Scheduled, "Scheduled"}}; + {skills::SkillStatus::Initializing, "Initializing"}, + {skills::SkillStatus::Preparing, "Preparing"}}; if (!manager) { @@ -311,7 +310,7 @@ namespace armarx item->setText(0, QString::fromStdString("TODO:")); item->setText( 1, QString::fromStdString(statusUpdate.executionId.skillId.toString())); - if (statusUpdate.hasBeenScheduled()) + if (statusUpdate.hasBeenInitialized()) { item->setText( 2, QString::fromStdString("YES (TODO:)")); // when was skill scheduled @@ -419,7 +418,10 @@ namespace armarx ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName; - manager->abortSkill(selectedSkill.providerName, selectedSkill.skillName); + + auto id = + skills::manager::dto::SkillID{selectedSkill.providerName, selectedSkill.skillName}; + manager->abortSkill(id); } void @@ -468,17 +470,17 @@ namespace armarx auto skillDesc = skills.at(selectedSkill.providerName).at(selectedSkill.skillName); { - auto it = new QTreeWidgetItem( - widget.treeWidgetSkillDetails, - {QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)}); + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Name"), + QString::fromStdString(skillDesc.skillId.skillName)}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } { auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("Available profiles"), - QString::fromStdString(simox::alg::join( - simox::alg::get_keys(skillDesc.profiles), ", "))}); + QString::fromStdString("" /*simox::alg::join( + simox::alg::get_keys(skillDesc.profiles), ", ")*/)}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } @@ -490,10 +492,13 @@ namespace armarx } { + armarx::core::time::Duration d; + armarx::core::time::fromIce(skillDesc.timeout, d); + auto it = new QTreeWidgetItem( widget.treeWidgetSkillDetails, {QString::fromStdString("Timeout"), - QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"}); + QString::fromStdString(std::to_string(d.toMilliSeconds())) + " ms"}); widget.treeWidgetSkillDetails->addTopLevelItem(it); } diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h index 821000d85ecfb6c7f2b2d25cd6db812ab0061125..d3fb1250f0d32b5f78c96c94c6b37bfd570fb3f1 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -38,7 +38,7 @@ #include <RobotAPI/libraries/aron/core/data/variant/All.h> #include <RobotAPI/libraries/aron/core/type/variant/All.h> #include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h> -#include <RobotAPI/libraries/skills/provider/SkillStatusUpdate.h> +#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h> #include "aronTreeWidget/AronTreeWidgetController.h" @@ -111,7 +111,7 @@ namespace armarx // Data taken from observer (snapshot of it) mutable std::mutex updateMutex; - skills::manager::dto::SkillDescriptionMapMap skills = {}; + skills::manager::dto::SkillDescriptionMap skills = {}; std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> pastSkillStatusUpdates = {}; // User Input diff --git a/source/RobotAPI/interface/skills/SkillManagerInterface.ice b/source/RobotAPI/interface/skills/SkillManagerInterface.ice index 17a07d8bcdf22678a551c56bf4b17a97c939532c..adda483ada28b7957bd2de1d3fa9e8e5e00d7e6d 100644 --- a/source/RobotAPI/interface/skills/SkillManagerInterface.ice +++ b/source/RobotAPI/interface/skills/SkillManagerInterface.ice @@ -39,6 +39,18 @@ module armarx string skillName; }; + struct ProviderID + { + string providerName; + }; + + struct ProviderInfo + { + ProviderID providerId; + provider::dti::SkillProviderInterface* provider; + provider::dto::SkillDescriptionMap providedSkills; + }; + // The minimum information that is needed to uniquely identifying a past skill execution struct SkillExecutionID { @@ -47,6 +59,7 @@ module armarx 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 + string uuid; }; // Status updates of a skill (similar to the status update of the providers except the skillID) @@ -67,7 +80,7 @@ module armarx data; // data, attached to the status update. If send via a callback, this data may be used by the callback interface }; - sequence<SkillStatusUpdate> SkillStatusUpdateList; + dictionary<SkillExecutionID, SkillStatusUpdate> SkillStatusUpdateMap; struct SkillExecutionRequest { @@ -78,15 +91,8 @@ module armarx params; // the parameters for the skill. Can be nullptr if the skill does not require parameters }; - struct ProviderInfo - { - string providerName; - provider::dti::SkillProviderInterface* provider; - provider::dto::SkillDescriptionMap providedSkills; - }; - // Provider data types - dictionary<string, provider::dto::SkillDescriptionMap> SkillDescriptionMapMap; + dictionary<SkillID, provider::dto::SkillDescription> SkillDescriptionMap; } module dti @@ -94,25 +100,33 @@ module armarx 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 a proxy of the provider. You should only communicate with the manager !! void addProvider(dto::ProviderInfo providerInfo); - void removeProvider(string providerName); + void removeProvider(dto::ProviderID provider); - dto::SkillDescriptionMapMap + dto::SkillDescriptionMap getSkillDescriptions(); // get all skilldescriptions from all providers dto::SkillStatusUpdate getSkillExecutionStatus(dto::SkillExecutionID executionId); - dto::SkillStatusUpdateList + dto::SkillStatusUpdateMap getSkillExecutionStatuses(); // returns the current executions from all providers dto::SkillStatusUpdate - executeSkill(dto::SkillExecutionRequest skillExecutionInfo); + executeSkill(dto::SkillExecutionRequest + skillExecutionInfo); // blocks until skill is finished. + + dto::SkillExecutionID executeSkillAsync( + dto::SkillExecutionRequest + skillExecutionRequest); // directly returns the execution id + + void addSkillParameters(dto::SkillExecutionID executionId, + aron::data::dto::Dict params); // add params to a skill - void abortSkill(string providerName, string skillName); + void abortSkill(dto::SkillExecutionID execId); // notify a skill to stop ASAP. }; } } diff --git a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice index 09e5db8712062f63759c11d92bc66d6af5875470..15a3dc3798bf695607c4e8a2c870b63910ed47c7 100644 --- a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice +++ b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice @@ -38,7 +38,7 @@ module armarx interface SkillMemoryInterface extends armem::server::MemoryInterface, dti::StatechartListenerInterface, manager::dti::SkillManagerInterface { - provider::dto::SkillStatusUpdateList getLatestSkillExecutionStatuses( + provider::dto::SkillStatusUpdateMap 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 300054875b5948ba23a75563928e9b7cd55237d6..31449a86d2cbccaabe4c2c5ecf9f9950f529d353 100644 --- a/source/RobotAPI/interface/skills/SkillProviderInterface.ice +++ b/source/RobotAPI/interface/skills/SkillProviderInterface.ice @@ -53,36 +53,51 @@ module armarx { sequence<string> StringList; - // A parameterization profile - struct SkillProfile + // A profile is something that is client side! + // // A parameterization profile + // struct SkillProfile + // { + // string profileName; + // string predecessorProfileName; // may be empty + // aron::data::dto::Dict + // parameterization; // may be only a partial set of accepted type + // }; + + // // A list of parameterization profiles. Note that the first element is recognized as root. Following elements overwrite the previous. + // dictionary<string, SkillProfile> SkillProfileDict; + + // A skill ID. Must be unique within one SkillManager + struct SkillID { - string profileName; - string predecessorProfileName; // may be empty - aron::data::dto::Dict parameterization; + string skillName; }; - // A list of parameterization profiles. Note that the first element is recognized as root. Following elements overwrite the previous. - dictionary<string, SkillProfile> SkillProfileDict; + // A provider ID. Only used in callbacks + struct ProviderID + { + string providerName; + }; // Description of a skill, independant of a provider // A skill is nothing but a executable thing, which can be executed on one or more 'robots' (empty means all) struct SkillDescription { - string skillName; // the name of the skill + SkillID skillId; // the id of the skill string description; // a human readable description of what the skill does. Used in GUI - SkillProfileDict profiles; // a dict of profiles - long timeoutMs; // in milliseconds, can be set to -1 for infinite + armarx::core::time::dto::Duration timeout; // can be set to -1 for infinite aron::type::dto::AronObject acceptedType; // the name of the object is irrelevant and only used in GUI. nullptr if not set + aron::data::dto::Dict + rootProfileDefaults; // default parameterization for the skill. Must be robot agnostic }; - dictionary<string, SkillDescription> SkillDescriptionMap; + dictionary<SkillID, SkillDescription> SkillDescriptionMap; // Input to a provider to execute a skill struct SkillExecutionRequest { - string skillName; // the id of the skill + SkillID skillId; // the id of the skill string executorName; // the name of the component/lib/skill that called the execution of the skill aron::data::dto::Dict params; // the used parameterization @@ -95,11 +110,12 @@ module armarx { enum Status { - Idle, - Scheduled, + Constructing, + Initializing, + Preparing, Running, - // terminating values, after execution a skill goes back to idle + // terminating values Failed, Succeeded, Aborted @@ -109,11 +125,12 @@ module armarx // The minimum information that is needed to uniquely identifying a past skill execution struct SkillExecutionID { - string skillName; // the name of the skill + 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 + string uuid; }; // Status updates of a skill @@ -133,27 +150,36 @@ module armarx data; // data, attached to the status update. If send via a callback, this data may be used by the callback interface }; - sequence<SkillStatusUpdate> SkillStatusUpdateList; + dictionary<SkillExecutionID, SkillStatusUpdate> SkillStatusUpdateMap; } module dti { interface SkillProviderInterface { - dto::SkillDescription getSkillDescription(string name); + dto::SkillDescription getSkillDescription(dto::SkillID skill); + dto::SkillDescriptionMap getSkillDescriptions(); + dto::SkillStatusUpdate getSkillExecutionStatus(dto::SkillExecutionID executionId); - dto::SkillStatusUpdateList - getSkillExecutionStatuses(); // returns all current skill executions chronologically + + dto::SkillStatusUpdateMap + getSkillExecutionStatuses(); // returns all current skill executions // 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 + // TODO: Explain skill phases // This method returns a status update where the status is ALWAYS one of the terminating values dto::SkillStatusUpdate executeSkill(dto::SkillExecutionRequest executionInfo); + dto::SkillExecutionID + executeSkillAsync(dto::SkillExecutionRequest executionInfo); + + void addSkillParameters(dto::SkillExecutionID executionId, + aron::data::dto::Dict params); // add params to a skill + // try to kill a skill as soon as possible. When the skill is stopped depends on the implementation. - void abortSkill(string skill); + void abortSkill(dto::SkillExecutionID skill); }; } } @@ -167,13 +193,17 @@ module armarx { module callback { + module dto + { + } + module dti { interface SkillProviderCallbackInterface { // used for callbacks from providers to update their skill execution status void updateStatusForSkill(provider::dto::SkillStatusUpdate statusUpdate, - string providerName); + provider::dto::ProviderID providerId); } } } diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index a5822667f61138a40a9f581de8dc68fb7fd812d6..d6635696acd4f72d3c3342423233a459baf89af0 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -1119,6 +1119,12 @@ namespace armarx::armem::server::obj::instance for (const auto& object : scene.objects) { + if (simox::alg::starts_with(object.className, "#")) + { + // marked to be ignored + continue; + } + const ObjectID classID = object.getClassID(objectFinder); objpose::ObjectPose& pose = objectPoses.emplace_back(); diff --git a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml index a4f7400e94ae9ee33d5eb82034b1c6eb37799484..9b218af037e355e1682fae745d7528ed2ce1ce45 100644 --- a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml +++ b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml @@ -37,18 +37,16 @@ The memory should look like the following: <String /> </ObjectChild> - <ObjectChild key='profiles'> - <Dict> - <armarx::skills::arondto::SkillProfile /> - </Dict> + <ObjectChild key='rootProfileParameterization'> + <AnyObject shared_ptr="1" /> </ObjectChild> <ObjectChild key='iceInfo'> <String /> </ObjectChild> - <ObjectChild key='timeoutMs'> - <int64 /> + <ObjectChild key='timeout'> + <Duration /> </ObjectChild> <ObjectChild key='acceptedType'> diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp index 89660232b7d16f7cbdf4f4ceef0c6d666e1d8ecd..51d783b81d880f27a22cfdeef6a538f9d9a60596 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp +++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp @@ -2,6 +2,8 @@ #include <SimoxUtility/algorithm/string.h> +#include <ArmarXCore/core/time/ice_conversions.h> + #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h> #include <RobotAPI/libraries/aron/converter/datatype/DatatypeConverterVisitor.h> @@ -35,23 +37,19 @@ namespace armarx::skills::segment // add skills auto skills = info.providedSkills; - auto provId = id().withProviderSegmentName(info.providerName); + auto provId = id().withProviderSegmentName(info.providerId.providerName); for (const auto& [key, desc] : skills) { armarx::skills::arondto::SkillDescription skillDescription; - skillDescription.skillName = desc.skillName; + skillDescription.skillName = desc.skillId.skillName; skillDescription.description = desc.description; skillDescription.iceInfo = info.provider->ice_toString(); - for (const auto& [key, p] : desc.profiles) - { - skillDescription.profiles[key] = {}; - skillDescription.profiles[key].profileName = p.profileName; - skillDescription.profiles[key].predecessorProfileName = p.predecessorProfileName; - skillDescription.profiles[key].parameterization = - aron::data::Dict::FromAronDictDTO(p.parameterization); - } - skillDescription.timeoutMs = desc.timeoutMs; + + skillDescription.rootProfileParameterization = + armarx::aron::data::Dict::FromAronDictDTO(desc.rootProfileDefaults); + + armarx::core::time::fromIce(desc.timeout, skillDescription.timeout); if (desc.acceptedType) { diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp index 8eb81c1647460d19e6a09ece3bd2acaa6551afd8..8960afd4b9aa84e9b93e132e648d35c465b7f371 100644 --- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp +++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp @@ -5,7 +5,7 @@ #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> +#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h> namespace armarx::skills::segment { @@ -37,8 +37,9 @@ namespace armarx::skills::segment // 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::Constructing, "Constructing"}, + {armarx::skills::provider::dto::Execution::Status::Initializing, "Initializing"}, + {armarx::skills::provider::dto::Execution::Status::Preparing, "Preparing"}, {armarx::skills::provider::dto::Execution::Status::Running, "Running"}, {armarx::skills::provider::dto::Execution::Status::Aborted, "Aborted"}, {armarx::skills::provider::dto::Execution::Status::Failed, "Failed"}, @@ -51,7 +52,7 @@ namespace armarx::skills::segment event.providerName = up.executionId.skillId.providerName; event.skillName = up.executionId.skillId.skillName; event.status = ExecutionStatus2String.at(update.header.status); - event.params = up.usedParameterization.usedInputParams; + event.params = up.usedParameterization.parameterization; event.data = up.data; armem::MemoryID commitId = id(); diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp index 21235afefb794e8c78443e840a240f56c6720b14..bed88039981cf50fd3897619d60981085c9c4738 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp +++ b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.cpp @@ -193,6 +193,36 @@ namespace armarx::aron::data setElementCopy(key, data); } + void + Dict::mergeAndReplace(const DictPtr& d) + { + if (d == nullptr) + { + return; + } + + // merge and overwrite + for (const auto& [k, v] : getElements()) + { + this->setElement(k, v); + } + } + + void + Dict::mergeAndReplaceCopy(const DictPtr& d) + { + if (d == nullptr) + { + return; + } + + // merge and overwrite + for (const auto& [k, v] : getElements()) + { + this->setElementCopy(k, v); + } + } + bool Dict::hasElement(const std::string& key) const { @@ -231,8 +261,9 @@ namespace armarx::aron::data const auto& p = data->getPath(); if (not p.hasDirectPrefix(this->getPath())) { - ARMARX_WARNING << "An element added to a dict does not have a correct path set. This " - "may cause errors. Please use setElemetCopy() instead."; + ARMARX_WARNING + << "An element added to a dict does not have a correct path set. This " + "may cause errors. Please use setElemetCopy() instead."; } } diff --git a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.h b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.h index f6c2d93955f53af91a04364ada5f3da724ae7033..a49add482dc4e7e6f1a1d5308d76e571785dbe73 100644 --- a/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.h +++ b/source/RobotAPI/libraries/aron/core/data/variant/container/Dict.h @@ -73,6 +73,9 @@ namespace armarx::aron::data VariantPtr getElement(const std::string&) const; std::map<std::string, VariantPtr> getElements() const; + void mergeAndReplace(const DictPtr& d); + void mergeAndReplaceCopy(const DictPtr& d); + VariantPtr at(const std::string&) const; void removeElement(const std::string& key); void clear(); diff --git a/source/RobotAPI/libraries/robotapi/CMakeLists.txt b/source/RobotAPI/libraries/robotapi/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d62c2b5f8297012bfb4be7c6a90f74ac6d542c11 --- /dev/null +++ b/source/RobotAPI/libraries/robotapi/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(core) +add_subdirectory(client) +add_subdirectory(server) diff --git a/source/RobotAPI/libraries/skills/core/CMakeLists.txt b/source/RobotAPI/libraries/skills/core/CMakeLists.txt index ae56efbde0909b63f5e75e9f33a49700ec163c20..66795b7ecdf0b0aa0897a07f5e47e5f5d489d4a1 100644 --- a/source/RobotAPI/libraries/skills/core/CMakeLists.txt +++ b/source/RobotAPI/libraries/skills/core/CMakeLists.txt @@ -15,31 +15,28 @@ armarx_add_library( SOURCES error/Exception.cpp + SkillID.cpp + ProviderID.cpp + ProviderInfo.cpp + SkillExecutionRequest.cpp + SkillStatusUpdate.cpp + SkillExecutionID.cpp + SkillPreparationInput.cpp + SkillParameterization.cpp Skill.cpp - SkillProxy.cpp - PeriodicSkill.cpp - SpecializedSkill.cpp - PeriodicSpecializedSkill.cpp SkillDescription.cpp - SkillContext.cpp HEADERS error/Exception.h + SkillID.h + ProviderID.h + ProviderInfo.h + SkillExecutionRequest.h + SkillStatusUpdate.h + SkillExecutionID.h + SkillPreparationInput.h + SkillParameterization.h Skill.h - SkillProxy.h - PeriodicSkill.h - SpecializedSkill.h - PeriodicSpecializedSkill.h SkillDescription.h - SkillContext.h - - mixins/All.h - mixins/ArvizSkillMixin.h - mixins/MNSSkillMixin.h - mixins/MemoryReadingSkillMixin.h - mixins/RobotReadingSkillMixin.h - mixins/ObjectReadingSkillMixin.h - mixins/ObjectWritingSkillMixin.h - mixins/GraspReadingSkillMixin.h ) add_library(RobotAPI::skills::core ALIAS RobotAPISkillsCore) diff --git a/source/RobotAPI/libraries/skills/core/ProviderID.cpp b/source/RobotAPI/libraries/skills/core/ProviderID.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c347dcf2fbf967f88fcd26eb8838193324f68c50 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/ProviderID.cpp @@ -0,0 +1,69 @@ +#include "ProviderID.h" + +namespace armarx +{ + namespace skills + { + ProviderID::ProviderID(const std::string& pname) : providerName(pname) + { + } + + ProviderID::ProviderID(const skills::SkillID& skillid) : providerName(skillid.providerName) + { + } + + bool + ProviderID::operator==(const ProviderID& other) const + { + return providerName == other.providerName; + } + + bool + ProviderID::operator!=(const ProviderID& other) const + { + return not(*this == other); + } + + bool + ProviderID::operator<(const ProviderID& other) const + { + return toString() < other.toString(); + } + + ProviderID + ProviderID::FromIce(const manager::dto::ProviderID& s) + { + return ProviderID(s.providerName); + } + + ProviderID + ProviderID::FromIce(const provider::dto::ProviderID& s) + { + return ProviderID(s.providerName); + } + + manager::dto::ProviderID + ProviderID::toManagerIce() const + { + return {providerName}; + } + + provider::dto::ProviderID + ProviderID::toProviderIce() const + { + return {providerName}; + } + + std::string + ProviderID::toString(const std::string& prefix) const + { + return (prefix.empty() ? std::string("") : (prefix + PREFIX_SEPARATOR)) + providerName; + } + } // namespace skills + + std::ostream& + skills::operator<<(std::ostream& os, const ProviderID& id) + { + return os << "'" << id.toString() << "'"; + } +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/ProviderID.h b/source/RobotAPI/libraries/skills/core/ProviderID.h new file mode 100644 index 0000000000000000000000000000000000000000..7aee01fd7a9a86fa1abf34f401fcbbbf3a7b6a7b --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/ProviderID.h @@ -0,0 +1,41 @@ +#pragma once + +#include <string> +#include <vector> + +#include <RobotAPI/interface/skills/SkillManagerInterface.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include "SkillID.h" + +namespace armarx +{ + namespace skills + { + class ProviderID + { + public: + static const constexpr char* PREFIX_SEPARATOR = "->"; + + std::string providerName; + + ProviderID() = delete; + ProviderID(const skills::SkillID& skillid); + ProviderID(const std::string& pName); + + bool operator==(const ProviderID& other) const; + bool operator!=(const ProviderID& other) const; + bool operator<(const ProviderID& other) const; + + manager::dto::ProviderID toManagerIce() const; + provider::dto::ProviderID toProviderIce() const; + + static ProviderID FromIce(const manager::dto::ProviderID&); + static ProviderID FromIce(const provider::dto::ProviderID&); + + std::string toString(const std::string& prefix = "") const; + }; + + std::ostream& operator<<(std::ostream& os, const ProviderID& id); + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/ProviderInfo.cpp b/source/RobotAPI/libraries/skills/core/ProviderInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec12cb9ae684323f2142cf3d433c02a2c4af42f1 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/ProviderInfo.cpp @@ -0,0 +1,26 @@ +#include "ProviderInfo.h" + +namespace armarx +{ + namespace skills + { + ProviderInfo::ProviderInfo(const ProviderID& pid, + const provider::dti::SkillProviderInterfacePrx& i, + const std::map<SkillID, SkillDescription>& skills) : + providerId(pid), provider(i), providedSkills(skills) + { + } + + ProviderInfo + ProviderInfo::FromIce(const manager::dto::ProviderInfo& i) + { + std::map<SkillID, SkillDescription> m; + for (const auto& [k, v] : i.providedSkills) + { + m.insert({skills::SkillID::FromIce(k, i.providerId.providerName), + skills::SkillDescription::FromIce(v)}); + } + return ProviderInfo(skills::ProviderID::FromIce(i.providerId), i.provider, m); + } + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/ProviderInfo.h b/source/RobotAPI/libraries/skills/core/ProviderInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..2213d1615819256242c05d50207d4dae5001c8e7 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/ProviderInfo.h @@ -0,0 +1,34 @@ +#pragma once + +#include <string> +#include <vector> + +#include <SimoxUtility/algorithm/string.h> + +#include <RobotAPI/interface/skills/SkillManagerInterface.h> + +#include "ProviderID.h" +#include "SkillDescription.h" +#include "SkillID.h" +#include "error/Exception.h" + +namespace armarx +{ + namespace skills + { + class ProviderInfo + { + public: + ProviderID providerId; + provider::dti::SkillProviderInterfacePrx provider; + std::map<SkillID, SkillDescription> providedSkills; + + ProviderInfo() = delete; + ProviderInfo(const ProviderID& pid, + const provider::dti::SkillProviderInterfacePrx& i, + const std::map<SkillID, SkillDescription>& skills); + + static ProviderInfo FromIce(const manager::dto::ProviderInfo&); + }; + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/Skill.cpp b/source/RobotAPI/libraries/skills/core/Skill.cpp index ba48923e7beab1876c6477d04845d05ce64883b9..e104ef656072cc0dd536a0ef3a8f924c2c0280ec 100644 --- a/source/RobotAPI/libraries/skills/core/Skill.cpp +++ b/source/RobotAPI/libraries/skills/core/Skill.cpp @@ -4,110 +4,79 @@ namespace armarx { namespace skills { - Skill::Skill(const SkillDescription& desc): - description(desc) + Skill::Skill(const SkillDescription& desc) : description(desc) { // replace constructor if you want to have a specific logging tag - Logging::setTag("armarx::skills::" + description.skillName); + Logging::setTag("armarx::skills::" + description.skillId.toString()); } // install a local condition via a lambda - void Skill::installConditionWithCallback(std::function<bool()>&& f, std::function<void()>&& cb) + void + Skill::installConditionWithCallback(std::function<bool()>&& f, std::function<void()>&& cb) { - std::lock_guard l(callbacksMutex); - callbacks.push_back({f, cb}); + std::lock_guard l(conditionCallbacksMutex); + conditionCallbacks.push_back({f, cb}); } - bool Skill::isSkillAvailable(const InitInput &in) const - { - return this->isAvailable(in); - } - - bool Skill::isAvailable(const InitInput& in) const - { - (void) in; - return true; - } - - void Skill::resetSkill() - { - //ARMARX_IMPORTANT << "Resetting skill '" << description.skillName << "'"; - - // resetting log times - started = armarx::core::time::DateTime::Invalid(); - exited = armarx::core::time::DateTime::Invalid(); - - // resetting master running variable - running = false; - - // resetting conditional variables - stopped = false; - timeoutReached = false; - - this->reset(); - } - - void Skill::waitForDependenciesOfSkill() - { - //ARMARX_IMPORTANT << "Waiting for dependencies of skill '" << description.skillName << "'"; - this->waitForDependencies(); - } - - void Skill::_init() + void + Skill::_init() { //ARMARX_IMPORTANT << "Initializing skill '" << description.skillName << "'"; - callbacks.clear(); + conditionCallbacks.clear(); running = true; started = armarx::core::time::DateTime::Now(); // install timeout condition installConditionWithCallback( - [&](){ return (armarx::core::time::DateTime::Now() >= (started + description.timeout)); }, - [&](){ notifyTimeoutReached(); } - ); + [&]() { + return (armarx::core::time::DateTime::Now() >= (started + description.timeout)); + }, + [&]() { notifyTimeoutReached(); }); - conditionCheckingThread = std::thread([&]() - { - armarx::core::time::Metronome metronome(conditionCheckingThreadFrequency); - while (running) // when the skill ends/aborts this variable will be set to false + conditionCheckingThread = std::thread( + [&]() { + armarx::core::time::Metronome metronome(conditionCheckingThreadFrequency); + while (running) // when the skill ends/aborts this variable will be set to false { - std::scoped_lock l(callbacksMutex); - for (auto& p : callbacks) { - auto& f = p.first; - auto& cb = p.second; - if (f()) + std::scoped_lock l(conditionCallbacksMutex); + for (auto& p : conditionCallbacks) { - cb(); + auto& f = p.first; + auto& cb = p.second; + if (f()) + { + cb(); + } } } + const auto sleepDuration = metronome.waitForNextTick(); + if (not sleepDuration.isPositive()) + { + ARMARX_WARNING + << deactivateSpam() << "PeriodicSkill: execution took too long (" + << -sleepDuration << " vs " + << conditionCheckingThreadFrequency.toCycleDuration() << ")"; + } } - const auto sleepDuration = metronome.waitForNextTick(); - if (not sleepDuration.isPositive()) - { - ARMARX_WARNING << deactivateSpam() << "PeriodicSkill: execution took too long (" << -sleepDuration << " vs " << conditionCheckingThreadFrequency.toCycleDuration() << ")"; - } - } - }); - } - Skill::InitResult Skill::initSkill(const InitInput& in) - { - this->_init(); - return this->init(in); + }); } - void Skill::_main() + void + Skill::_prepare() { // Nothing here yet... } - Skill::MainResult Skill::mainOfSkill(const MainInput& in) + + void + Skill::_main() { - this->_main(); - return this->main(in); + // Nothing here yet... } - void Skill::_exit() + void + Skill::_exit() { // ARMARX_IMPORTANT << "Exiting Skill '" << description.skillName << "'"; running = false; // stop checking conditions @@ -118,20 +87,51 @@ namespace armarx } exited = armarx::core::time::DateTime::Now(); } - Skill::ExitResult Skill::exitSkill(const ExitInput& in) + + Skill::InitResult + Skill::initSkill() + { + this->_init(); + return this->init(); + } + + bool + Skill::skillPreparationFinished() const + { + return this->preparationFinished(); + } + + Skill::PrepareResult + Skill::prepareSkill() { - auto ret = this->exit(in); + this->_prepare(); + return this->prepare(); + } + + Skill::MainResult + Skill::mainOfSkill() + { + this->_main(); + return this->main(); + } + + Skill::ExitResult + Skill::exitSkill() + { + auto ret = this->exit(); this->_exit(); return ret; } - void Skill::notifyTimeoutReached() + void + Skill::notifyTimeoutReached() { timeoutReached = true; onTimeoutReached(); } - Skill::MainResult Skill::MakeAbortedResult(aron::data::DictPtr data) + Skill::MainResult + Skill::MakeAbortedResult(aron::data::DictPtr data) { return MainResult{ .status = TerminatedSkillStatus::Aborted, @@ -139,65 +139,81 @@ namespace armarx }; } - void Skill::notifySkillToStopASAP() + void + Skill::notifySkillToStopASAP() { stopped = true; onStopRequested(); } - bool Skill::checkWhetherSkillShouldStopASAP() const + bool + Skill::checkWhetherSkillShouldStopASAP() const { return stopped || timeoutReached; } // condition effects - void Skill::onTimeoutReached() + void + Skill::onTimeoutReached() { } - void Skill::onStopRequested() + + void + Skill::onStopRequested() { } - // reset all local variables - void Skill::reset() + // always called before prepare (should not take longer than 100ms) + Skill::InitResult + Skill::init() { - // Default nothing to reset + // Default nothing to init + return {.status = TerminatedSkillStatus::Succeeded}; } - // Wait if needed - void Skill::waitForDependencies() + bool + Skill::preparationFinished() const { - // Default wait for nothing + std::scoped_lock l(parametersMutex); + if (description.acceptedType != nullptr) + { + if (this->parameters != nullptr) + { + // wait until parameters fulfill type + return this->parameters->fullfillsType(description.acceptedType); + } + + // false if we have to wait for parameters + return false; + } + + // always true if no type set. + return true; } - // always called before execute (should not take longer than 100ms) - Skill::InitResult Skill::init(const InitInput&) + // always called before main (should not take longer than 100ms) + Skill::PrepareResult + Skill::prepare() { - // Default nothing to init - return {.status = TerminatedSkillStatus::Succeeded}; + // Default nothing to prepare + return {.status = ActiveOrTerminatedSkillStatus::Succeeded}; } - // always called after execute or if skill fails (should not take longer than 100ms) - Skill::ExitResult Skill::exit(const ExitInput&) + // always called after main or if skill fails (should not take longer than 100ms) + Skill::ExitResult + Skill::exit() { // Default nothing to exit return {.status = TerminatedSkillStatus::Succeeded}; } - Skill::MainResult Skill::main(const MainInput& in) + Skill::MainResult + Skill::main() { // This is just a dummy implementation - ARMARX_IMPORTANT << "Dummy executing skill '" << description.skillName << "'. Please overwrite this method."; + ARMARX_IMPORTANT << "Dummy executing skill '" << description.skillId + << "'. Please overwrite this method."; return {.status = TerminatedSkillStatus::Succeeded, .data = nullptr}; } - - Skill::MainResult Skill::executeFullSkill(const MainInput& in) - { - this->resetSkill(); - this->initSkill(InitInput{.executorName = in.executorName, .params = in.params}); - auto ret = this->mainOfSkill(in); - this->exitSkill(ExitInput{.executorName = in.executorName, .params = in.params}); - return ret; - } - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/Skill.h b/source/RobotAPI/libraries/skills/core/Skill.h index bfba4d4cce7c37a880ea93b919373bdd3e126402..30f1f666e59a8f86421299aa30025b16fcbb7411 100644 --- a/source/RobotAPI/libraries/skills/core/Skill.h +++ b/source/RobotAPI/libraries/skills/core/Skill.h @@ -1,10 +1,10 @@ #pragma once // std/stl +#include <functional> #include <mutex> #include <queue> #include <thread> -#include <functional> // base class #include <ArmarXCore/core/logging/Logging.h> @@ -16,11 +16,11 @@ #include <RobotAPI/interface/skills/SkillManagerInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> -#include "../error/Exception.h" - +#include "SkillDescription.h" #include "SkillID.h" +#include "SkillPreparationInput.h" #include "SkillStatusUpdate.h" -#include "SkillDescription.h" +#include "error/Exception.h" namespace armarx { @@ -36,17 +36,9 @@ namespace armarx TerminatedSkillStatus status; }; - struct InitInput - { - std::string executorName; - aron::data::DictPtr params; - }; - - struct MainInput + struct PrepareResult { - std::string executorName; - aron::data::DictPtr params; - CallbackT callback; + ActiveOrTerminatedSkillStatus status; }; struct MainResult @@ -60,41 +52,26 @@ namespace armarx TerminatedSkillStatus status; }; - struct ExitInput - { - std::string executorName; - aron::data::DictPtr params; - }; - Skill() = delete; Skill(const SkillDescription&); virtual ~Skill() = default; /// The id of the skill (combination of provider and name must be unique). - SkillID getSkillId() const + SkillID + getSkillId() const { - return {providerName, description.skillName}; + return {providerName, description.skillId.providerName}; } - // Non virtual base methods. They internally call the virtual methods - // Lifecycle of a skill: - // 1. check if it is available - bool isSkillAvailable(const InitInput& in) const; + PrepareResult prepareSkill(); - // 2. reset skill - void resetSkill(); + bool skillPreparationFinished() const; - // 3. Set skill scheduled. Wait for dependencies - void waitForDependenciesOfSkill(); + InitResult initSkill(); - // 4. All dependencies resolved. Init skill - InitResult initSkill(const InitInput& in); + MainResult mainOfSkill(); - // 5. Execute main function of skill - MainResult mainOfSkill(const MainInput& in); - - // 6. Exit skill. This method is called in any case once the skill is scheduled. - ExitResult exitSkill(const ExitInput& in); + ExitResult exitSkill(); // Condition listeners // used to notify the skill from extern to stop @@ -103,8 +80,28 @@ namespace armarx // returns whether the skill should terminate as soon as possible bool checkWhetherSkillShouldStopASAP() const; - /// Do init, main, exit together - MainResult executeFullSkill(const MainInput& in); + // merge parameters to the local parameters of the skill + void + addParameters(const aron::data::DictPtr& d) + { + std::scoped_lock l(this->parametersMutex); + if (this->parameters == nullptr) + { + this->parameters = d; + } + else + { + this->parameters->mergeAndReplaceCopy(d); + } + } + + // get the parameters + aron::data::DictPtr + getParameters() const + { + std::scoped_lock l(this->parametersMutex); + return this->parameters; + } protected: static MainResult MakeAbortedResult(aron::data::DictPtr data = nullptr); @@ -114,27 +111,25 @@ namespace armarx // helper methods to do all the static initialization stuff void _init(); + void _prepare(); void _main(); void _exit(); private: - /// Override if your skill can be unavailable. It receives the same input as the init method - virtual bool isAvailable(const InitInput& in) const; - - /// Override if you have special members that needs to be resetted. It is called before the skill ititializes - virtual void reset(); - - /// Override if you have special dependencies you have to wait for - virtual void waitForDependencies(); + /// Override this method with the actual implementation. + virtual InitResult init(); /// Override this method with the actual implementation. - virtual InitResult init(const InitInput& in); + virtual PrepareResult prepare(); + + /// Override this method with the actual implementation + virtual bool preparationFinished() const; /// Override this method with the actual implementation. The callback is for status updates to the calling instance - virtual MainResult main(const MainInput& in); + virtual MainResult main(); /// Override this method with the actual implementation. - virtual ExitResult exit(const ExitInput& in); + virtual ExitResult exit(); /// Override these methods if you want to do something special when notification comes virtual void onTimeoutReached(); @@ -142,35 +137,49 @@ namespace armarx protected: /// install a condition which is frequently checked from the conditionCheckingThread - void installConditionWithCallback(std::function<bool()>&& f, std::function<void()>&& cb); + void installConditionWithCallback(std::function<bool()>&& f, + std::function<void()>&& cb); public: - /// The descripion of the skill, which will be available via the provider/manager + // The descripion of the skill, which will be available via the provider/manager const SkillDescription description; - /// running params + // running params armarx::core::time::DateTime started = armarx::core::time::DateTime::Invalid(); armarx::core::time::DateTime exited = armarx::core::time::DateTime::Invalid(); - /// proxy that called the skills. Will be set from provider and is const afterwards + // parameterization.Will be set from implementation wrapper. + // const params after initialization + std::function<void(const SkillStatus s, const armarx::aron::data::DictPtr&)> callback; manager::dti::SkillManagerInterfacePrx manager = nullptr; - - /// the provider that owns this skill. Will be set from provider and is const afterwards std::string providerName = "INVALID PROVIDER NAME"; + std::string executorName = "INVALID EXECUTOR NAME"; + + // non-const params + mutable std::mutex parametersMutex; + armarx::aron::data::DictPtr parameters; protected: - /// active conditions. First is condition (bool return func) - std::vector<std::pair<std::function<bool()>, std::function<void()>>> callbacks; - mutable std::mutex callbacksMutex; + // active conditions. First is condition (bool return func) + mutable std::mutex conditionCallbacksMutex; + std::vector<std::pair<std::function<bool()>, std::function<void()>>> conditionCallbacks; + /// Use conditions this way + std::atomic_bool initializing = false; + std::atomic_bool preparing = false; std::atomic_bool running = false; std::atomic_bool stopped = false; std::atomic_bool timeoutReached = false; + private: std::thread conditionCheckingThread; // A therad that checks the conditions frequently armarx::Frequency conditionCheckingThreadFrequency = armarx::Frequency::Hertz(20); }; - } -} + + template <class T> + concept isSkill = std::is_base_of<Skill, T>::value; + + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillDescription.cpp b/source/RobotAPI/libraries/skills/core/SkillDescription.cpp index 3fec65dd9e1d1edf405202c3aaa0bc6df89392ad..fb5f6f0622b8aeec861087d8040b18a2c62b6b5c 100644 --- a/source/RobotAPI/libraries/skills/core/SkillDescription.cpp +++ b/source/RobotAPI/libraries/skills/core/SkillDescription.cpp @@ -1,20 +1,34 @@ #include "SkillDescription.h" #include <ArmarXCore/core/ice_conversions.h> +#include <ArmarXCore/core/time/ice_conversions.h> namespace armarx { namespace skills { - provider::dto::SkillProfile - SkillProfile::toIce() const + // provider::dto::SkillProfile + // SkillProfile::toIce() const + // { + // provider::dto::SkillProfile ret; + // ret.profileName = profileName; + // ret.predecessorProfileName = predecessorProfileName; + // ret.parameterization = parameterization->toAronDictDTO(); + // return ret; + // } + + SkillDescription::SkillDescription(const SkillID& id, + const std::string& desc, + const aron::data::DictPtr& data, + const armarx::core::time::Duration& timeout, + const aron::type::ObjectPtr& acceptedType) : + skillId(id), + description(desc), + rootProfileParameterization(data), + timeout(timeout), + acceptedType(acceptedType) { - provider::dto::SkillProfile ret; - ret.profileName = profileName; - ret.predecessorProfileName = predecessorProfileName; - ret.parameterization = parameterization->toAronDictDTO(); - return ret; } provider::dto::SkillDescription @@ -23,13 +37,24 @@ namespace armarx provider::dto::SkillDescription ret; ret.acceptedType = aron::type::Object::ToAronObjectDTO(acceptedType); ret.description = description; - ret.skillName = skillName; - for (const auto& [key, p] : profiles) - { - ret.profiles[key] = p.toIce(); - } - ret.timeoutMs = timeout.toMilliSeconds(); + ret.skillId = skillId.toProviderIce(); + ret.rootProfileDefaults = rootProfileParameterization->toAronDictDTO(); + + armarx::core::time::toIce(ret.timeout, timeout); return ret; } + + SkillDescription + SkillDescription::FromIce(const provider::dto::SkillDescription& i) + { + armarx::core::time::Duration _d; + armarx::core::time::fromIce(i.timeout, _d); + return SkillDescription( + SkillID::FromIce(i.skillId), + i.description, + armarx::aron::data::Dict::FromAronDictDTO(i.rootProfileDefaults), + _d, + armarx::aron::type::Object::FromAronObjectDTO(i.acceptedType)); + } } // namespace skills } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillDescription.h b/source/RobotAPI/libraries/skills/core/SkillDescription.h index 42dbd46e8661fb1c1e23e223139835e2524b8fb0..e1e5b4fcf5f44280aef624c8a9d78521b9b87e6f 100644 --- a/source/RobotAPI/libraries/skills/core/SkillDescription.h +++ b/source/RobotAPI/libraries/skills/core/SkillDescription.h @@ -9,33 +9,44 @@ #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> #include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> +#include "SkillID.h" + namespace armarx { namespace skills { - struct SkillProfile - { - static const constexpr char* ROOT_PROFILE_NAME = "root"; - static const constexpr char* NO_PREDECESSOR = ""; + // struct SkillProfile + // { + // static const constexpr char* ROOT_PROFILE_NAME = "root"; + // static const constexpr char* NO_PREDECESSOR = ""; - std::string profileName = ROOT_PROFILE_NAME; - std::string predecessorProfileName = ""; - aron::data::DictPtr parameterization = nullptr; + // std::string profileName = ROOT_PROFILE_NAME; + // std::string predecessorProfileName = ""; + // aron::data::DictPtr parameterization = nullptr; - provider::dto::SkillProfile toIce() const; - }; + // provider::dto::SkillProfile toIce() const; + // }; struct SkillDescription { - static const constexpr char* SKILL_NOT_INITIALIZED = "NOT INITIALIZED YET"; + SkillDescription() = delete; + SkillDescription(const SkillID& id, + const std::string& desc, + const aron::data::DictPtr& data = nullptr, + const armarx::core::time::Duration& timeout = + armarx::core::time::Duration::MilliSeconds(-1), + const aron::type::ObjectPtr& acceptedType = nullptr); - std::string skillName = SKILL_NOT_INITIALIZED; - std::string description = SKILL_NOT_INITIALIZED; - std::map<std::string, SkillProfile> profiles = {}; - armarx::core::time::Duration timeout = armarx::core::time::Duration::MilliSeconds(-1); - aron::type::ObjectPtr acceptedType = nullptr; + + SkillID skillId; + std::string description; + aron::data::DictPtr rootProfileParameterization; + armarx::core::time::Duration timeout; + aron::type::ObjectPtr acceptedType; provider::dto::SkillDescription toIce() const; + + static SkillDescription FromIce(const provider::dto::SkillDescription& i); }; } // namespace skills } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp b/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3efb06d9e50e1d55bccf238e282d20366c4f7298 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp @@ -0,0 +1,52 @@ +#include "SkillExecutionID.h" + +namespace armarx +{ + namespace skills + { + SkillExecutionId::SkillExecutionId(const SkillID& id, + const std::string& executorName, + const armarx::core::time::DateTime& time) : + skillId(id), executorName(executorName), executionStartedTime(time) + { + } + + skills::manager::dto::SkillExecutionID + SkillExecutionId::toManagerIce() 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::toProviderIce() const + { + skills::provider::dto::SkillExecutionID ret; + ret.skillId = skillId.toProviderIce(); + ret.executorName = executorName; + armarx::core::time::toIce(ret.executionStartedTime, executionStartedTime); + return ret; + } + + SkillExecutionId + SkillExecutionId::FromIce(const skills::manager::dto::SkillExecutionID& i) + { + armarx::core::time::DateTime t; + armarx::core::time::fromIce(i.executionStartedTime, t); + return {skills::SkillID::FromIce(i.skillId), i.executorName, t}; + } + + SkillExecutionId + SkillExecutionId::FromIce(const skills::provider::dto::SkillExecutionID& i, + const std::string& providerName) + { + armarx::core::time::DateTime t; + armarx::core::time::fromIce(i.executionStartedTime, t); + return {skills::SkillID::FromIce(i.skillId, providerName), i.executorName, t}; + } + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h new file mode 100644 index 0000000000000000000000000000000000000000..356aec6116b10e9b5ce9c686d01201364a9619b5 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h @@ -0,0 +1,66 @@ +#pragma once + +#include <string> +#include <vector> + +#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" + +namespace armarx +{ + namespace skills + { + struct SkillExecutionId + { + SkillID skillId; + std::string executorName; + armarx::core::time::DateTime executionStartedTime; + + SkillExecutionId() = delete; + SkillExecutionId(const SkillID&, + const std::string& executorName, + const armarx::core::time::DateTime&); + + 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 toManagerIce() const; + + skills::provider::dto::SkillExecutionID toProviderIce() const; + + static SkillExecutionId FromIce(const skills::manager::dto::SkillExecutionID&); + + static SkillExecutionId FromIce(const skills::provider::dto::SkillExecutionID&, + const std::string& providerName); + }; + + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.cpp b/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d045cc2395b8863de8a3352b25969dff78ed191f --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.cpp @@ -0,0 +1,56 @@ +#include "SkillExecutionRequest.h" + +namespace armarx +{ + namespace skills + { + SkillExecutionRequest::SkillExecutionRequest( + const skills::SkillID& skill, + const std::string executorName, + const armarx::aron::data::DictPtr& params, + const callback::dti::SkillProviderCallbackInterfacePrx& callback) : + skillId(skill), executorName(executorName), params(params), callbackInterface(callback) + { + } + + manager::dto::SkillExecutionRequest + SkillExecutionRequest::toManagerIce() const + { + manager::dto::SkillExecutionRequest ret; + ret.skillId = skillId.toManagerIce(); + ret.executorName = executorName; + ret.params = params->toAronDictDTO(); + return ret; + } + + provider::dto::SkillExecutionRequest + SkillExecutionRequest::toProviderIce() const + { + provider::dto::SkillExecutionRequest ret; + ret.skillId = skillId.toProviderIce(); + ret.executorName = executorName; + ret.params = params->toAronDictDTO(); + ret.callbackInterface = callbackInterface; + return ret; + } + + SkillExecutionRequest + SkillExecutionRequest::FromIce(const manager::dto::SkillExecutionRequest& req) + { + return {skills::SkillID::FromIce(req.skillId), + req.executorName, + armarx::aron::data::Dict::FromAronDictDTO(req.params), + nullptr}; + } + + SkillExecutionRequest + SkillExecutionRequest::FromIce(const provider::dto::SkillExecutionRequest& req) + { + return {skills::SkillID::FromIce(req.skillId), + req.executorName, + armarx::aron::data::Dict::FromAronDictDTO(req.params), + req.callbackInterface}; + } + + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.h b/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.h new file mode 100644 index 0000000000000000000000000000000000000000..ec39e2f44d2faab47932abd89e878ff9996dafc0 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionRequest.h @@ -0,0 +1,43 @@ +#pragma once + +#include <string> +#include <vector> + +#include <SimoxUtility/algorithm/string.h> + +#include <ArmarXCore/core/time/DateTime.h> +#include <ArmarXCore/core/time/ice_conversions.h> + +#include <RobotAPI/interface/skills/SkillManagerInterface.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include "SkillID.h" +#include "error/Exception.h" + +namespace armarx +{ + namespace skills + { + class SkillExecutionRequest + { + public: + skills::SkillID skillId; + std::string executorName; + armarx::aron::data::DictPtr params; + callback::dti::SkillProviderCallbackInterfacePrx callbackInterface; + + SkillExecutionRequest() = delete; + SkillExecutionRequest(const skills::SkillID& skill, + const std::string executorName, + const armarx::aron::data::DictPtr& params, + const callback::dti::SkillProviderCallbackInterfacePrx& callback); + + manager::dto::SkillExecutionRequest toManagerIce() const; + provider::dto::SkillExecutionRequest toProviderIce() const; + + static SkillExecutionRequest FromIce(const manager::dto::SkillExecutionRequest&); + static SkillExecutionRequest + FromIce(const provider::dto::SkillExecutionRequest&); + }; + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillID.cpp b/source/RobotAPI/libraries/skills/core/SkillID.cpp similarity index 76% rename from source/RobotAPI/libraries/skills/provider/SkillID.cpp rename to source/RobotAPI/libraries/skills/core/SkillID.cpp index a384261f876673b680d8bd102a1439ef05744fcb..80373376a4438af2143b4c0ecc395a3ca67f5da9 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillID.cpp +++ b/source/RobotAPI/libraries/skills/core/SkillID.cpp @@ -4,6 +4,10 @@ namespace armarx { namespace skills { + SkillID::SkillID(const std::string& skillName) : SkillID(NOT_YET_KNOWN, skillName) + { + } + SkillID::SkillID(const std::string& providerName, const std::string& skillName) : providerName(providerName), skillName(skillName) { @@ -44,12 +48,30 @@ namespace armarx return toString() < other.toString(); } + SkillID + SkillID::FromIce(const manager::dto::SkillID& s) + { + return SkillID(s.providerName, s.skillName); + } + + SkillID + SkillID::FromIce(const provider::dto::SkillID& s, const std::string& providerName) + { + return SkillID(providerName, s.skillName); + } + manager::dto::SkillID - SkillID::toIce() const + SkillID::toManagerIce() const { return {providerName, skillName}; } + provider::dto::SkillID + SkillID::toProviderIce() const + { + return {skillName}; + } + std::string SkillID::toString(const std::string& prefix) const { diff --git a/source/RobotAPI/libraries/skills/provider/SkillID.h b/source/RobotAPI/libraries/skills/core/SkillID.h similarity index 65% rename from source/RobotAPI/libraries/skills/provider/SkillID.h rename to source/RobotAPI/libraries/skills/core/SkillID.h index 3eb1fd6f4dac0d7fdb9e2d7b258a968f548e8a14..a65765f0cb6336c732b22f3c2b323fce6d32cbe3 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillID.h +++ b/source/RobotAPI/libraries/skills/core/SkillID.h @@ -6,9 +6,8 @@ #include <SimoxUtility/algorithm/string.h> #include <RobotAPI/interface/skills/SkillManagerInterface.h> -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -#include "../error/Exception.h" +#include "error/Exception.h" namespace armarx { @@ -19,18 +18,26 @@ namespace armarx public: static const constexpr char* PREFIX_SEPARATOR = "->"; static const constexpr char* NAME_SEPARATOR = "/"; + static const constexpr char* NOT_YET_KNOWN = "NOT YET KNOWN"; std::string providerName; std::string skillName; SkillID() = delete; + SkillID(const std::string& skillName); 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; - manager::dto::SkillID toIce() const; + manager::dto::SkillID toManagerIce() const; + provider::dto::SkillID toProviderIce() const; + + static SkillID FromIce(const manager::dto::SkillID&); + static SkillID FromIce(const provider::dto::SkillID&, + const std::string& providerName = NOT_YET_KNOWN); + std::string toString(const std::string& prefix = "") const; }; diff --git a/source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp b/source/RobotAPI/libraries/skills/core/SkillParameterization.cpp similarity index 100% rename from source/RobotAPI/libraries/skills/provider/SkillParameterization.cpp rename to source/RobotAPI/libraries/skills/core/SkillParameterization.cpp diff --git a/source/RobotAPI/libraries/skills/core/SkillParameterization.h b/source/RobotAPI/libraries/skills/core/SkillParameterization.h new file mode 100644 index 0000000000000000000000000000000000000000..5358eafa7591ad2ea7331b65427f0be062d1d194 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillParameterization.h @@ -0,0 +1,34 @@ +#pragma once + +#include <string> +#include <vector> + +#include <RobotAPI/interface/skills/SkillProviderInterface.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +namespace armarx +{ + namespace skills + { + struct SkillParameterization + { + SkillParameterization() = delete; + + SkillParameterization(const aron::data::DictPtr& params, + const callback::dti::SkillProviderCallbackInterfacePrx& i) : + parameterization(params), callbackInterface(i) + { + } + + static SkillParameterization + FromIce(const armarx::aron::data::dto::DictPtr& params, + const callback::dti::SkillProviderCallbackInterfacePrx& i) + { + return SkillParameterization(armarx::aron::data::Dict::FromAronDictDTO(params), i); + } + + aron::data::DictPtr parameterization; + callback::dti::SkillProviderCallbackInterfacePrx callbackInterface; + }; + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillPreparationInput.cpp b/source/RobotAPI/libraries/skills/core/SkillPreparationInput.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0ec681e2b772aa773a6cc890198e24c28714207 --- /dev/null +++ b/source/RobotAPI/libraries/skills/core/SkillPreparationInput.cpp @@ -0,0 +1,8 @@ +#include "SkillParameterization.h" + +namespace armarx +{ + namespace skills + { + } +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillParameterization.h b/source/RobotAPI/libraries/skills/core/SkillPreparationInput.h similarity index 56% rename from source/RobotAPI/libraries/skills/provider/SkillParameterization.h rename to source/RobotAPI/libraries/skills/core/SkillPreparationInput.h index 65261a5cb939f72b69ea46c1807e52640752c9cb..b5cc2bb20c392864ccb31607e1ef02e9174fb211 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillParameterization.h +++ b/source/RobotAPI/libraries/skills/core/SkillPreparationInput.h @@ -10,10 +10,6 @@ namespace armarx { namespace skills { - struct SkillParameterization - { - aron::data::DictPtr usedInputParams = nullptr; - callback::dti::SkillProviderCallbackInterfacePrx usedCallbackInterface = nullptr; - }; + } // namespace skills } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp b/source/RobotAPI/libraries/skills/core/SkillStatusUpdate.cpp similarity index 58% rename from source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp rename to source/RobotAPI/libraries/skills/core/SkillStatusUpdate.cpp index 8a7ac2ab532bb0d0817e1894ae2565014f1940fa..df5950ac34a0a724d7464801aaef5f37d3743134 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.cpp +++ b/source/RobotAPI/libraries/skills/core/SkillStatusUpdate.cpp @@ -41,11 +41,14 @@ namespace armarx { switch (status) { - case SkillStatus::Idle: - ret = provider::dto::Execution::Status::Idle; + case SkillStatus::Constructing: + ret = provider::dto::Execution::Status::Constructing; return; - case SkillStatus::Scheduled: - ret = provider::dto::Execution::Status::Scheduled; + case SkillStatus::Initializing: + ret = provider::dto::Execution::Status::Initializing; + return; + case SkillStatus::Preparing: + ret = provider::dto::Execution::Status::Preparing; return; case SkillStatus::Running: ret = provider::dto::Execution::Status::Running; @@ -107,9 +110,11 @@ namespace armarx { switch (status) { - case provider::dto::Execution::Status::Idle: + case provider::dto::Execution::Status::Constructing: + [[fallthrough]]; + case provider::dto::Execution::Status::Initializing: [[fallthrough]]; - case provider::dto::Execution::Status::Scheduled: + case provider::dto::Execution::Status::Preparing: [[fallthrough]]; case provider::dto::Execution::Status::Running: break; @@ -133,9 +138,11 @@ namespace armarx { switch (status) { - case provider::dto::Execution::Status::Idle: + case provider::dto::Execution::Status::Constructing: [[fallthrough]]; - case provider::dto::Execution::Status::Scheduled: + case provider::dto::Execution::Status::Initializing: + [[fallthrough]]; + case provider::dto::Execution::Status::Preparing: break; case provider::dto::Execution::Status::Running: ret = ActiveOrTerminatedSkillStatus::Running; @@ -160,11 +167,14 @@ namespace armarx { switch (status) { - case provider::dto::Execution::Status::Idle: - ret = SkillStatus::Idle; + case provider::dto::Execution::Status::Constructing: + ret = SkillStatus::Constructing; + return; + case provider::dto::Execution::Status::Initializing: + ret = SkillStatus::Initializing; return; - case provider::dto::Execution::Status::Scheduled: - ret = SkillStatus::Scheduled; + case provider::dto::Execution::Status::Preparing: + ret = SkillStatus::Preparing; return; case provider::dto::Execution::Status::Running: ret = SkillStatus::Running; @@ -182,189 +192,98 @@ namespace armarx 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); - } - - void - SkillExecutionId::fromIce(const skills::provider::dto::SkillExecutionID& i, - const std::string& providerName) - { - 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) + SkillStatusUpdateBase::SkillStatusUpdateBase(const SkillExecutionId& exec, + const SkillParameterization& param) : + executionId(exec), usedParameterization(param) { - 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 + SkillStatusUpdateBase::toManagerIce() const { manager::dto::SkillStatusUpdate ret; - ret.header.executionId.skillId = executionId.skillId.toIce(); + ret.header.executionId.skillId = executionId.skillId.toManagerIce(); 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; + aron::data::Dict::ToAronDictDTO(usedParameterization.parameterization); + ret.header.usedCallbackInterface = usedParameterization.callbackInterface; ret.data = aron::data::Dict::ToAronDictDTO(data); return ret; } provider::dto::SkillStatusUpdate - SkillStatusUpdateBase::toIceProviderView() const + SkillStatusUpdateBase::toProviderIce() const { provider::dto::SkillStatusUpdate ret; - ret.header.executionId.skillName = executionId.skillId.skillName; + ret.header.executionId.skillId = executionId.skillId.toProviderIce(); 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; + aron::data::Dict::ToAronDictDTO(usedParameterization.parameterization); + ret.header.usedCallbackInterface = usedParameterization.callbackInterface; 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 + TerminatedSkillStatusUpdate::toManagerIce() const { - manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toManagerIce(); skills::toIce(ret.header.status, status); return ret; } provider::dto::SkillStatusUpdate - TerminatedSkillStatusUpdate::toIceProviderView() const + TerminatedSkillStatusUpdate::toProviderIce() const { - provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toProviderIce(); skills::toIce(ret.header.status, status); return ret; } manager::dto::SkillStatusUpdate - SkillStatusUpdate::toIce() const + SkillStatusUpdate::toManagerIce() const { - manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toManagerIce(); skills::toIce(ret.header.status, status); return ret; } provider::dto::SkillStatusUpdate - SkillStatusUpdate::toIceProviderView() const + SkillStatusUpdate::toProviderIce() const { - provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toProviderIce(); skills::toIce(ret.header.status, status); return ret; } manager::dto::SkillStatusUpdate - ActiveOrTerminatedSkillStatusUpdate::toIce() const + ActiveOrTerminatedSkillStatusUpdate::toManagerIce() const { - manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIce(); + manager::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toManagerIce(); skills::toIce(ret.header.status, status); return ret; } provider::dto::SkillStatusUpdate - ActiveOrTerminatedSkillStatusUpdate::toIceProviderView() const + ActiveOrTerminatedSkillStatusUpdate::toProviderIce() const { - provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toIceProviderView(); + provider::dto::SkillStatusUpdate ret = SkillStatusUpdateBase::toProviderIce(); 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); + TerminatedSkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); return ret; } @@ -372,31 +291,22 @@ namespace armarx TerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, const std::string& providerName) { - TerminatedSkillStatusUpdate ret; - ret.fromIce(update, providerName); + TerminatedSkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId, providerName), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); return ret; } - 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); + SkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); return ret; } @@ -404,31 +314,22 @@ namespace armarx SkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, const std::string& providerName) { - SkillStatusUpdate ret; - ret.fromIce(update, providerName); + SkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId, providerName), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); 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); + ActiveOrTerminatedSkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); return ret; } @@ -436,8 +337,11 @@ namespace armarx ActiveOrTerminatedSkillStatusUpdate::FromIce(const provider::dto::SkillStatusUpdate& update, const std::string& providerName) { - ActiveOrTerminatedSkillStatusUpdate ret; - ret.fromIce(update, providerName); + ActiveOrTerminatedSkillStatusUpdate ret( + skills::SkillExecutionId::FromIce(update.header.executionId, providerName), + skills::SkillParameterization::FromIce(update.header.usedParams, + update.header.usedCallbackInterface)); + skills::fromIce(update.header.status, ret.status); return ret; } } // namespace skills diff --git a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h b/source/RobotAPI/libraries/skills/core/SkillStatusUpdate.h similarity index 54% rename from source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h rename to source/RobotAPI/libraries/skills/core/SkillStatusUpdate.h index 7c83877df3ef4c046df3e4991ec9b61da1805cab..536a169f620062f461aa0e11577de4cd6106ac84 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillStatusUpdate.h +++ b/source/RobotAPI/libraries/skills/core/SkillStatusUpdate.h @@ -9,6 +9,7 @@ #include <RobotAPI/interface/skills/SkillProviderInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> +#include "SkillExecutionID.h" #include "SkillID.h" #include "SkillParameterization.h" @@ -18,12 +19,13 @@ namespace armarx { enum class SkillStatus { - Idle = 0, - Scheduled = 1, - Running = 2, - Failed = 4, - Succeeded = 8, - Aborted = 16 + Constructing = 0, + Initializing = 1, + Preparing = 2, + Running = 4, + Failed = 8, + Succeeded = 16, + Aborted = 32 }; enum class ActiveOrTerminatedSkillStatus @@ -54,71 +56,21 @@ namespace armarx 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 SkillExecutionId executionId; SkillParameterization usedParameterization; + SkillStatusUpdateBase() = delete; + SkillStatusUpdateBase(const SkillExecutionId& exec, const SkillParameterization& param); + // data aron::data::DictPtr data = nullptr; - manager::dto::SkillStatusUpdate toIce() const; - - provider::dto::SkillStatusUpdate toIceProviderView() const; + manager::dto::SkillStatusUpdate toManagerIce() const; - void fromIce(const provider::dto::SkillStatusUpdate& update, - const std::string& providerName); - - void fromIce(const manager::dto::SkillStatusUpdate& update); + provider::dto::SkillStatusUpdate toProviderIce() const; }; // Will be returned after the execution of a skill @@ -126,20 +78,17 @@ namespace armarx { TerminatedSkillStatus status = TerminatedSkillStatus::Failed; + using SkillStatusUpdateBase::SkillStatusUpdateBase; + bool hasBeenTerminated() const { return true; } - manager::dto::SkillStatusUpdate toIce() const; - - provider::dto::SkillStatusUpdate toIceProviderView() const; + manager::dto::SkillStatusUpdate toManagerIce() const; - void fromIce(const provider::dto::SkillStatusUpdate& update, - const std::string& providerName); - - void fromIce(const manager::dto::SkillStatusUpdate& update); + provider::dto::SkillStatusUpdate toProviderIce() const; static TerminatedSkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update, @@ -154,6 +103,8 @@ namespace armarx { ActiveOrTerminatedSkillStatus status = ActiveOrTerminatedSkillStatus::Failed; + using SkillStatusUpdateBase::SkillStatusUpdateBase; + bool hasBeenTerminated() const { @@ -162,14 +113,9 @@ namespace armarx status == ActiveOrTerminatedSkillStatus::Aborted; } - manager::dto::SkillStatusUpdate toIce() const; - - provider::dto::SkillStatusUpdate toIceProviderView() const; + manager::dto::SkillStatusUpdate toManagerIce() const; - void fromIce(const provider::dto::SkillStatusUpdate& update, - const std::string& providerName); - - void fromIce(const manager::dto::SkillStatusUpdate& update); + provider::dto::SkillStatusUpdate toProviderIce() const; static ActiveOrTerminatedSkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update, @@ -182,18 +128,32 @@ namespace armarx // Will be used as status updates from skills to the callback interface struct SkillStatusUpdate : public SkillStatusUpdateBase { - SkillStatus status = SkillStatus::Idle; + SkillStatus status = SkillStatus::Constructing; + + using SkillStatusUpdateBase::SkillStatusUpdateBase; bool - hasBeenScheduled() const + hasBeenConstructed() const { - return status == SkillStatus::Scheduled || hasBeenRunning(); + return status != SkillStatus::Constructing; + } + + bool + hasBeenInitialized() const + { + return status != SkillStatus::Initializing && hasBeenConstructed(); + } + + bool + hasBeenPrepared() const + { + return status != SkillStatus::Preparing && hasBeenInitialized(); } bool hasBeenRunning() const { - return status == SkillStatus::Running || hasBeenTerminated(); + return status != SkillStatus::Running || hasBeenPrepared(); } bool @@ -203,14 +163,9 @@ namespace armarx status == SkillStatus::Aborted; } - manager::dto::SkillStatusUpdate toIce() const; - - provider::dto::SkillStatusUpdate toIceProviderView() const; - - void fromIce(const provider::dto::SkillStatusUpdate& update, - const std::string& providerName); + manager::dto::SkillStatusUpdate toManagerIce() const; - void fromIce(const manager::dto::SkillStatusUpdate& update); + provider::dto::SkillStatusUpdate toProviderIce() const; static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate& update, const std::string& providerName); diff --git a/source/RobotAPI/libraries/skills/core/SpecializedSkill.h b/source/RobotAPI/libraries/skills/core/SpecializedSkill.h deleted file mode 100644 index 3f2b9371e2b087b4a5da77fb06e898bca525c320..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/skills/core/SpecializedSkill.h +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -#include "Skill.h" - -#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> - -// Debug -#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> - -namespace armarx -{ - namespace skills - { - template <class AronT> - class SpecializedSkill : public Skill - { - public: - using ParamType = AronT; - - struct SpecializedInitInput - { - std::string executorName; - AronT params; - }; - - struct SpecializedMainInput - { - std::string executorName; - AronT params; - CallbackT callback; - }; - - struct SpecializedExitInput - { - std::string executorName; - AronT params; - }; - - using Skill::Skill; - virtual ~SpecializedSkill() = default; - - /// returns the accepted type of the skill - static armarx::aron::type::ObjectPtr GetAcceptedType() - { - return AronT::ToAronType(); - } - - bool isSkillAvailable(const SpecializedInitInput& in) const - { - return this->isAvailable(); - } - - Skill::InitResult initSkill(const SpecializedInitInput& in) - { - Skill::_init(); - return this->init(in); - } - Skill::MainResult mainOfSkill(const SpecializedMainInput& in) - { - Skill::_main(); - return this->main(in); - } - Skill::ExitResult exitSkill(const SpecializedExitInput& in) - { - Skill::_exit(); - return this->exit(in); - } - - Skill::MainResult executeFullSkill(const SpecializedMainInput& in) - { - this->resetSkill(); - this->initSkill(SpecializedInitInput({.executorName = in.executorName, .params = in.params})); - auto ret = this->mainOfSkill(in); - this->exit(SpecializedExitInput({.executorName = in.executorName, .params = in.params})); - return ret; - } - - private: - /// Override this method if you want to disable a skill based on certain conditions - virtual bool isAvailable(const SpecializedInitInput&) const - { - return true; - } - - /// Override this method with the actual implementation. The callback is for status updates to the calling instance - virtual Skill::InitResult init(const SpecializedInitInput&) - { - return InitResult{.status = TerminatedSkillStatus::Succeeded}; - } - - /// Override this method with the actual implementation. The callback is for status updates to the calling instance - virtual Skill::MainResult main(const SpecializedMainInput& in) - { - ARMARX_IMPORTANT << "Dummy executing skill '" << description.skillName << "'. Please overwrite this method."; - return Skill::MainResult{.status = TerminatedSkillStatus::Succeeded, .data = nullptr}; - } - - /// Override this method with the actual implementation. The callback is for status updates to the calling instance - virtual Skill::ExitResult exit(const SpecializedExitInput&) - { - return ExitResult{.status = TerminatedSkillStatus::Succeeded}; - } - - /// Do not use anymore - bool isAvailable(const InitInput& in) const final - { - AronT p; - p.fromAron(in.params); - - return isAvailable(SpecializedInitInput({.executorName = in.executorName, .params = p})); - } - - /// Do not use anymore - Skill::InitResult init(const InitInput& in) final - { - AronT p; - p.fromAron(in.params); - - return init(SpecializedInitInput({.executorName = in.executorName, .params = p})); - } - - /// Do not use anymore - Skill::MainResult main(const MainInput& in) final - { - AronT p; - p.fromAron(in.params); - - return main(SpecializedMainInput({.executorName = in.executorName, .params = p, .callback = in.callback})); - } - - /// Do not use anymore - Skill::ExitResult exit(const ExitInput& in) final - { - AronT p; - p.fromAron(in.params); - - return exit(SpecializedExitInput({.executorName = in.executorName, .params = p})); - } - }; - } -} diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp index 5fbc2e925f5461514d4bec656762920935600ec3..057715f98f5f316fb6c6fd7e84b4fa096ddf766c 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp @@ -4,9 +4,9 @@ #include <ArmarXCore/core/time/DateTime.h> #include <ArmarXCore/core/time/ice_conversions.h> -#include <RobotAPI/libraries/skills/error/Exception.h> -#include <RobotAPI/libraries/skills/provider/SkillID.h> -#include <RobotAPI/libraries/skills/provider/SkillStatusUpdate.h> +#include <RobotAPI/libraries/skills/core/SkillID.h> +#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h> +#include <RobotAPI/libraries/skills/core/error/Exception.h> namespace armarx::plugins { @@ -24,155 +24,206 @@ namespace armarx::plugins SkillManagerComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) { } -} // namespace armarx::plugins -namespace armarx -{ - SkillManagerComponentPluginUser::SkillManagerComponentPluginUser() + skills::ProviderID + SkillManagerComponentPlugin::getFirstProviderNameThatHasSkill(const skills::SkillID& skillId) { - addPlugin(plugin); + // NON LOCKING! WE ASSERT THAT THE CALLER HOLDS LOCK + for (const auto& [providerName, providerPrx] : skillProviderMap) + { + auto allSkills = providerPrx->getSkillDescriptions(); + for (const auto& [currentSkillID, skillDesc] : allSkills) + { + if (currentSkillID.skillName == skillId.skillName) + { + return {providerName}; + } + } + } + return {"INVALID PROVIDER NAME"}; } void - SkillManagerComponentPluginUser::addProvider(const skills::manager::dto::ProviderInfo& info, - const Ice::Current&) + SkillManagerComponentPlugin::addProvider(const skills::ProviderInfo& info) { - std::lock_guard l(skillProviderMapMutex); - if (skillProviderMap.find(info.providerName) == skillProviderMap.end()) + std::scoped_lock l(skillProviderMapMutex); + if (skillProviderMap.find(info.providerId.providerName) == skillProviderMap.end()) { - ARMARX_INFO << "Adding a provider with name '" << info.providerName << "'."; - skillProviderMap.insert({info.providerName, info.provider}); + ARMARX_INFO << "Adding a provider with name '" << info.providerId.providerName << "'."; + skillProviderMap.insert({info.providerId.providerName, info.provider}); } else { - ARMARX_INFO << "Trying to add a provider with name '" << info.providerName + ARMARX_INFO << "Trying to add a provider with name '" << info.providerId.providerName << "' but the provider already exists. " << "Overwriting the old provider info."; - skillProviderMap[info.providerName] = info.provider; + skillProviderMap[info.providerId.providerName] = info.provider; } } void - SkillManagerComponentPluginUser::removeProvider(const std::string& providerName, - const Ice::Current&) + SkillManagerComponentPlugin::removeProvider(const skills::ProviderID& id) { - std::lock_guard l(skillProviderMapMutex); - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + std::scoped_lock l(skillProviderMapMutex); + if (auto it = skillProviderMap.find(id.providerName); it != skillProviderMap.end()) { - ARMARX_INFO << "Removing a provider with name '" << providerName << "'."; + ARMARX_INFO << "Removing a provider with name '" << id.providerName << "'."; skillProviderMap.erase(it); } else { - ARMARX_INFO << "Trying to remove a provider with name '" << providerName + ARMARX_INFO << "Trying to remove a provider with name '" << id.providerName << "' but it couldn't be found."; } } - std::string - SkillManagerComponentPluginUser::getFirstProviderNameThatHasSkill(const std::string& skillName) + skills::SkillStatusUpdate + SkillManagerComponentPlugin::executeSkill( + const skills::SkillExecutionRequest& req, + const skills::callback::dti::SkillProviderCallbackInterfacePrx& myPrx) { - // NON LOCKING! WE ASSERT THAT THE CALLER HOLDS LOCK - for (const auto& [providerName, providerPrx] : skillProviderMap) + std::unique_lock l(skillProviderMapMutex); + + skills::ProviderID provderId("INVALID PROVIDER NAME"); + + // TODO: Really support regexes! + if (req.skillId.providerName == "*") { - auto allSkills = providerPrx->getSkillDescriptions(); - for (const auto& [currentSkillName, skillDesc] : allSkills) + provderId = getFirstProviderNameThatHasSkill(req.skillId.skillName); + } + else if (not(req.skillId.providerName.empty())) + { + provderId = skills::ProviderID(req.skillId); + } + + + if (auto it = skillProviderMap.find(provderId); it != skillProviderMap.end()) + { + const auto& provider = it->second; + + if (!provider) { - if (currentSkillName == skillName) - { - return providerName; - } + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" + << provderId << "'. Removing it from skills."; + skillProviderMap.erase(it); + + throw skills::error::SkillException( + __PRETTY_FUNCTION__, + "Skill execution failed. Could not execute a skill of provider '" + + provderId.toString() + "' because the provider does not exist."); } + + try + { + skills::SkillExecutionRequest exInfo( + req.skillId, req.executorName, req.params, myPrx); + + auto async = provider->begin_executeSkill(exInfo.toProviderIce()); + l.unlock(); // allow parallel e.g. stopping + auto up = provider->end_executeSkill(async); + + // convert to manager view + return skills::SkillStatusUpdate::FromIce(up, provderId.providerName); + } + catch (...) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ + << ": Found disconnected or buggy skill provider '" << provderId + << "' during execution. Removing it from skills."; + skillProviderMap.erase(it); + + throw skills::error::SkillException( + __PRETTY_FUNCTION__, + "Skill execution failed. Could not execute a skill of provider '" + + provderId.toString() + "' because the provider does not exist."); + } + } + else + { + throw skills::error::SkillException( + __PRETTY_FUNCTION__, + "Skill execution failed. Could not execute a skill of provider '" + + provderId.toString() + "' because the provider does not exist."); } - return "INVALID PROVIDER NAME"; } - using SkillProviderInterfacePrxMap = - std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx>; - - skills::manager::dto::SkillStatusUpdate - SkillManagerComponentPluginUser::executeSkill( - const skills::manager::dto::SkillExecutionRequest& info, - const Ice::Current&) + skills::SkillExecutionId + SkillManagerComponentPlugin::executeSkillAsync( + const skills::SkillExecutionRequest& req, + const skills::callback::dti::SkillProviderCallbackInterfacePrx& myPrx) { std::unique_lock l(skillProviderMapMutex); - std::string providerName = "INVALID PROVIDER NAME"; + skills::ProviderID provderId("INVALID PROVIDER NAME"); // TODO: Really support regexes! - if (info.skillId.providerName == "*") + if (req.skillId.providerName == "*") { - providerName = getFirstProviderNameThatHasSkill(info.skillId.skillName); + provderId = getFirstProviderNameThatHasSkill(req.skillId.skillName); } - else if (not(info.skillId.providerName.empty())) + else if (not(req.skillId.providerName.empty())) { - providerName = info.skillId.providerName; + provderId = req.skillId.providerName; } - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + if (auto it = skillProviderMap.find(provderId); it != skillProviderMap.end()) { const auto& provider = it->second; if (!provider) { ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << providerName << "'. Removing it from skills."; + << provderId << "'. 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."); + provderId.toString() + "' because the provider does not exist."); } try { - 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::SkillExecutionRequest exInfo( + req.skillId, req.executorName, req.params, myPrx); - auto async = provider->begin_executeSkill(exInfo); + auto async = provider->begin_executeSkillAsync(exInfo.toProviderIce()); l.unlock(); // allow parallel e.g. stopping - auto up = provider->end_executeSkill(async); + auto up = provider->end_executeSkillAsync(async); // convert to manager view - return skills::SkillStatusUpdate::FromIce(up, providerName).toIce(); + return skills::SkillExecutionId::FromIce(up, provderId.providerName); } catch (...) { ARMARX_WARNING << __PRETTY_FUNCTION__ - << ": Found disconnected or buggy skill provider '" << providerName + << ": Found disconnected or buggy skill provider '" << provderId << "' during execution. 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."); + provderId.toString() + "' because the provider does not exist."); } } else { throw skills::error::SkillException( __PRETTY_FUNCTION__, - "Skill execution failed. Could not execute a skill of provider '" + providerName + - "' because the provider does not exist."); + "Skill execution failed. Could not execute a skill of provider '" + + provderId.toString() + "' because the provider does not exist."); } } void - SkillManagerComponentPluginUser::abortSkill(const std::string& providerName, - const std::string& skillName, - const Ice::Current& current) + SkillManagerComponentPlugin::addSkillParameters(const skills::SkillExecutionId& id, + const aron::data::DictPtr& data) { std::unique_lock l(skillProviderMapMutex); - if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end()) + if (auto it = skillProviderMap.find(skills::ProviderID(id.skillId.providerName)); + it != skillProviderMap.end()) { const auto& providerName = it->first; const auto& provider = it->second; @@ -187,9 +238,10 @@ namespace armarx try { - auto async = provider->begin_abortSkill(skillName); + auto async = + provider->begin_addSkillParameters(id.toProviderIce(), data->toAronDictDTO()); l.unlock(); // allow parallel e.g. stopping - return provider->end_abortSkill(async); + return provider->end_addSkillParameters(async); } catch (...) { @@ -200,20 +252,40 @@ namespace armarx } void - SkillManagerComponentPluginUser::updateStatusForSkill( - const skills::provider::dto::SkillStatusUpdate& statusUpdate, - const std::string& providerName, - const Ice::Current&) + SkillManagerComponentPlugin::abortSkill(const skills::SkillExecutionId& id) { - (void)statusUpdate; - (void)providerName; - // If you want to use the status, implement this method! + std::unique_lock l(skillProviderMapMutex); + if (auto it = skillProviderMap.find(id.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); + return; + } + + try + { + auto async = provider->begin_abortSkill(id.toProviderIce()); + l.unlock(); // allow parallel e.g. stopping + return provider->end_abortSkill(async); + } + catch (...) + { + ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" + << providerName << "'. Removing it from skills on next execute."; + } + } } - skills::manager::dto::SkillDescriptionMapMap - SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current& current) + std::map<skills::SkillID, skills::SkillDescription> + SkillManagerComponentPlugin::getSkillDescriptions() { - skills::manager::dto::SkillDescriptionMapMap ret; + std::map<skills::SkillID, skills::SkillDescription> ret; std::scoped_lock l(skillProviderMapMutex); for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) @@ -232,7 +304,12 @@ namespace armarx try { skills::provider::dto::SkillDescriptionMap m = provider->getSkillDescriptions(); - ret.insert({providerName, m}); + + for (const auto& [k, v] : m) + { + ret.insert({skills::SkillID::FromIce(k), skills::SkillDescription::FromIce(v)}); + } + ++it; } catch (...) @@ -245,103 +322,223 @@ namespace armarx return ret; } - skills::manager::dto::SkillStatusUpdate - SkillManagerComponentPluginUser::getSkillExecutionStatus( - const skills::manager::dto::SkillExecutionID& executionId, - const Ice::Current& current) + std::optional<skills::SkillStatusUpdate> + SkillManagerComponentPlugin::getSkillExecutionStatus(const skills::SkillExecutionId& execId) { - 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& providerId = it->first; const auto& provider = it->second; if (!provider) { ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << providerName << "'. Removing it from skills."; + << providerId << "'. 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 + + providerId.toString() + "' because the provider does not exist."); } try { - auto async = provider->begin_getSkillExecutionStatus(execId.toIceProviderView()); + auto async = provider->begin_getSkillExecutionStatus(execId.toProviderIce()); l.unlock(); // allow parallel e.g. stopping auto up = provider->end_getSkillExecutionStatus(async); // convert to manager view - return skills::SkillStatusUpdate::FromIce(up, providerName).toIce(); + return skills::SkillStatusUpdate::FromIce(up, providerId.providerName); } catch (...) { ARMARX_WARNING << __PRETTY_FUNCTION__ - << ": Found disconnected or buggy skill provider '" << providerName + << ": Found disconnected or buggy skill provider '" << providerId << "' 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 + + providerId.toString() + "' because the provider does not exist."); } } else { - // no actove skill. Return idle - skills::SkillStatusUpdate idle; - idle.executionId = execId; - return idle.toIce(); + // no actove skill. Return null + return std::nullopt; } } - skills::manager::dto::SkillStatusUpdateList - SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& current) + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> + SkillManagerComponentPlugin::getSkillExecutionStatuses() { - skills::manager::dto::SkillStatusUpdateList ret; + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> ret; std::scoped_lock l(skillProviderMapMutex); for (auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();) { - const auto& providerName = it->first; + const auto& providerId = it->first; const auto& provider = it->second; if (!provider) { ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found disconnected skill provider '" - << providerName << "'. Removing it from skills."; + << providerId << "'. Removing it from skills."; it = skillProviderMap.erase(it); continue; } try { - skills::provider::dto::SkillStatusUpdateList m = - provider->getSkillExecutionStatuses(); + auto m = provider->getSkillExecutionStatuses(); - for (const auto& up : m) + for (const auto& [k, v] : m) { - // convert provider view to manager view - ret.push_back(skills::SkillStatusUpdate::FromIce(up, providerName).toIce()); + ret.insert({skills::SkillExecutionId::FromIce(k, providerId.providerName), + skills::SkillStatusUpdate::FromIce(v, providerId.providerName)}); } it++; } catch (...) { ARMARX_WARNING << __PRETTY_FUNCTION__ << ": Found buggy skill provider '" - << providerName << "'. Removing it from skills."; + << providerId << "'. Removing it from skills."; it = skillProviderMap.erase(it); } } return ret; } + +} // namespace armarx::plugins + +namespace armarx +{ + SkillManagerComponentPluginUser::SkillManagerComponentPluginUser() + { + addPlugin(plugin); + } + + void + SkillManagerComponentPluginUser::addProvider(const skills::manager::dto::ProviderInfo& info, + const Ice::Current&) + { + auto i = skills::ProviderInfo::FromIce(info); + this->plugin->addProvider(i); + } + + void + SkillManagerComponentPluginUser::removeProvider( + const skills::manager::dto::ProviderID& provider, + const Ice::Current&) + { + auto i = skills::ProviderID::FromIce(provider); + this->plugin->removeProvider(i); + } + + using SkillProviderInterfacePrxMap = + std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx>; + + skills::manager::dto::SkillStatusUpdate + SkillManagerComponentPluginUser::executeSkill( + const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current&) + { + skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; + getProxy(myPrx, -1); + + auto e = skills::SkillExecutionRequest::FromIce(info); + return this->plugin->executeSkill(e, myPrx).toManagerIce(); + } + + skills::manager::dto::SkillExecutionID + SkillManagerComponentPluginUser::executeSkillAsync( + const skills::manager::dto::SkillExecutionRequest& info, + const Ice::Current& current) + { + skills::callback::dti::SkillProviderCallbackInterfacePrx myPrx; + getProxy(myPrx, -1); + + auto e = skills::SkillExecutionRequest::FromIce(info); + return this->plugin->executeSkillAsync(e, myPrx).toManagerIce(); + } + + void + SkillManagerComponentPluginUser::addSkillParameters( + const skills::manager::dto::SkillExecutionID& info, + const aron::data::dto::DictPtr& params, + const Ice::Current& current) + { + auto a = armarx::aron::data::Dict::FromAronDictDTO(params); + auto e = skills::SkillExecutionId::FromIce(info); + this->plugin->addSkillParameters(e, a); + } + + void + SkillManagerComponentPluginUser::abortSkill(const skills::manager::dto::SkillExecutionID& id, + const Ice::Current& current) + { + auto i = skills::SkillExecutionId::FromIce(id); + this->plugin->abortSkill(i); + } + + void + SkillManagerComponentPluginUser::updateStatusForSkill( + const skills::provider::dto::SkillStatusUpdate& statusUpdate, + const skills::provider::dto::ProviderID& pid, + const Ice::Current&) + { + (void)statusUpdate; + (void)pid; + // If you want to use the status, implement this method! + } + + skills::manager::dto::SkillDescriptionMap + SkillManagerComponentPluginUser::getSkillDescriptions(const Ice::Current& current) + { + skills::manager::dto::SkillDescriptionMap ret; + + auto m = this->plugin->getSkillDescriptions(); + + for (const auto& [k, v] : m) + { + ret.insert({k.toManagerIce(), v.toIce()}); + } + + return ret; + } + + skills::manager::dto::SkillStatusUpdate + SkillManagerComponentPluginUser::getSkillExecutionStatus( + const skills::manager::dto::SkillExecutionID& executionId, + const Ice::Current& current) + { + auto e = skills::SkillExecutionId::FromIce(executionId); + auto o = this->plugin->getSkillExecutionStatus(e); + if (o.has_value()) + { + return o->toManagerIce(); + } + return {}; // TODO!! + } + + skills::manager::dto::SkillStatusUpdateMap + SkillManagerComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& current) + { + skills::manager::dto::SkillStatusUpdateMap ret; + + auto m = this->plugin->getSkillExecutionStatuses(); + + for (const auto& [k, v] : m) + { + ret.insert({k.toManagerIce(), v.toManagerIce()}); + } + + return ret; + } } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h index cd3a576dec2cb53ee419f29de5db6546ac66ea09..5aaadd6e6dc35038b0aaf1dbff259cdf934e88c8 100644 --- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h +++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.h @@ -6,6 +6,10 @@ #include <ArmarXCore/core/ManagedIceObject.h> #include <RobotAPI/interface/skills/SkillManagerInterface.h> +#include <RobotAPI/libraries/skills/core/ProviderID.h> +#include <RobotAPI/libraries/skills/core/ProviderInfo.h> +#include <RobotAPI/libraries/skills/core/SkillExecutionRequest.h> +#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h> namespace armarx::plugins { @@ -19,6 +23,37 @@ namespace armarx::plugins void preOnConnectComponent() override; void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; + + void addProvider(const skills::ProviderInfo& info); + + void removeProvider(const skills::ProviderID& id); + + skills::SkillStatusUpdate + executeSkill(const skills::SkillExecutionRequest& req, + const skills::callback::dti::SkillProviderCallbackInterfacePrx& prx); + + skills::SkillExecutionId + executeSkillAsync(const skills::SkillExecutionRequest& req, + const skills::callback::dti::SkillProviderCallbackInterfacePrx& prx); + + void addSkillParameters(const skills::SkillExecutionId& id, + const aron::data::DictPtr& data); + + void abortSkill(const skills::SkillExecutionId& id); + + std::map<skills::SkillID, skills::SkillDescription> getSkillDescriptions(); + + std::optional<skills::SkillStatusUpdate> + getSkillExecutionStatus(const skills::SkillExecutionId& id); + + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> getSkillExecutionStatuses(); + + skills::ProviderID getFirstProviderNameThatHasSkill(const skills::SkillID& skillid); + + protected: + std::mutex skillProviderMapMutex; + std::map<skills::ProviderID, skills::provider::dti::SkillProviderInterfacePrx> + skillProviderMap; }; } // namespace armarx::plugins @@ -33,36 +68,39 @@ namespace armarx void addProvider(const skills::manager::dto::ProviderInfo& providerInfo, const Ice::Current& current) override; - void removeProvider(const std::string&, const Ice::Current& current) override; + void removeProvider(const skills::manager::dto::ProviderID& provider, + const Ice::Current& current) override; skills::manager::dto::SkillStatusUpdate executeSkill(const skills::manager::dto::SkillExecutionRequest& info, const Ice::Current& current) override; + + skills::manager::dto::SkillExecutionID + executeSkillAsync(const skills::manager::dto::SkillExecutionRequest& skillExecutionRequest, + const Ice::Current& current) override; + + void addSkillParameters(const skills::manager::dto::SkillExecutionID& executionId, + const aron::data::dto::DictPtr& params, + const Ice::Current& current) override; + void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update, - const std::string& providerName, + const skills::provider::dto::ProviderID& id, const Ice::Current& current) override; - void abortSkill(const std::string& providerName, - const std::string& skillName, + + void abortSkill(const skills::manager::dto::SkillExecutionID& id, const Ice::Current& current) override; - skills::manager::dto::SkillDescriptionMapMap + skills::manager::dto::SkillDescriptionMap 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 + skills::manager::dto::SkillStatusUpdateMap getSkillExecutionStatuses(const Ice::Current& current) override; - protected: - std::string getFirstProviderNameThatHasSkill(const std::string& skillName); - private: armarx::plugins::SkillManagerComponentPlugin* plugin = nullptr; - - protected: - std::mutex skillProviderMapMutex; - std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx> skillProviderMap; }; } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/CMakeLists.txt b/source/RobotAPI/libraries/skills/provider/CMakeLists.txt index 46fae9591072d31c9d40e97728ed9c849c3ba0d4..4ba71803f991a7ba83aa1562299a08c1090f4587 100644 --- a/source/RobotAPI/libraries/skills/provider/CMakeLists.txt +++ b/source/RobotAPI/libraries/skills/provider/CMakeLists.txt @@ -17,19 +17,34 @@ armarx_add_library( SOURCES SkillProviderComponentPlugin.cpp - SkillStatusUpdate.cpp - SkillParameterization.cpp + SkillFactory.cpp LambdaSkill.cpp - SkillID.cpp + SkillProxy.cpp + PeriodicSkill.cpp + SpecializedSkill.cpp + PeriodicSpecializedSkill.cpp detail/SkillImplementationWrapper.cpp + SkillContext.cpp HEADERS SkillProviderComponentPlugin.h - SkillStatusUpdate.h - SkillParameterization.h + SkillFactory.h LambdaSkill.h - SkillID.h + SkillProxy.h + PeriodicSkill.h + SpecializedSkill.h + PeriodicSpecializedSkill.h detail/SkillImplementationWrapper.h + SkillContext.h + + mixins/All.h + mixins/ArvizSkillMixin.h + mixins/MNSSkillMixin.h + mixins/MemoryReadingSkillMixin.h + mixins/RobotReadingSkillMixin.h + mixins/ObjectReadingSkillMixin.h + mixins/ObjectWritingSkillMixin.h + mixins/GraspReadingSkillMixin.h ) add_library(RobotAPI::skills::provider ALIAS RobotAPISkillsProvider) diff --git a/source/RobotAPI/libraries/skills/provider/LambdaSkill.cpp b/source/RobotAPI/libraries/skills/provider/LambdaSkill.cpp index 280cdb93e5eb62413a159f232b20c5da0b7e3bd7..804042b8ac47b2b1c0ec762c87c4e4ce186daf97 100644 --- a/source/RobotAPI/libraries/skills/provider/LambdaSkill.cpp +++ b/source/RobotAPI/libraries/skills/provider/LambdaSkill.cpp @@ -5,11 +5,12 @@ namespace armarx namespace skills { - Skill::MainResult LambdaSkill::main(const MainInput& in) + Skill::MainResult + LambdaSkill::main() { - TerminatedSkillStatus res = fun(in.executorName, in.params); + TerminatedSkillStatus res = fun(); return {.status = res, .data = nullptr}; } - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/LambdaSkill.h b/source/RobotAPI/libraries/skills/provider/LambdaSkill.h index 01e3a3897e78b444c222b352556bea118f5bc50f..dda6c472c711f9cae1c3d6ac396218ef10f50ca5 100644 --- a/source/RobotAPI/libraries/skills/provider/LambdaSkill.h +++ b/source/RobotAPI/libraries/skills/provider/LambdaSkill.h @@ -1,6 +1,6 @@ #pragma once -#include "Skill.h" +#include <RobotAPI/libraries/skills/core/Skill.h> namespace armarx { @@ -9,19 +9,16 @@ namespace armarx class LambdaSkill : public Skill { public: - using FunT = std::function<TerminatedSkillStatus(const std::string clientId, const aron::data::DictPtr&)>; + using FunT = std::function<TerminatedSkillStatus()>; LambdaSkill() = delete; - LambdaSkill(const FunT& f, const SkillDescription& desc) : - Skill(desc), - fun(f) - {}; + LambdaSkill(const SkillDescription& desc, const FunT& f) : Skill(desc), fun(f){}; private: - MainResult main(const MainInput& in) override; + MainResult main() override; private: FunT fun; }; - } -} + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/PeriodicSkill.cpp b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp similarity index 81% rename from source/RobotAPI/libraries/skills/core/PeriodicSkill.cpp rename to source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp index 70daa959f0256646125c8477768f304db5555312..4df38fb17050ad444472327ae14dca744c559a3c 100644 --- a/source/RobotAPI/libraries/skills/core/PeriodicSkill.cpp +++ b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp @@ -26,27 +26,30 @@ #include "ArmarXCore/core/time/Frequency.h" #include <ArmarXCore/core/time/Metronome.h> -#include "RobotAPI/libraries/skills/provider/Skill.h" +#include "RobotAPI/libraries/skills/core/Skill.h" namespace armarx::skills { - PeriodicSkill::PeriodicSkill(const SkillDescription& skillDescription, const armarx::Frequency& frequency) : + PeriodicSkill::PeriodicSkill(const SkillDescription& skillDescription, + const armarx::Frequency& frequency) : Skill(skillDescription), frequency(frequency) { } - PeriodicSkill::StepResult PeriodicSkill::stepOfSkill(const MainInput& in) + PeriodicSkill::StepResult + PeriodicSkill::stepOfSkill() { - return this->step(in); + return this->step(); } - Skill::MainResult PeriodicSkill::main(const MainInput& in) + Skill::MainResult + PeriodicSkill::main() { core::time::Metronome metronome(frequency); while (not Skill::checkWhetherSkillShouldStopASAP()) { - const auto res = stepOfSkill(in); + const auto res = stepOfSkill(); switch (res.status) { case ActiveOrTerminatedSkillStatus::Running: @@ -63,7 +66,9 @@ namespace armarx::skills const auto sleepDuration = metronome.waitForNextTick(); if (not sleepDuration.isPositive()) { - ARMARX_INFO << deactivateSpam() << "PeriodicSkill: execution took too long (" << -sleepDuration << " too long. Expected " << frequency.toCycleDuration() << ")"; + ARMARX_INFO << deactivateSpam() << "PeriodicSkill: execution took too long (" + << -sleepDuration << " too long. Expected " + << frequency.toCycleDuration() << ")"; } } @@ -81,10 +86,11 @@ namespace armarx::skills throw skills::error::SkillException(__PRETTY_FUNCTION__, "Should not happen!"); } - - PeriodicSkill::StepResult PeriodicSkill::step(const MainInput& in) + PeriodicSkill::StepResult + PeriodicSkill::step() { - ARMARX_IMPORTANT << "Dummy executing once skill '" << description.skillName << "'. Please overwrite this method!"; + ARMARX_IMPORTANT << "Dummy executing once skill '" << description.skillId + << "'. Please overwrite this method!"; return {ActiveOrTerminatedSkillStatus::Succeeded, nullptr}; } diff --git a/source/RobotAPI/libraries/skills/core/PeriodicSkill.h b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.h similarity index 88% rename from source/RobotAPI/libraries/skills/core/PeriodicSkill.h rename to source/RobotAPI/libraries/skills/provider/PeriodicSkill.h index 5df6e07e9b7304b8e7c4db10141d3980f31a041c..60823be8cdd6881b02ca4cad905d2bc30908ae15 100644 --- a/source/RobotAPI/libraries/skills/core/PeriodicSkill.h +++ b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.h @@ -23,7 +23,8 @@ #include <ArmarXCore/core/time/Frequency.h> -#include "Skill.h" +#include <RobotAPI/libraries/skills/core/Skill.h> + #include "SpecializedSkill.h" namespace armarx::skills @@ -40,19 +41,18 @@ namespace armarx::skills PeriodicSkill(const SkillDescription& skillDescription, const armarx::Frequency& frequency); - StepResult stepOfSkill(const MainInput& in); + StepResult stepOfSkill(); private: /// Do not use anymore - Skill::MainResult main(const MainInput& in) final; + Skill::MainResult main() final; /// Override this method with your own step function - virtual StepResult step(const MainInput& in); + virtual StepResult step(); private: const armarx::Frequency frequency; }; - } // namespace armarx::skills diff --git a/source/RobotAPI/libraries/skills/core/PeriodicSpecializedSkill.cpp b/source/RobotAPI/libraries/skills/provider/PeriodicSpecializedSkill.cpp similarity index 100% rename from source/RobotAPI/libraries/skills/core/PeriodicSpecializedSkill.cpp rename to source/RobotAPI/libraries/skills/provider/PeriodicSpecializedSkill.cpp diff --git a/source/RobotAPI/libraries/skills/core/PeriodicSpecializedSkill.h b/source/RobotAPI/libraries/skills/provider/PeriodicSpecializedSkill.h similarity index 84% rename from source/RobotAPI/libraries/skills/core/PeriodicSpecializedSkill.h rename to source/RobotAPI/libraries/skills/provider/PeriodicSpecializedSkill.h index 4efac5d6d3ff33206063b928cd202e45476b0b63..83f9ae009d1245511d222240c0fc185a2aefea70 100644 --- a/source/RobotAPI/libraries/skills/core/PeriodicSpecializedSkill.h +++ b/source/RobotAPI/libraries/skills/provider/PeriodicSpecializedSkill.h @@ -24,7 +24,8 @@ #include <ArmarXCore/core/time/Frequency.h> #include <ArmarXCore/core/time/Metronome.h> -#include "Skill.h" +#include <RobotAPI/libraries/skills/core/Skill.h> + #include "PeriodicSkill.h" #include "SpecializedSkill.h" @@ -42,15 +43,17 @@ namespace armarx::skills using StepResult = PeriodicSkill::StepResult; PeriodicSpecializedSkill() = delete; - PeriodicSpecializedSkill(const SkillDescription& skillDescription, const armarx::Frequency& frequency) : + + PeriodicSpecializedSkill(const SkillDescription& skillDescription, + const armarx::Frequency& frequency) : Base(skillDescription), frequency(frequency) { } - - StepResult stepOfSkill(const typename Base::SpecializedMainInput& in) + StepResult + stepOfSkill() { - return this->step(in); + return this->step(); } private: @@ -58,13 +61,14 @@ namespace armarx::skills using Skill::timeoutReached; /// Do not use anymore - Skill::MainResult main(const typename Base::SpecializedMainInput& in) final + Skill::MainResult + main() final { core::time::Metronome metronome(frequency); while (not Skill::checkWhetherSkillShouldStopASAP()) { - const auto statusUpdate = stepOfSkill(in); + const auto statusUpdate = stepOfSkill(); switch (statusUpdate.status) { case ActiveOrTerminatedSkillStatus::Running: @@ -81,7 +85,9 @@ namespace armarx::skills const auto sleepDuration = metronome.waitForNextTick(); if (not sleepDuration.isPositive()) { - ARMARX_INFO << deactivateSpam() << "PeriodicSkill: execution took too long (" << -sleepDuration << " too long. Expected " << frequency.toCycleDuration() << ")"; + ARMARX_INFO << deactivateSpam() << "PeriodicSkill: execution took too long (" + << -sleepDuration << " too long. Expected " + << frequency.toCycleDuration() << ")"; } } @@ -100,9 +106,11 @@ namespace armarx::skills } /// Override this method with your own step function - virtual StepResult step(const typename Base::SpecializedMainInput& in) + virtual StepResult + step() { - ARMARX_IMPORTANT << "Dummy executing once skill '" << this->description.skillName << "'. Please overwrite this method!"; + ARMARX_IMPORTANT << "Dummy executing once skill '" << this->description.skillName + << "'. Please overwrite this method!"; return {ActiveOrTerminatedSkillStatus::Succeeded, nullptr}; } diff --git a/source/RobotAPI/libraries/skills/core/SkillContext.cpp b/source/RobotAPI/libraries/skills/provider/SkillContext.cpp similarity index 100% rename from source/RobotAPI/libraries/skills/core/SkillContext.cpp rename to source/RobotAPI/libraries/skills/provider/SkillContext.cpp diff --git a/source/RobotAPI/libraries/skills/core/SkillContext.h b/source/RobotAPI/libraries/skills/provider/SkillContext.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/SkillContext.h rename to source/RobotAPI/libraries/skills/provider/SkillContext.h diff --git a/source/RobotAPI/libraries/skills/provider/SkillFactory.cpp b/source/RobotAPI/libraries/skills/provider/SkillFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78ec9ef6d60dabdf1dab84964aa3722cec9256e5 --- /dev/null +++ b/source/RobotAPI/libraries/skills/provider/SkillFactory.cpp @@ -0,0 +1,6 @@ +#include "SkillFactory.h" + +namespace armarx +{ + +} diff --git a/source/RobotAPI/libraries/skills/provider/SkillFactory.h b/source/RobotAPI/libraries/skills/provider/SkillFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..eadb1bab9300ee5c0b527f8fa8095bc540ca55c1 --- /dev/null +++ b/source/RobotAPI/libraries/skills/provider/SkillFactory.h @@ -0,0 +1,90 @@ +#pragma once + +#include <tuple> + +#include <RobotAPI/libraries/skills/core/Skill.h> + +namespace armarx +{ + namespace skills + { + class SkillFactory + { + public: + using FunT = std::function<std::unique_ptr<Skill>()>; + + SkillFactory(const SkillDescription& id, const FunT& f) : fun(f), desc(id) + { + } + + template <class _Skill, class... Args> + requires isSkill<_Skill> + + static std::unique_ptr<SkillFactory> + ForSkill(const SkillDescription& id, Args&&... args) + + { + return std::make_unique<SkillFactory>( + id, [&]() { return std::make_unique<_Skill>(std::forward<Args>(args)...); }); + } + + + template <class _Skill, class... Args> + requires isSkill<_Skill> + + static std::unique_ptr<SkillFactory> + ForSkillDescriptionGetter(Args&&... args) + + { + return std::make_unique<SkillFactory>( + _Skill::GetSkillDescription(), + [&]() { return std::make_unique<_Skill>(std::forward<Args>(args)...); }); + } + + virtual std::unique_ptr<Skill> + createSkill() const + { + return fun(); + } + + const SkillDescription& + getSkillDescription() const + { + return desc; + } + + void + setOwner(const std::string& providerName) + { + ARMARX_CHECK(this->desc.skillId.providerName.empty()) + << "The owning provider of the factory for skill '" + << this->desc.skillId.skillName << "' was already set. This is not valid."; + this->desc.skillId.providerName = providerName; + } + + SkillID + getSkillID(const std::string& providerName) const + { + SkillID copy = getSkillID(); + copy.providerName = providerName; + return copy; + } + + const SkillID& + getSkillID() const + { + return desc.skillId; + } + + + protected: + FunT fun; + + SkillDescription desc; + }; + + template <class T> + concept isSkillFactory = std::is_base_of<SkillFactory, T>::value; + + } // namespace skills +} // namespace armarx diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp index 0e63d700d43c9aaba521a0aeb77181552a2ff2a2..3686ccb9fc32da8b6568644a6c8cb031bbb0391c 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp @@ -24,21 +24,12 @@ namespace armarx::plugins auto& p = parent<SkillProviderComponentPluginUser>(); const std::string providerName = p.getName(); - // update skill ownership - for (auto& [skillName, impl] : skillImplementations) - { - impl.skill->manager = manager; - impl.skill->providerName = providerName; - } - // register self to manager skills::manager::dto::ProviderInfo i; i.provider = myPrx; - i.providerName = providerName; + i.providerId = {providerName}; i.providedSkills = p.getSkillDescriptions(); - manager->addProvider(i); - - connected = true; + manager->addProvider(i); // add provider info to manager } void @@ -47,7 +38,8 @@ namespace armarx::plugins auto& p = parent<SkillProviderComponentPluginUser>(); std::string providerName = p.getName(); - manager->removeProvider(providerName); + auto id = skills::manager::dto::ProviderID{providerName}; + manager->removeProvider(id); } void @@ -62,82 +54,272 @@ namespace armarx::plugins } void - SkillProviderComponentPlugin::addSkill(const skills::LambdaSkill::FunT& f, - const skills::SkillDescription& desc) + SkillProviderComponentPlugin::addSkillFactory(const skills::LambdaSkill::FunT& f, + const skills::SkillDescription& desc) { - auto lambda = std::make_unique<skills::LambdaSkill>(f, desc); - addSkill(std::move(lambda)); + auto fac = skills::SkillFactory::ForSkill<skills::LambdaSkill>(desc, desc, f); + // std::make_unique<skills::SkillFactory>( + // desc, [&]() { return std::make_unique<skills::LambdaSkill>(f, desc); }); + addSkillFactory(std::move(fac)); } void - SkillProviderComponentPlugin::addSkill(std::unique_ptr<skills::Skill>&& skill) + SkillProviderComponentPlugin::addSkillFactory(std::unique_ptr<skills::SkillFactory>&& fac) { - if (!skill) + if (!fac) { return; } - std::string skillName = skill->description.skillName; + auto& p = parent<SkillProviderComponentPluginUser>(); + const std::string providerName = p.getName(); // lock skills map - const std::unique_lock l(skillImplementationsMapMutex); - if (skillImplementations.find(skillName) != skillImplementations.end()) + const std::unique_lock l(skillFactoriesMutex); + auto skillId = fac->getSkillID(providerName); + + if (skillFactories.find(skillId) != skillFactories.end()) { - ARMARX_WARNING << "Try to add a skill '" + skillName + + ARMARX_WARNING << "Try to add a skill factory for skill '" + skillId.toString() + "' which already exists in list. Ignoring this skill."; return; } - ARMARX_INFO << "Adding skill and set owning provider name `" << skillName << "`."; - auto s = skillImplementations.emplace(skillName, std::move(skill)); + ARMARX_INFO << "Adding skill `" << skillId << "` and set owning provider name to `" + << providerName << "` ."; + fac->setOwner(providerName); - 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; - } + skillFactories.emplace(fac->getSkillID(), std::move(fac)); + + // 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::SkillFactory* + SkillProviderComponentPlugin::getSkillFactory(const armarx::skills::SkillID& skill) + { + ARMARX_CHECK_GREATER(skillFactories.count(skill), 0) + << "Skill '" + skill.toString() + "' not found."; + + const std::unique_lock l(skillFactoriesMutex); + auto* facPtr = skillFactories.at(skill).get(); + return static_cast<skills::SkillFactory*>(facPtr); } - skills::detail::SkillImplementationWrapper& - SkillProviderComponentPlugin::getSkill(const std::string& name) + std::optional<skills::SkillStatusUpdate> + SkillProviderComponentPlugin::getSkillExecutionStatus( + const skills::SkillExecutionId& execId) const { - ARMARX_CHECK_GREATER(skillImplementations.count(name), 0) - << "Skill '" + name + "' not found."; - const std::unique_lock l(skillImplementationsMapMutex); - return skillImplementations.at(name); + const std::unique_lock l(skillExecutionsMutex); + if (skillExecutions.find(execId) != skillExecutions.end()) + { + ARMARX_WARNING << "Skill execution for skill '" + execId.skillId.toString() + + "' not found!"; + return std::nullopt; + } + + return skillExecutions.at(execId).statusUpdate; } - skills::provider::dto::SkillStatusUpdateList + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> SkillProviderComponentPlugin::getSkillExecutionStatuses() const { - skills::provider::dto::SkillStatusUpdateList skillUpdates; - const std::unique_lock l(skillImplementationsMapMutex); - for (const auto& [key, impl] : skillImplementations) + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> skillUpdates; + + const std::scoped_lock l(skillExecutionsMutex); + for (const auto& [key, impl] : skillExecutions) { - const std::shared_lock l2(impl.skillStatusesMutex); - for (const auto& [execId, up] : impl.statusUpdates) - { - (void)execId; - skillUpdates.push_back(up.toIceProviderView()); - } + const std::scoped_lock l2(impl.skillStatusesMutex); + skillUpdates.insert({key, impl.statusUpdate}); } return skillUpdates; } - skills::provider::dto::SkillDescriptionMap + std::optional<skills::SkillDescription> + SkillProviderComponentPlugin::getSkillDescription(const skills::SkillID& skillId) const + { + const std::unique_lock l(skillFactoriesMutex); + if (skillFactories.find(skillId) != skillFactories.end()) + { + ARMARX_WARNING << "Skill description for skill '" + skillId.toString() + "' not found!"; + return std::nullopt; + } + + return skillFactories.at(skillId)->getSkillDescription(); + } + + std::map<skills::SkillID, skills::SkillDescription> SkillProviderComponentPlugin::getSkillDescriptions() const { - skills::provider::dto::SkillDescriptionMap skillDesciptions; - const std::unique_lock l(skillImplementationsMapMutex); - for (const auto& [key, impl] : skillImplementations) + std::map<skills::SkillID, skills::SkillDescription> skillDesciptions; + const std::unique_lock l(skillFactoriesMutex); + for (const auto& [key, fac] : skillFactories) { - skillDesciptions.insert({key, impl.skill->description.toIce()}); + skillDesciptions.insert({key, fac->getSkillDescription()}); } return skillDesciptions; } + skills::SkillStatusUpdate + SkillProviderComponentPlugin::executeSkill(const skills::SkillExecutionRequest& executionInfo) + { + // The skill will be executed in a seperate thread + std::thread execution; + + // setup input args for skill execution + skills::SkillParameterization usedParameterization{executionInfo.params, + executionInfo.callbackInterface}; + + skills::SkillExecutionId execId( + executionInfo.skillId, executionInfo.executorName, armarx::core::time::DateTime::Now()); + + skills::SkillStatusUpdate ret{execId, usedParameterization}; + { + auto l1 = std::unique_lock{skillFactoriesMutex}; + + const auto& id = executionInfo.skillId; + const auto& fac = getSkillFactory(id); + + // async start execution. But we wait for the execution to finish at the end of this method + execution = std::thread( + [&]() + { + skills::detail::SkillImplementationWrapper* wrapper; + { + const std::unique_lock l2{skillExecutionsMutex}; + auto it = skillExecutions.emplace( + std::piecewise_construct, + std::make_tuple(execId), + std::make_tuple(fac, execId, usedParameterization)); + + ARMARX_CHECK(it.second) + << "For some reason a skill '" << execId.skillId.toString() + << "' execution failed when instantiating the " + "wrapper class and adding it to the internally used map. This " + "should " + "not happen!!"; + + wrapper = &it.first->second; + } + + + // execute waits until the previous execution finishes. + auto x = wrapper->executeSkill(); + ret.data = x.data; + ret.status = armarx::skills::toSkillStatus(x.status); + }); + } // 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 + + if (execution.joinable()) + { + execution.join(); + + // tidy up map of executions + const std::unique_lock l2{skillExecutionsMutex}; + if (auto it = skillExecutions.find(execId); it != skillExecutions.end()) + { + skillExecutions.erase(it); + } + } + return ret; + } + + skills::SkillExecutionId + SkillProviderComponentPlugin::executeSkillAsync( + const skills::SkillExecutionRequest& executionInfo) + { + // The skill will be executed in a seperate thread + std::thread execution; + + // setup input args for skill execution + skills::SkillParameterization usedParameterization{executionInfo.params, + executionInfo.callbackInterface}; + + skills::SkillExecutionId execId( + executionInfo.skillId, executionInfo.executorName, armarx::core::time::DateTime::Now()); + + { + auto l1 = std::unique_lock{skillFactoriesMutex}; + + const auto& id = executionInfo.skillId; + const auto& fac = getSkillFactory(id); + + // async start execution. But we wait for the execution to finish at the end of this method + execution = std::thread( + [&]() + { + skills::detail::SkillImplementationWrapper* wrapper; + { + const std::unique_lock l2{skillExecutionsMutex}; + auto it = skillExecutions.emplace( + std::piecewise_construct, + std::make_tuple(execId), + std::make_tuple(fac, execId, usedParameterization)); + + ARMARX_CHECK(it.second) + << "For some reason a skill '" << execId.skillId.toString() + << "' execution failed when instantiating the " + "wrapper class and adding it to the internally used map. This " + "should " + "not happen!!"; + + wrapper = &it.first->second; + } + + + // execute waits until the previous execution finishes. + auto x = wrapper->executeSkill(); + }); + } // 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 + + execution.detach(); + return execId; + } + + void + SkillProviderComponentPlugin::addSkillParameters(const skills::SkillExecutionId& id, + const armarx::aron::data::DictPtr& input) + { + const std::scoped_lock l{skillExecutionsMutex}; + auto it = skillExecutions.find(id); + if (it == skillExecutions.end()) + { + ARMARX_INFO << "No acive execution for skill '" + id.skillId.toString() + + "' found! Ignoring prepareSkill request."; + return; + } + + std::scoped_lock l2{it->second.skillStatusesMutex}; + if (it->second.statusUpdate.status != skills::SkillStatus::Preparing) + { + ARMARX_INFO << "Could not prepare the skill '" + id.skillId.toString() + + "' because its not in preparing phase."; + return; + } + + it->second.addSkillParameters(input); + } + + void + SkillProviderComponentPlugin::abortSkill(const skills::SkillExecutionId& execId) + { + const std::unique_lock l(skillExecutionsMutex); + auto it = skillExecutions.find(execId); + if (it == skillExecutions.end()) + { + ARMARX_INFO << "No acive execution for skill '" + execId.skillId.toString() + + "' found! Ignoring abortSkill request."; + return; + } + + it->second.stopSkill(); + } + } // namespace armarx::plugins namespace armarx @@ -148,31 +330,36 @@ namespace armarx } void - SkillProviderComponentPluginUser::addSkill(std::unique_ptr<skills::Skill>&& skill) + SkillProviderComponentPluginUser::addSkillFactory(std::unique_ptr<skills::SkillFactory>&& skill) { - plugin->addSkill(std::move(skill)); + plugin->addSkillFactory(std::move(skill)); } void - SkillProviderComponentPluginUser::addSkill(const skills::LambdaSkill::FunT& f, - const skills::SkillDescription& desc) + SkillProviderComponentPluginUser::addSkillFactory(const skills::SkillDescription& desc, + const skills::LambdaSkill::FunT& f) { - plugin->addSkill(f, desc); + plugin->addSkillFactory(f, desc); } skills::provider::dto::SkillDescription - SkillProviderComponentPluginUser::getSkillDescription(const std::string& name, - const Ice::Current& /*unused*/) + SkillProviderComponentPluginUser::getSkillDescription( + const skills::provider::dto::SkillID& skillId, + const Ice::Current& /*unused*/) { - - const auto& skillWrapper = plugin->getSkill(name); - return skillWrapper.skill->description.toIce(); + auto id = skills::SkillID::FromIce(skillId, getName()); + return plugin->getSkillDescription(id)->toIce(); } skills::provider::dto::SkillDescriptionMap SkillProviderComponentPluginUser::getSkillDescriptions(const Ice::Current& /*unused*/) { - return plugin->getSkillDescriptions(); + skills::provider::dto::SkillDescriptionMap ret; + for (const auto& [k, v] : plugin->getSkillDescriptions()) + { + ret.insert({k.toProviderIce(), v.toIce()}); + } + return ret; } skills::provider::dto::SkillStatusUpdate @@ -181,27 +368,23 @@ namespace armarx const Ice::Current& /*unused*/) { auto execId = skills::SkillExecutionId::FromIce(executionId, getName()); - - auto& skillWrapper = plugin->getSkill(executionId.skillName); - - const std::shared_lock l(skillWrapper.skillStatusesMutex); - if (auto it = skillWrapper.statusUpdates.find(execId); - it != skillWrapper.statusUpdates.end()) - { - return it->second.toIceProviderView(); - } - else + auto o = plugin->getSkillExecutionStatus(execId); + if (o.has_value()) { - skills::SkillStatusUpdate idle; - idle.executionId = execId; - return idle.toIceProviderView(); + return o->toProviderIce(); } + return {}; // TODO!! } - skills::provider::dto::SkillStatusUpdateList + skills::provider::dto::SkillStatusUpdateMap SkillProviderComponentPluginUser::getSkillExecutionStatuses(const Ice::Current& /*unused*/) { - return plugin->getSkillExecutionStatuses(); + skills::provider::dto::SkillStatusUpdateMap ret; + for (const auto& [k, v] : plugin->getSkillExecutionStatuses()) + { + ret.insert({k.toProviderIce(), v.toProviderIce()}); + } + return ret; } // Please not that this method waits until the skill can be scheduled! @@ -210,42 +393,38 @@ namespace armarx const skills::provider::dto::SkillExecutionRequest& info, const Ice::Current& /*unused*/) { - // The skill will be executed in a seperate thread - std::thread execution; - - // setup input args for skill execution - skills::SkillParameterization usedParameterization; - usedParameterization.usedCallbackInterface = info.callbackInterface; - usedParameterization.usedInputParams = aron::data::Dict::FromAronDictDTO(info.params); - - skills::provider::dto::SkillStatusUpdate ret; - { - const std::string skillName = info.skillName; - auto& wrapper = plugin->getSkill(skillName); + auto exec = skills::SkillExecutionRequest::FromIce(info); + auto up = this->plugin->executeSkill(exec); + return up.toProviderIce(); + } - // async start execution. But we wait for the execution to finish at the end of this method - execution = std::thread( - [&ret, &wrapper, &info, &usedParameterization]() - { - // execute waits until the previous execution finishes. - auto x = wrapper.setupAndExecuteSkill(info.executorName, usedParameterization); - 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 + skills::provider::dto::SkillExecutionID + SkillProviderComponentPluginUser::executeSkillAsync( + const skills::provider::dto::SkillExecutionRequest& info, + const Ice::Current& current /*unused*/) + { + auto exec = skills::SkillExecutionRequest::FromIce(info); + auto id = this->plugin->executeSkillAsync(exec); + return id.toProviderIce(); + } - if (execution.joinable()) - { - execution.join(); - } - return ret; + void + SkillProviderComponentPluginUser::addSkillParameters( + const skills::provider::dto::SkillExecutionID& id, + const aron::data::dto::DictPtr& input, + const Ice::Current& current /*unused*/) + { + auto exec = skills::SkillExecutionId::FromIce(id, getName()); + auto prep = armarx::aron::data::Dict::FromAronDictDTO(input); + this->plugin->addSkillParameters(exec, prep); } void - SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, + SkillProviderComponentPluginUser::abortSkill(const skills::provider::dto::SkillExecutionID& id, const Ice::Current& /*unused*/) { - auto& wrapper = plugin->getSkill(skillName); - wrapper.skill->notifySkillToStopASAP(); + auto exec = skills::SkillExecutionId::FromIce(id, getName()); + this->plugin->abortSkill(exec); } const std::experimental::observer_ptr<plugins::SkillProviderComponentPlugin>& diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h index f4d3489fe9c9f235e9ad94a4d73d028b57a4d6e6..881b813c2f161a5593ae0ba0b90a30fe8be5d136 100644 --- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h +++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h @@ -15,10 +15,14 @@ #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> // Include all types of skills +#include <RobotAPI/libraries/skills/core/Skill.h> +#include <RobotAPI/libraries/skills/core/SkillExecutionRequest.h> +#include <RobotAPI/libraries/skills/core/SkillPreparationInput.h> + #include "LambdaSkill.h" #include "PeriodicSkill.h" #include "PeriodicSpecializedSkill.h" -#include "Skill.h" +#include "SkillFactory.h" #include "SpecializedSkill.h" // Helper wrapper for execution @@ -45,35 +49,51 @@ namespace armarx::plugins void preOnDisconnectComponent() override; - void addSkill(const skills::LambdaSkill::FunT&, const skills::SkillDescription&); - void addSkill(std::unique_ptr<skills::Skill>&&); + void addSkillFactory(const skills::LambdaSkill::FunT&, const skills::SkillDescription&); + void addSkillFactory(std::unique_ptr<skills::SkillFactory>&&); template <typename T, typename... Args> - T* - addSkill(Args&&... args) - { - static_assert(std::is_base_of<skills::Skill, T>::value, - "T must be derived from skills::Skill!"); - auto skill = std::make_unique<T>(std::forward<Args>(args)...); - auto* skillPtr = skill.get(); - addSkill(std::move(skill)); - return static_cast<T*>(skillPtr); + requires skills::isSkillFactory<T> T* + addSkillFactory(const skills::SkillID& id, Args&&... args) + { + auto fac = std::make_unique<T>(id, std::forward<Args>(args)...); + auto* facPtr = fac.get(); + addSkillFactory(std::move(fac)); + return static_cast<T*>(facPtr); } - skills::provider::dto::SkillStatusUpdateList getSkillExecutionStatuses() const; - skills::provider::dto::SkillDescriptionMap getSkillDescriptions() const; + // Ice forwards + std::optional<skills::SkillStatusUpdate> + getSkillExecutionStatus(const skills::SkillExecutionId&) const; + std::map<skills::SkillExecutionId, skills::SkillStatusUpdate> + getSkillExecutionStatuses() const; + + std::optional<skills::SkillDescription> getSkillDescription(const skills::SkillID&) const; + std::map<skills::SkillID, skills::SkillDescription> getSkillDescriptions() const; + + skills::SkillStatusUpdate executeSkill(const skills::SkillExecutionRequest& executionInfo); + + skills::SkillExecutionId + executeSkillAsync(const skills::SkillExecutionRequest& executionInfo); + + void addSkillParameters(const skills::SkillExecutionId& id, + const armarx::aron::data::DictPtr& params); + + void abortSkill(const skills::SkillExecutionId& execId); private: - skills::detail::SkillImplementationWrapper& getSkill(const std::string& name); + skills::SkillFactory* getSkillFactory(const armarx::skills::SkillID& name); skills::manager::dti::SkillManagerInterfacePrx manager; skills::provider::dti::SkillProviderInterfacePrx myPrx; - mutable std::mutex skillImplementationsMapMutex; + mutable std::mutex skillFactoriesMutex; + std::map<skills::SkillID, std::unique_ptr<skills::SkillFactory>> skillFactories; - bool connected = false; - std::map<std::string, skills::detail::SkillImplementationWrapper> skillImplementations; + mutable std::mutex skillExecutionsMutex; + std::map<skills::SkillExecutionId, skills::detail::SkillImplementationWrapper> + skillExecutions; friend class armarx::SkillProviderComponentPluginUser; }; @@ -88,35 +108,50 @@ namespace armarx public: SkillProviderComponentPluginUser(); + // Ice Implementations skills::provider::dto::SkillDescription - getSkillDescription(const std::string&, + getSkillDescription(const skills::provider::dto::SkillID& skill, const Ice::Current& current = Ice::Current()) override; + skills::provider::dto::SkillDescriptionMap getSkillDescriptions(const Ice::Current& current = Ice::Current()) override; + skills::provider::dto::SkillStatusUpdate getSkillExecutionStatus(const skills::provider::dto::SkillExecutionID& executionId, const Ice::Current& current = Ice::Current()) override; - skills::provider::dto::SkillStatusUpdateList + + skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses(const Ice::Current& current = Ice::Current()) override; skills::provider::dto::SkillStatusUpdate executeSkill(const skills::provider::dto::SkillExecutionRequest& executionInfo, const Ice::Current& current = Ice::Current()) override; - void abortSkill(const std::string& name, + + skills::provider::dto::SkillExecutionID + executeSkillAsync(const skills::provider::dto::SkillExecutionRequest& executionInfo, + const Ice::Current& current = Ice::Current()) override; + + void addSkillParameters(const skills::provider::dto::SkillExecutionID& executionId, + const armarx::aron::data::dto::DictPtr& input, + const Ice::Current& current = Ice::Current()) override; + + void abortSkill(const skills::provider::dto::SkillExecutionID& skill, const Ice::Current& current = Ice::Current()) override; + // Plugin const std::experimental::observer_ptr<plugins::SkillProviderComponentPlugin>& getSkillProviderPlugin() const; protected: - void addSkill(const skills::LambdaSkill::FunT&, const skills::SkillDescription&); - void addSkill(std::unique_ptr<skills::Skill>&&); + // utility + void addSkillFactory(const skills::SkillDescription&, const skills::LambdaSkill::FunT&); + void addSkillFactory(std::unique_ptr<skills::SkillFactory>&&); template <typename T, typename... Args> T* - addSkill(Args&&... args) + addSkillFactory(Args&&... args) { - return plugin->addSkill<T>(std::forward<Args>(args)...); + return plugin->addSkillFactory<T>(std::forward<Args>(args)...); } private: diff --git a/source/RobotAPI/libraries/skills/core/SkillProxy.cpp b/source/RobotAPI/libraries/skills/provider/SkillProxy.cpp similarity index 94% rename from source/RobotAPI/libraries/skills/core/SkillProxy.cpp rename to source/RobotAPI/libraries/skills/provider/SkillProxy.cpp index be2aa65cb30d2c385c4977bf1dea98c7d3a0a4ea..0c28fb5a62db877960cd9f3d3e3e8ebad478a12e 100644 --- a/source/RobotAPI/libraries/skills/core/SkillProxy.cpp +++ b/source/RobotAPI/libraries/skills/provider/SkillProxy.cpp @@ -20,7 +20,7 @@ namespace armarx SkillProxy::SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager, const std::string& skillProviderName, const SkillDescription& skillDesc) : - manager(manager), skillId(skillProviderName, skillDesc.skillName) + manager(manager), skillId(skillProviderName, skillDesc.skillId.skillName) { } @@ -31,7 +31,7 @@ namespace armarx skills::manager::dto::SkillExecutionRequest req; req.executorName = executorName; req.params = params->toAronDictDTO(); - req.skillId = skillId.toIce(); + req.skillId = skillId.toManagerIce(); auto terminatingUpdate = manager->executeSkill(req); return TerminatedSkillStatusUpdate::FromIce(terminatingUpdate); @@ -44,7 +44,7 @@ namespace armarx skills::manager::dto::SkillExecutionRequest req; req.executorName = executorName; req.params = params->toAronDictDTO(); - req.skillId = skillId.toIce(); + req.skillId = skillId.toManagerIce(); auto future = manager->begin_executeSkill(req); return future; @@ -55,7 +55,7 @@ namespace armarx { // TODO: This will be used in the future, do not remove it! (void)executorName; - manager->abortSkill(skillId.providerName, skillId.skillName); + //manager->abortSkill(); } aron::data::DictPtr diff --git a/source/RobotAPI/libraries/skills/core/SkillProxy.h b/source/RobotAPI/libraries/skills/provider/SkillProxy.h similarity index 97% rename from source/RobotAPI/libraries/skills/core/SkillProxy.h rename to source/RobotAPI/libraries/skills/provider/SkillProxy.h index c9ea3f09f8eb8f9e57b23a09226d8d1903ab2644..a77c8603742c4ffc1957f6e9278f09211db6307c 100644 --- a/source/RobotAPI/libraries/skills/core/SkillProxy.h +++ b/source/RobotAPI/libraries/skills/provider/SkillProxy.h @@ -1,6 +1,6 @@ #pragma once -#include "Skill.h" +#include <RobotAPI/libraries/skills/core/Skill.h> namespace armarx { diff --git a/source/RobotAPI/libraries/skills/core/SpecializedSkill.cpp b/source/RobotAPI/libraries/skills/provider/SpecializedSkill.cpp similarity index 100% rename from source/RobotAPI/libraries/skills/core/SpecializedSkill.cpp rename to source/RobotAPI/libraries/skills/provider/SpecializedSkill.cpp diff --git a/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h b/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h new file mode 100644 index 0000000000000000000000000000000000000000..c56953e46b0a28744a189d520c982d2ad8316775 --- /dev/null +++ b/source/RobotAPI/libraries/skills/provider/SpecializedSkill.h @@ -0,0 +1,63 @@ +#pragma once + +#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h> +#include <RobotAPI/libraries/skills/core/Skill.h> + +// Debug +#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> + +namespace armarx +{ + namespace skills + { + template <class AronT> + class SpecializedSkill : public Skill + { + public: + using ParamType = AronT; + + struct SpecializedMainInput + { + std::string executorName; + AronT params; + CallbackT callback; + }; + + using Skill::Skill; + virtual ~SpecializedSkill() = default; + + /// returns the accepted type of the skill + static armarx::aron::type::ObjectPtr + GetAcceptedType() + { + return AronT::ToAronType(); + } + + + private: + /// Do not use anymore + Skill::InitResult + init() final + { + return InitResult{.status = TerminatedSkillStatus::Succeeded}; + } + + /// Do not use anymore + Skill::MainResult + main() final + { + ARMARX_IMPORTANT << "Dummy executing skill '" << description.skillId + << "'. Please overwrite this method."; + return Skill::MainResult{.status = TerminatedSkillStatus::Succeeded, + .data = nullptr}; + } + + /// Do not use anymore + Skill::ExitResult + exit() final + { + return ExitResult{.status = TerminatedSkillStatus::Succeeded}; + } + }; + } // 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 32f8358c25f19a17aab365d7bc080ece79d90041..bbe71e6ae1e3e4c237ae1e553425b576ccafdc88 100644 --- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp +++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp @@ -5,57 +5,83 @@ namespace armarx namespace skills::detail { SkillImplementationWrapper::SkillImplementationWrapper( - std::unique_ptr<skills::Skill>&& skill) : - skill(std::move(skill)) + const skills::SkillFactory* fac, + const skills::SkillExecutionId& execId, + const skills::SkillParameterization& param) : + factory(fac), statusUpdate(execId, param) { - ARMARX_CHECK_NOT_NULL(this->skill); + ARMARX_CHECK_NOT_NULL(this->factory); } - TerminatedSkillStatusUpdate - SkillImplementationWrapper::setupAndExecuteSkill( - const std::string& executorName, - const skills::SkillParameterization parameterization) + // ask a skill to stop + void + SkillImplementationWrapper::stopSkill() { - const std::string skillName = skill->description.skillName; - ARMARX_INFO_S << "Executing skill: " << skillName; + if (this->skill == nullptr) + { + // skill has not started yet. + return; + } - // we can safely assume that no two executions have the same timestamp - const skills::SkillExecutionId executionId = { - skill->getSkillId(), executorName, armarx::core::time::DateTime::Now()}; + this->skill->notifySkillToStopASAP(); + } - // set params and setup variables + void + SkillImplementationWrapper::addSkillParameters(const aron::data::DictPtr& i) + { + if (this->skill == nullptr) { - std::unique_lock l(skillStatusesMutex); - statusUpdates[executionId] = - SkillStatusUpdate({{executionId, parameterization}, SkillStatus::Scheduled}); + // skill has not started yet + return; } - // 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); - }; + this->skill->addParameters(i); + } + + TerminatedSkillStatusUpdate + SkillImplementationWrapper::executeSkill() + { + // ------------------------------------------------------------------------------------- + // sanity check + // ------------------------------------------------------------------------------------- + ARMARX_CHECK(!has_been_called) + << "A SKILL HAS ALREADY BEEN CALLED. THIS SHOULD NOT HAPPEN!!"; + + has_been_called = true; + + ARMARX_CHECK(this->skill == nullptr) + << "A SKILL HAS ALREADY BEEN CONSTRUCTED. THIS SHOULD NOT HAPPEN!!"; + + + // ------------------------------------------------------------------------------------- + // setup basic vars and lambdas + // ------------------------------------------------------------------------------------- + // actually we should lock... however this is only read access and the members are const throughout the execution... + const auto initial_aron_params = statusUpdate.usedParameterization.parameterization; + const auto callback_interface = statusUpdate.usedParameterization.callbackInterface; + const auto skillId = statusUpdate.executionId.skillId; + const auto skillName = skillId.skillName; + const auto providerName = skillId.providerName; + const auto executorName = statusUpdate.executionId.executorName; + + ARMARX_INFO_S << "Executing skill: " << skillName; - 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; + statusUpdate.usedParameterization.parameterization = skill->parameters; - auto& callbackInterface = statusUpdate.usedParameterization.usedCallbackInterface; - - if (callbackInterface) + if (callback_interface) { - callbackInterface->updateStatusForSkill(statusUpdate.toIceProviderView(), - skill->getSkillId().providerName); + skills::provider::dto::ProviderID pid({providerName}); + callback_interface->updateStatusForSkill(statusUpdate.toProviderIce(), pid); } }; - auto createErrorMessage = [](const std::string& message) + auto createErrorMessageData = [](const std::string& message) { auto obj = aron::make_dict(); auto m = aron::make_string(message, aron::Path({"errormessage"})); @@ -63,165 +89,131 @@ namespace armarx return obj; }; - // Check params - if (skill->description.acceptedType && not(aron_params)) { - std::string message = "SkillError 001: The Skill '" + skillName + - "' requires a type but params are NULL."; - ARMARX_ERROR_S << message; - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + std::unique_lock l(skillStatusesMutex); + + // --------------------------------------------------------------------------------- + // check times + // --------------------------------------------------------------------------------- + if ((armarx::core::time::DateTime::Now() - + statusUpdate.executionId.executionStartedTime) > + armarx::core::time::Duration::Seconds(1)) + { + ARMARX_WARNING_S << "SkillError 001: For some reason the skill '" + << skillId.toString() + << "' has been scheduled > 1s ago. The execution should start " + "much faster! Continue, but this is bad behavior.."; + } } - if (skill->description.acceptedType && aron_params && - not(aron_params->fullfillsType(skill->description.acceptedType))) + // ------------------------------------------------------------------------------------- + // construct skill + // ------------------------------------------------------------------------------------- + updateStatus(SkillStatus::Constructing); + this->skill = this->factory->createSkill(); + this->skill->executorName = (executorName); + this->skill->callback = [&](const SkillStatus s, const armarx::aron::data::DictPtr& d) + { updateStatus(s, d); }; + + + auto makeTerminationResult = [&](const std::string& message) + { + updateStatus(SkillStatus::Failed, createErrorMessageData(message)); + + std::unique_lock l(skillStatusesMutex); + auto terminated = TerminatedSkillStatusUpdate(statusUpdate.executionId, + statusUpdate.usedParameterization); + terminated.data = statusUpdate.data; + terminated.status = TerminatedSkillStatus::Failed; + return terminated; + }; + + // ------------------------------------------------------------------------------------- + // Check params + // ------------------------------------------------------------------------------------- + if (skill->description.acceptedType && initial_aron_params && + not(initial_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."; ARMARX_ERROR_S << message; - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + return makeTerminationResult(message); } - // Check if skill is available with the given parameterization - try - { - if (not skill->isSkillAvailable( - Skill::InitInput{.executorName = executorName, .params = aron_params})) - { - std::string message = - "SkillError 101: The Skill '" + skillName + "' is not available."; - ARMARX_WARNING << message; - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); - } - } - catch (const std::exception& ex) + auto exitAndMakeTerminationResult = [&](const std::string& message) { - std::string message = - "SkillError 101e: An error occured during the check whether skill '" + - skillName + "' is available. The error was: " + GetHandledExceptionString(); - ARMARX_ERROR_S << message; - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); - } - - // set scheduled - updateStatus(SkillStatus::Scheduled); + skill->exitSkill(); // try to exit skill. Ignore return value + return makeTerminationResult(message); + }; - // reset skill and perhaps wait for dependencies + // ------------------------------------------------------------------------------------- + // Init skill + // ------------------------------------------------------------------------------------- try { - skill->resetSkill(); + updateStatus(SkillStatus::Initializing); + Skill::InitResult initRet = skill->initSkill(); + if (initRet.status != TerminatedSkillStatus::Succeeded) + { + std::string message = "SkillError 101: The initialization of skill '" + + skillName + "' did not succeed."; + return exitAndMakeTerminationResult(message); + } } catch (const std::exception& ex) { std::string message = - "SkillError 201e: An error occured during the reset of skill '" + skillName + - "'. The error was: " + GetHandledExceptionString(); + "SkillError 101e: An error occured during the initialization of skill '" + + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - - updateStatus(SkillStatus::Failed); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + return exitAndMakeTerminationResult(message); } + // ------------------------------------------------------------------------------------- + // Prepare skill + // ------------------------------------------------------------------------------------- try { - skill->waitForDependenciesOfSkill(); + updateStatus(SkillStatus::Preparing); + + // set initial parameters that were attached to the execution request + skill->addParameters(initial_aron_params); + while (not skill->skillPreparationFinished()) + { + // wait... + skill->prepareSkill(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } } catch (const std::exception& ex) { - std::string message = "SkillError 301e: An error occured during waiting for skill " + std::string message = "SkillError 201e: An error occured during waiting for skill " "dependencies of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - - updateStatus(SkillStatus::Failed); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + return exitAndMakeTerminationResult(message); } // execute. If the skill fails for some reason, from this point it will always execute its exit function. updateStatus(SkillStatus::Running); - - try - { - 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 - - updateStatus(skills::toSkillStatus(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(); - ARMARX_ERROR_S << message; - skill->exitSkill( - {executorName, aron_params}); // try to exit skill. Ignore return value - - updateStatus(SkillStatus::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(); 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 - - updateStatus(skills::toSkillStatus(mainRet.status)); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - mainRet.status}); + return exitAndMakeTerminationResult(message); } } @@ -231,33 +223,19 @@ namespace armarx "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 - - updateStatus(SkillStatus::Failed); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + return exitAndMakeTerminationResult(message); } // Main succeeded! try { - Skill::ExitResult exitRet = skill->exitSkill({executorName, aron_params}); + Skill::ExitResult exitRet = skill->exitSkill(); 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 - - updateStatus(skills::toSkillStatus(exitRet.status)); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - exitRet.status}); + return makeTerminationResult(message); } } @@ -267,12 +245,7 @@ namespace armarx "SkillError 601e: An error occured during the exit method of skill '" + skillName + "'. The error was: " + GetHandledExceptionString(); ARMARX_ERROR_S << message; - - updateStatus(SkillStatus::Failed); - tidyUpStatusUpdates(); - return TerminatedSkillStatusUpdate( - {{executionId, parameterization, createErrorMessage(message)}, - TerminatedSkillStatus::Failed}); + return makeTerminationResult(message); } // Exit succeeded! @@ -281,12 +254,14 @@ namespace armarx // All succeeded! updateStatus(SkillStatus::Succeeded); - // Tidy up - tidyUpStatusUpdates(); - // return result of main method - return {{executionId, parameterization, mainRet.data}, - TerminatedSkillStatus::Succeeded}; + std::unique_lock l(skillStatusesMutex); + TerminatedSkillStatusUpdate ret(statusUpdate.executionId, + statusUpdate.usedParameterization); + ret.data = mainRet.data; + ret.status = TerminatedSkillStatus::Succeeded; + + return ret; } } // 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 32fafd3537724d96fde728e1ce3ddba5d2b06ad2..8ae7dcf7709f2f7293346eb6b928e7e00709b619 100644 --- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h +++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.h @@ -3,10 +3,11 @@ #include <shared_mutex> #include <RobotAPI/interface/skills/SkillManagerInterface.h> - -#include "../Skill.h" -#include "../SkillDescription.h" -#include "../SkillStatusUpdate.h" +#include <RobotAPI/libraries/skills/core/Skill.h> +#include <RobotAPI/libraries/skills/core/SkillDescription.h> +#include <RobotAPI/libraries/skills/core/SkillPreparationInput.h> +#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h> +#include <RobotAPI/libraries/skills/provider/SkillFactory.h> namespace armarx { @@ -16,23 +17,32 @@ namespace armarx { class SkillImplementationWrapper { - public: - // fixed values. Do not change after skill instantiation - const std::unique_ptr<Skill> skill; + private: + const skills::SkillFactory* factory; + + std::unique_ptr<Skill> skill; + + std::atomic_bool has_been_called = false; // sanitize + public: // Current execution statuses. Changes during execution // The status also holds the used parameterization - mutable std::shared_mutex skillStatusesMutex; - std::map<skills::SkillExecutionId, SkillStatusUpdate> statusUpdates; + mutable std::mutex skillStatusesMutex; + SkillStatusUpdate statusUpdate; // ctor - SkillImplementationWrapper(std::unique_ptr<skills::Skill>&& skill); + SkillImplementationWrapper(const skills::SkillFactory* fac, + const skills::SkillExecutionId&, + const skills::SkillParameterization&); // 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 executeSkill(); + + // ask a skill to stop + void stopSkill(); + + void addSkillParameters(const aron::data::DictPtr& i); }; } // namespace detail } // namespace skills diff --git a/source/RobotAPI/libraries/skills/core/mixins/All.h b/source/RobotAPI/libraries/skills/provider/mixins/All.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/All.h rename to source/RobotAPI/libraries/skills/provider/mixins/All.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/ArvizSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/ArvizSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/ArvizSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/ArvizSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/GraspReadingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/GraspReadingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/GraspReadingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/GraspReadingSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/MNSSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/MNSSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/MNSSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/MNSSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/MemoryReadingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/MemoryReadingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/MemoryReadingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/MemoryReadingSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/ObjectReadingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/ObjectReadingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/ObjectReadingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/ObjectReadingSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/ObjectWritingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/ObjectWritingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/ObjectWritingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/ObjectWritingSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/RobotReadingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/RobotReadingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/RobotReadingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/RobotReadingSkillMixin.h diff --git a/source/RobotAPI/libraries/skills/core/mixins/RobotWritingSkillMixin.h b/source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h similarity index 100% rename from source/RobotAPI/libraries/skills/core/mixins/RobotWritingSkillMixin.h rename to source/RobotAPI/libraries/skills/provider/mixins/RobotWritingSkillMixin.h