Skill.h
Go to the documentation of this file.
1#pragma once
2
3#include <atomic>
4#include <functional>
5#include <memory>
6#include <mutex>
7#include <optional>
8#include <string>
9#include <thread>
10#include <type_traits>
11#include <utility>
12#include <vector>
13
18
19#include <RobotAPI/interface/skills/SkillManagerInterface.h>
30
31namespace armarx
32{
33 namespace skills
34 {
35 using SkillExecutionHandlePtr = std::unique_ptr<class SkillExecutionHandle>;
36
37 /**
38 * @brief Base class for skills.
39 */
41 {
42 using SkillProxyPtr = std::unique_ptr<class SkillProxy>;
43
44 public:
45 using CallbackT =
46 std::function<void(const SkillStatus s, const armarx::aron::data::DictPtr&)>;
47
48 /// A result struct for skill initialization
53
54 /// A result struct for skill preparing
59
60 /// A result struct for th main method of a skill
66
67 /// A result struct for skill exit function
72
73 /// We completely remove the default constructor! A skill without a desciption cannot
74 /// exist
75 Skill() = delete;
76
77 /// Constructor of a skill for inheritance. Every skill must have a skill description
78 Skill(const SkillDescription&);
79
80 /// Virtual destructor of a skill
81 ~Skill() override;
82
83 /// Get the id of the skill
84 SkillID getSkillId() const;
85
86 /// Get the description of a skill
88
89 /// Set the provider id of the description of the skill.
90 /// This method is called when creating a skill in a skill provider
91 void setProviderId(const skills::ProviderID& pid);
92
93 void setCallback(const CallbackT& callback);
94
95 void setManager(const manager::dti::SkillManagerInterfacePrx& manager);
96
97 void setExecutorName(const std::string& executorName);
98
99 void updateSubSkillStatus(const skills::SkillStatusUpdate& statusUpdate);
100
101 /// Prepare a skill once. This method is called in a loop as long as it returns RUNNING
102 /// If the loop does not terminate with SUCCEDED the skill execution is failed.
104
105 /// Initialization of a skill. Called directly after construction.
106 /// If this method does not return SUCCEEDED the skill execution is failed.
108
109 /// Main method of a skill.
111
112 /// Exit method of a skill. It is guaranteed that exit is always called
113 /// (unless there is a segfault or similar)
115
116 /// Notify the skill from extern to stop
117 void notifySkillToStop();
118
119 /// Returns whether the skill should terminate as soon as possible
120 bool shouldSkillTerminate() const override;
121
122 /// Merge parameters to the local parameters of the skill
124
125 /// Hard set the parameters, ignoring everything that has been set or merged before
126 void setParameters(const aron::data::DictPtr& d);
127
128 /// Get the parameters of a skill that have been set so far
130
131 protected:
132 void throwIfSkillShouldTerminate(const std::string& abortedMessage = "") const;
133 void throwIfSkillShouldTerminate(const std::function<void()>& do_before,
134 const std::string& abortedMessage = "") const;
135
139
140 // fires if the skill reaches timeout
142
143 private:
144 // helper methods to do all the static initialization stuff
145 InitResult _init();
146 PrepareResult _prepare();
147 MainResult _main();
148 ExitResult _exit();
149
150 void _onTimeoutReached();
151 void _onStopRequested();
152
153 std::optional<TerminatedSkillStatusUpdate>
154 executeSkill(const ::armarx::skills::SkillID& skillID,
155 std::function<aron::data::DictPtr(aron::data::DictPtr&)> const&
156 parametersFunction) override;
157
158 protected:
159 /// Override this method with the actual implementation.
160 virtual InitResult init();
161
162 /// Override this method with the actual implementation.
163 virtual PrepareResult prepare();
164
165 /// Override this method with the actual implementation. The callback is for status
166 /// updates to the calling instance
167 virtual MainResult main();
168
169 /// Override this method with the actual implementation.
170 virtual ExitResult exit();
171
172 protected:
173 /// Override these methods if you want to do something special when notification comes
174 virtual void onTimeoutReached();
175 virtual void onStopRequested();
176
177 public:
178 /// install a condition which is frequently checked from the conditionCheckingThread
179 void installConditionWithCallback(std::function<bool()>&& f,
180 std::function<void()>&& cb);
181
182 void waitFor(const armarx::Duration& duration,
184 armarx::Duration::MilliSeconds(200)) const override;
185
186 // Calling subskills
187
188 [[nodiscard]] SkillExecutionHandlePtr
189 callSubskillAsync(const SkillID& skillId,
190 std::function<void(aron::data::DictPtr&)> parametersFunction);
191
192 [[nodiscard]] SkillExecutionHandlePtr callSubskillAsync(const SkillID& skillId);
193
194 /**
195 * @brief Call a subskill with the given ID and its default parameters.
196 * @param skillId The subskill's ID.
197 * @return The terminated skill status update.
198 * @throw armarx::skills::error::SkillAbortedException
199 * If the calling skill has been aborted.
200 * @throw armarx::skills::error::SkillFailedException
201 * If the calling skill's timeout was reached.
202 */
203 std::optional<TerminatedSkillStatusUpdate> callSubskill(const SkillID& skillId);
204
205 /**
206 * @brief Call a subskill with the given ID and parameters.
207 * @param skillId The subskill's ID.
208 * @param parameters The parameters.
209 * @return The terminated skill status update.
210 * @throw armarx::skills::error::SkillAbortedException
211 * If the calling skill has been aborted.
212 * @throw armarx::skills::error::SkillFailedException
213 * If the calling skill's timeout was reached.
214 */
215 std::optional<TerminatedSkillStatusUpdate>
216 callSubskill(const SkillID& skillId, const aron::data::DictPtr& parameters);
217
218 /**
219 * @brief Call a subskill with the given ID and parameters.
220 * @param skillId The subskill's ID.
221 * @param parameters The parameters.
222 * @return The terminated skill status update.
223 * @throw armarx::skills::error::SkillAbortedException
224 * If the calling skill has been aborted.
225 * @throw armarx::skills::error::SkillFailedException
226 * If the calling skill's timeout was reached.
227 */
228 template <class ParameterT>
229 std::optional<TerminatedSkillStatusUpdate>
230 callSubskill(const SkillID& skillId, const ParameterT& parameters)
231 {
232 return callSubskill(skillId, parameters.toAron());
233 }
234
235 /**
236 * @brief Call a subskill with parameters based on the default parameters.
237 *
238 * Creates the skill's default parameters, and calls `parametersFunction` on them.
239 * This allows the caller to modify the parameters before executing the skill.
240 *
241 * @param skillId The subskill's ID.
242 * @param parametersFunction Function which edits the parameters.
243 * @return The terminated skill status update.
244 * @throw armarx::skills::error::SkillAbortedException
245 * If the calling skill has been aborted.
246 * @throw armarx::skills::error::SkillFailedException
247 * If the calling skill's timeout was reached.
248 */
249 std::optional<TerminatedSkillStatusUpdate>
250 callSubskill(const SkillID& skillId,
251 std::function<void(aron::data::DictPtr& parameters)> parametersFunction);
252
253 /**
254 * @brief Call a subskill with parameters based on the default parameters.
255 *
256 * Creates the skill's default parameters, converts them to `ParameterT`,
257 * and calls `parametersFunction` on them.
258 * This allows the caller to modify the parameters as `ParameterT` before executing
259 * the skill.
260 *
261 * @param skillId The subskill's ID.
262 * @param parametersFunction Function which edits the parameters.
263 * @return The terminated skill status update.
264 * @throw armarx::skills::error::SkillAbortedException
265 * If the calling skill has been aborted.
266 * @throw armarx::skills::error::SkillFailedException
267 * If the calling skill's timeout was reached.
268 */
269 template <class ParameterT>
270 std::optional<TerminatedSkillStatusUpdate>
271 callSubskill(const SkillID& skillId,
272 std::function<void(ParameterT& parameters)> parametersFunction)
273 {
274 SkillProxyPtr proxy = std::make_unique<SkillProxy>(manager, skillId);
275
276 ParameterT parameters;
277 if (auto parametersAron = proxy->getRootProfileParameters())
278 {
279 parameters = ParameterT::FromAron(parametersAron);
280 }
281
282 parametersFunction(parameters);
283
284 return callSubskill(std::move(proxy), parameters.toAron());
285 }
286
287 /// Similar to callSubskill but non-blocking
288 template <class ParameterT>
289 [[nodiscard]] SkillExecutionHandlePtr
291 std::function<void(ParameterT& parameters)> parametersFunction)
292 {
293 SkillProxyPtr proxy = std::make_unique<SkillProxy>(manager, skillId);
294 return callSubskillAsync(std::move(proxy), parametersFunction);
295 }
296
297 [[nodiscard]] SkillExecutionHandlePtr
299
300 // FIXME: make these protected again
301 // private:
302 public:
303 /**
304 * @brief Call a subskill with default parameters and block until the subskill
305 * terminates.
306 *
307 * If you call a subskill this way it will be stopped if the current skill stops.
308 *
309 * @param proxy Skill proxy.
310 * @return Terminated skill status update.
311 * @throw armarx::skills::error::SkillAbortedException
312 * If the calling skill has been aborted.
313 * @throw armarx::skills::error::SkillFailedException
314 * If the calling skill's timeout was reached.
315 */
316 std::optional<TerminatedSkillStatusUpdate> callSubskill(SkillProxyPtr proxy);
317
318 /**
319 * @brief Call a subskill with given parameters and block until the subskill terminates.
320 * @param proxy Skill proxy.
321 * @param parameters Parameters passed to the skill.
322 * @return Terminated skill status update.
323 * @throw armarx::skills::error::SkillAbortedException
324 * If the calling skill has been aborted.
325 * @throw armarx::skills::error::SkillFailedException
326 * If the calling skill's timeout was reached.
327 */
328 std::optional<TerminatedSkillStatusUpdate>
330
331 /// Similar to callSubskill but non-blocking
333
334 /// Similar to callSubskill but non-blocking
335 [[nodiscard]] SkillExecutionHandlePtr
337
338 template <class ParameterT>
340 callSubskillAsync(SkillProxyPtr proxy,
341 std::function<void(ParameterT& parameters)> parametersFunction)
342 {
343 ParameterT parameters;
344 if (auto parametersAron = proxy->getRootProfileParameters())
345 {
346 parameters = ParameterT::FromAron(parametersAron);
347 }
348
349 parametersFunction(parameters);
350
351 return callSubskillAsync(std::move(proxy), parameters.toAron());
352 }
353
354 public:
355 // running params
358
359 protected:
360 // parameterization. Will be set from implementation wrapper. No getters available
361 // const after construction!!
363 manager::dti::SkillManagerInterfacePrx manager = nullptr;
364 std::string executorName = "";
365
366 protected:
367 // non-const params. Const after preparation. Getters are available
368 mutable std::mutex parametersMutex;
370
371 // The descripion of the skill
373
374 // Task outcome tracking for the current skill execution
376
377 // Status variables
378 std::atomic_bool constructing = true;
379 std::atomic_bool initializing = false;
380 std::atomic_bool preparing = false;
381 std::atomic_bool running = false;
382 std::atomic_bool exiting = false;
383 std::atomic_bool finished = false;
384
385 // Conditionals to indicate that an event has occured. Use conditions this way
386 std::atomic_bool stopped = false;
387 std::atomic_bool timeoutReached = false;
388
389 private:
390 // active conditions. First is condition (bool return func)
391 mutable std::mutex conditionCallbacksMutex;
392 std::vector<std::pair<std::function<bool()>, std::function<void()>>>
393 conditionCallbacks = {};
394
395 std::thread conditionCheckingThread; // A thread that checks the conditions frequently
396 armarx::Frequency conditionCheckingThreadFrequency = armarx::Frequency::Hertz(20);
397
398 mutable std::mutex subskillsMutex;
399 std::vector<skills::SkillExecutionID> subskills;
400
401 public:
402 /**
403 * @brief Call a subskill with default parameters and block until the subskill
404 * terminates.
405 *
406 * If you call a subskill this way it will be stopped if the current skill stops.
407 *
408 * @param proxy Skill proxy.
409 * @return Terminated skill status update.
410 * @throw armarx::skills::error::SkillAbortedException
411 * If the calling skill has been aborted.
412 * @throw armarx::skills::error::SkillFailedException
413 * If the calling skill's timeout was reached.
414 */
415 [[deprecated("callSubskill(proxy) should be replaced by callSubskill(skillId)")]] std::
416 optional<TerminatedSkillStatusUpdate>
418 {
419 return callSubskill(proxy.getSkillId());
420 }
421
422 /**
423 * @brief Call a subskill with given parameters and block until the subskill terminates.
424 * @param proxy Skill proxy.
425 * @param parameters Parameters passed to the skill.
426 * @return Terminated skill status update.
427 * @throw armarx::skills::error::SkillAbortedException
428 * If the calling skill has been aborted.
429 * @throw armarx::skills::error::SkillFailedException
430 * If the calling skill's timeout was reached.
431 */
432 [[deprecated(
433 "callSubskill(proxy, parameters) should be replaced by "
434 "callSubskill(skillId, parameters)")]] std::optional<TerminatedSkillStatusUpdate>
436 {
437 return callSubskill(proxy.getSkillId(), parameters);
438 }
439
440 /// Similar to callSubskill but non-blocking
441 template <class ParameterT>
442 [[deprecated("callSubskillAsync(proxy, parametersFunction) should be replaced by "
443 "callSubskillAsync(skillId, parametersFunction)")]] SkillExecutionHandlePtr
445 std::function<void(ParameterT& parameters)> parametersFunction)
446 {
447 ParameterT parameters;
448 if (auto parametersAron = proxy.getRootProfileParameters())
449 {
450 parameters = ParameterT::FromAron(parametersAron);
451 }
452
453 parametersFunction(parameters);
454
455 return callSubskillAsync(proxy.getSkillId(), parameters.toAron());
456 }
457
458 [[deprecated("callSubskillAsync(proxy, parameters) should be replaced by "
459 "callSubskillAsync(skillId, parameters)")]] SkillExecutionHandlePtr
465 };
466
467 template <class T>
468 concept isSkill = std::is_base_of<Skill, T>::value;
469
470 } // namespace skills
471} // namespace armarx
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition Duration.cpp:48
static Frequency Hertz(std::int64_t hertz)
Definition Frequency.cpp:20
Base Class for all Logging classes.
Definition Logging.h:240
Represents a point in time.
Definition DateTime.h:25
static DateTime Now()
Definition DateTime.cpp:51
static DateTime Invalid()
Definition DateTime.cpp:57
Represents a duration.
Definition Duration.h:17
Represents a frequency.
Definition Frequency.h:17
SkillID getSkillId() const
get the skill id from the skill description
aron::data::DictPtr getRootProfileParameters() const
get the default parameters of the skill. TODO: Skill profiles in memory!
virtual PrepareResult prepare()
Override this method with the actual implementation.
Definition Skill.cpp:527
CallbackT callback
Definition Skill.h:362
void installConditionWithCallback(std::function< bool()> &&f, std::function< void()> &&cb)
install a condition which is frequently checked from the conditionCheckingThread
Definition Skill.cpp:47
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId, const ParameterT &parameters)
Call a subskill with the given ID and parameters.
Definition Skill.h:230
std::atomic_bool running
Definition Skill.h:381
armarx::core::time::DateTime started
Definition Skill.h:356
void notifyTimeoutReached()
Definition Skill.cpp:454
SkillExecutionHandlePtr callSubskillAsync(const skills::SkillProxy &proxy, const aron::data::DictPtr &parameters)
Definition Skill.h:460
armarx::core::time::DateTime exited
Definition Skill.h:357
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId)
Call a subskill with the given ID and its default parameters.
Definition Skill.cpp:119
std::atomic_bool finished
Definition Skill.h:383
std::atomic_bool exiting
Definition Skill.h:382
static MainResult MakeSucceededResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:413
void setManager(const manager::dti::SkillManagerInterfacePrx &manager)
Definition Skill.cpp:563
manager::dti::SkillManagerInterfacePrx manager
Definition Skill.h:363
InitResult initSkill()
Initialization of a skill.
Definition Skill.cpp:341
SkillExecutionHandlePtr callSubskillAsync(SkillProxyPtr proxy, std::function< void(ParameterT &parameters)> parametersFunction)
Definition Skill.h:340
virtual InitResult init()
Override this method with the actual implementation.
Definition Skill.cpp:519
static MainResult MakeAbortedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:431
armarx::aron::data::DictPtr parameters
Definition Skill.h:369
ExitResult exitSkill()
Exit method of a skill.
Definition Skill.cpp:369
std::atomic_bool constructing
Definition Skill.h:378
void notifySkillToStop()
Notify the skill from extern to stop.
Definition Skill.cpp:440
PrepareResult prepareSkill()
Prepare a skill once.
Definition Skill.cpp:350
SkillExecutionHandlePtr callSubskillAsync(const SkillProxy &proxy, std::function< void(ParameterT &parameters)> parametersFunction)
Similar to callSubskill but non-blocking.
Definition Skill.h:444
std::atomic_bool timeoutReached
Definition Skill.h:387
SkillDescription description
Definition Skill.h:372
std::mutex parametersMutex
Definition Skill.h:368
virtual void onStopRequested()
Definition Skill.cpp:513
bool shouldSkillTerminate() const override
Returns whether the skill should terminate as soon as possible.
Definition Skill.cpp:469
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId, std::function< void(aron::data::DictPtr &parameters)> parametersFunction)
Call a subskill with parameters based on the default parameters.
SkillExecutionHandlePtr callSubskillAsync(const SkillID &skillId, std::function< void(ParameterT &parameters)> parametersFunction)
Similar to callSubskill but non-blocking.
Definition Skill.h:290
std::atomic_bool stopped
Definition Skill.h:386
virtual MainResult main()
Override this method with the actual implementation.
Definition Skill.cpp:542
void throwIfSkillShouldTerminate(const std::string &abortedMessage="") const
Definition Skill.cpp:389
SkillID getSkillId() const
Get the id of the skill.
Definition Skill.cpp:587
std::optional< TerminatedSkillStatusUpdate > callSubskill(const skills::SkillProxy &proxy)
Call a subskill with default parameters and block until the subskill terminates.
Definition Skill.h:417
virtual ExitResult exit()
Override this method with the actual implementation.
Definition Skill.cpp:535
void setCallback(const CallbackT &callback)
Definition Skill.cpp:557
std::optional< TerminatedSkillStatusUpdate > callSubskill(const skills::SkillProxy &proxy, const aron::data::DictPtr &parameters)
Call a subskill with given parameters and block until the subskill terminates.
Definition Skill.h:435
~Skill() override
Virtual destructor of a skill.
Definition Skill.cpp:592
MainResult mainOfSkill()
Main method of a skill.
Definition Skill.cpp:359
aron::data::DictPtr getParameters() const
Get the parameters of a skill that have been set so far.
Definition Skill.cpp:219
SkillExecutionHandlePtr callSubskillAsync(const SkillID &skillId, std::function< void(aron::data::DictPtr &)> parametersFunction)
Definition Skill.cpp:148
void setParameters(const aron::data::DictPtr &d)
Hard set the parameters, ignoring everything that has been set or merged before.
Definition Skill.cpp:206
std::atomic_bool initializing
Definition Skill.h:379
void updateSubSkillStatus(const skills::SkillStatusUpdate &statusUpdate)
Definition Skill.cpp:575
SkillDescription getSkillDescription() const
Get the description of a skill.
Definition Skill.cpp:581
Skill()=delete
We completely remove the default constructor!
armem::task_outcome::TaskOutcome taskOutcome_
Definition Skill.h:375
virtual void onTimeoutReached()
Override these methods if you want to do something special when notification comes.
Definition Skill.cpp:508
static MainResult MakeFailedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:422
void updateParameters(const aron::data::DictPtr &d)
Merge parameters to the local parameters of the skill.
Definition Skill.cpp:190
void setProviderId(const skills::ProviderID &pid)
Set the provider id of the description of the skill.
Definition Skill.cpp:551
void waitFor(const armarx::Duration &duration, const armarx::Duration &interval=armarx::Duration::MilliSeconds(200)) const override
Definition Skill.cpp:54
void setExecutorName(const std::string &executorName)
Definition Skill.cpp:569
std::function< void(const SkillStatus s, const armarx::aron::data::DictPtr &)> CallbackT
Definition Skill.h:45
std::string executorName
Definition Skill.h:364
std::atomic_bool preparing
Definition Skill.h:380
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId, std::function< void(ParameterT &parameters)> parametersFunction)
Call a subskill with parameters based on the default parameters.
Definition Skill.h:271
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
std::unique_ptr< class SkillExecutionHandle > SkillExecutionHandlePtr
Definition Skill.h:35
std::unique_ptr< class SkillProxy > SkillProxyPtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
Interval< T > interval(T lo, T hi)
This file is part of ArmarX.
A result struct for skill exit function.
Definition Skill.h:69
TerminatedSkillStatus status
Definition Skill.h:70
A result struct for skill initialization.
Definition Skill.h:50
TerminatedSkillStatus status
Definition Skill.h:51
A result struct for th main method of a skill.
Definition Skill.h:62
TerminatedSkillStatus status
Definition Skill.h:63
aron::data::DictPtr data
Definition Skill.h:64
A result struct for skill preparing.
Definition Skill.h:56
ActiveOrTerminatedSkillStatus status
Definition Skill.h:57