diff --git a/source/RobotAPI/libraries/skills/core/Skill.cpp b/source/RobotAPI/libraries/skills/core/Skill.cpp index 0b7a32df224d925ced896414d7d47f540f04a0d5..a01eb4908baed4e5f6dc18c76f5493053d4bb886 100644 --- a/source/RobotAPI/libraries/skills/core/Skill.cpp +++ b/source/RobotAPI/libraries/skills/core/Skill.cpp @@ -19,10 +19,22 @@ namespace armarx } std::optional<TerminatedSkillStatusUpdate> - Skill::callSubskill(const SkillProxy& prx, const aron::data::DictPtr& params) + Skill::callSubskill(const SkillProxy& proxy) { - auto eid = callSubskillAsync(prx, params); - auto ret = prx.join(eid); + return callSubskill(proxy, proxy.getRootProfileParameters()); + } + + std::optional<TerminatedSkillStatusUpdate> + Skill::callSubskill(const SkillProxy& proxy, const aron::data::DictPtr& parameters) + { + auto executionId = callSubskillAsync(proxy, parameters); + auto ret = proxy.join(executionId); + + // While the sub skill was running, our skill might also have been aborted. + // In this case, the correct behavour would be aborting ourselves. + // The caller of callSubskill() can catch the thrown error::SkillAbortedException + // if necessary. + throwIfSkillShouldTerminate(); return ret; } @@ -37,6 +49,35 @@ namespace armarx return eid; } + std::optional<TerminatedSkillStatusUpdate> + Skill::callSubskill(const SkillID& skillId) + { + return callSubskill(SkillProxy(manager, skillId)); + } + + std::optional<TerminatedSkillStatusUpdate> + Skill::callSubskill(const SkillID& skillId, const aron::data::DictPtr& parameters) + { + return callSubskill(SkillProxy(manager, skillId), parameters); + } + + std::optional<TerminatedSkillStatusUpdate> + Skill::callSubskill(const SkillID& skillId, + std::function<void(aron::data::DictPtr&)> parametersFunction) + { + SkillProxy proxy(manager, skillId); + + aron::data::DictPtr parameters = proxy.getRootProfileParameters(); + if (not parameters) + { + parameters = armarx::aron::make_dict(); + } + + parametersFunction(parameters); + + return callSubskill(proxy, parameters); + } + void Skill::updateParameters(const aron::data::DictPtr& d) { diff --git a/source/RobotAPI/libraries/skills/core/Skill.h b/source/RobotAPI/libraries/skills/core/Skill.h index 5ec80e77d9956e8516ae84ffec16313bab0c9206..9fffd35a6f258e778200351ef387ba9d3b184480 100644 --- a/source/RobotAPI/libraries/skills/core/Skill.h +++ b/source/RobotAPI/libraries/skills/core/Skill.h @@ -1,15 +1,11 @@ #pragma once -// std/stl #include <functional> #include <mutex> #include <queue> #include <thread> -// base class #include <ArmarXCore/core/logging/Logging.h> - -// ArmarX #include <ArmarXCore/core/time/DateTime.h> #include <ArmarXCore/core/time/Metronome.h> @@ -27,6 +23,9 @@ namespace armarx { namespace skills { + /** + * @brief Base class for skills. + */ class Skill : public armarx::Logging { public: @@ -185,14 +184,136 @@ namespace armarx void installConditionWithCallback(std::function<bool()>&& f, std::function<void()>&& cb); - /// call a subskill and block until the subskill terminates. - /// If you call a subskill this way it will be stopped if the current skill stops. + // Calling subskills + + /** + * @brief Call a subskill with default parameters and block until the subskill terminates. + * + * If you call a subskill this way it will be stopped if the current skill stops. + * + * @param proxy Skill proxy. + * @return Terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + std::optional<TerminatedSkillStatusUpdate> + callSubskill(const skills::SkillProxy& proxy); + + /** + * @brief Call a subskill with given parameters and block until the subskill terminates. + * @param proxy Skill proxy. + * @param parameters Parameters passed to the skill. + * @return Terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ std::optional<TerminatedSkillStatusUpdate> - callSubskill(const skills::SkillProxy& prx, const aron::data::DictPtr& = nullptr); + callSubskill(const skills::SkillProxy& proxy, const aron::data::DictPtr& parameters); /// Similar to callSubskill but non-blocking - skills::SkillExecutionID callSubskillAsync(const skills::SkillProxy& prx, - const aron::data::DictPtr& = nullptr); + skills::SkillExecutionID callSubskillAsync(const skills::SkillProxy& proxy); + + /// Similar to callSubskill but non-blocking + skills::SkillExecutionID callSubskillAsync(const skills::SkillProxy& proxy, + const aron::data::DictPtr& parameters); + + /** + * @brief Call a subskill with the given ID and its default parameters. + * @param skillId The subskill's ID. + * @return The terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + std::optional<TerminatedSkillStatusUpdate> callSubskill(const SkillID& skillId); + + /** + * @brief Call a subskill with the given ID and parameters. + * @param skillId The subskill's ID. + * @param parameters The parameters. + * @return The terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + std::optional<TerminatedSkillStatusUpdate> + callSubskill(const SkillID& skillId, const aron::data::DictPtr& parameters); + + /** + * @brief Call a subskill with the given ID and parameters. + * @param skillId The subskill's ID. + * @param parameters The parameters. + * @return The terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + template <class ParameterT> + std::optional<TerminatedSkillStatusUpdate> + callSubskill(const SkillID& skillId, const ParameterT& parameters) + { + return callSubskill(skillId, parameters.toAron()); + } + + /** + * @brief Call a subskill with parameters based on the default parameters. + * + * Creates the skill's default parameters, and calls `parametersFunction` on them. + * This allows the caller to modify the parameters before executing the skill. + * + * @param skillId The subskill's ID. + * @param parametersFunction Function which edits the parameters. + * @return The terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + std::optional<TerminatedSkillStatusUpdate> + callSubskill(const SkillID& skillId, + std::function<void(aron::data::DictPtr& parameters)> parametersFunction); + + /** + * @brief Call a subskill with parameters based on the default parameters. + * + * Creates the skill's default parameters, converts them to `ParameterT`, + * and calls `parametersFunction` on them. + * This allows the caller to modify the parameters as `ParameterT` before executing + * the skill. + * + * @param skillId The subskill's ID. + * @param parametersFunction Function which edits the parameters. + * @return The terminated skill status update. + * @throw armarx::skills::error::SkillAbortedException + * If the calling skill has been aborted. + * @throw armarx::skills::error::SkillFailedException + * If the calling skill's timeout was reached. + */ + template <class ParameterT> + std::optional<TerminatedSkillStatusUpdate> + callSubskill(const SkillID& skillId, + std::function<void(ParameterT& parameters)> parametersFunction) + { + SkillProxy proxy(manager, skillId); + + ParameterT parameters; + if (auto parametersAron = proxy.getRootProfileParameters()) + { + parameters = ParameterT::FromAron(parametersAron); + } + + parametersFunction(parameters); + + return callSubskill(proxy, parameters.toAron()); + } + public: // running params