SkillProviderComponentPlugin.cpp
Go to the documentation of this file.
2
3#include <chrono>
4#include <exception>
5#include <experimental/memory>
6#include <map>
7#include <memory>
8#include <mutex>
9#include <optional>
10#include <shared_mutex>
11#include <sstream>
12#include <string>
13#include <thread>
14#include <tuple>
15#include <utility>
16
17#include <Ice/Current.h>
18#include <IceUtil/Optional.h>
19
25
26#include <RobotAPI/interface/aron/Aron.h>
27#include <RobotAPI/interface/skills/SkillManagerInterface.h>
28#include <RobotAPI/interface/skills/SkillProviderInterface.h>
41
42namespace armarx::plugins
43{
44 void
48
49 void
55
56 void
58 {
60 const std::string providerName = p.getName();
61
62 // register self to manager
63 skills::ProviderInfo i{.providerId = skills::ProviderID{.providerName = providerName},
64 .providerInterface = myPrx,
65 .providedSkills = getSkillDescriptions()};
66
67 ARMARX_INFO << "Adding provider to manager: " << i.providerId;
68 manager->addProvider(i.toIce()); // add provider info to manager
69 }
70
71 void
73 {
75 std::string providerName = p.getName();
76
77 auto id = skills::manager::dto::ProviderID{providerName};
78 manager->removeProvider(id);
79
80 // Drain all in-flight executions before tearing down the runtimes.
81 // Joining must happen before destroying the SkillRuntime objects
82 // because each runtime owns its own std::thread, which must not be
83 // destroyed while joinable (would call std::terminate).
84 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> drained;
85 {
86 const std::unique_lock l(skillExecutionsMutex);
87 for (auto& [id, runtime] : skillExecutions)
88 {
89 drained.push_back(std::move(runtime));
90 }
91 skillExecutions.clear();
92 }
93 for (auto& runtime : drained)
94 {
95 if (runtime && runtime->execution.joinable())
96 {
97 try
98 {
99 runtime->execution.join();
100 }
101 catch (const std::exception& e)
102 {
103 ARMARX_WARNING << "Failed to join skill execution thread during "
104 "disconnect: "
105 << e.what();
106 }
107 }
108 }
109 drained.clear();
110
111 // remove all skills
112 ARMARX_INFO << "Removing all skills";
113 skillFactories.clear();
114 }
115
116 void
118 {
119 std::string prefix = "skill.";
120 properties->component(
121 manager,
122 "SkillMemory",
123 prefix + "SkillManager",
124 "The name of the SkillManager (or SkillMemory) proxy this provider belongs to.");
125 properties->topic<armarx::skills::SkillEventListenerInterface>(
126 "SkillEventListener", prefix + "tpc.sub.SkillEventListener");
127 }
128
129 void
130 SkillProviderComponentPlugin::addSkillFactory(std::unique_ptr<skills::SkillBlueprint>&& fac)
131 {
132 if (!fac)
133 {
134 return;
135 }
136
138 const std::string componentName = p.getName();
139
140 const skills::ProviderID providerId({componentName});
141
142 // lock skills map
143 const std::unique_lock l(skillFactoriesMutex);
144 auto skillId = fac->createSkillDescription(providerId).skillId;
145
146 if (skillFactories.find(skillId) != skillFactories.end())
147 {
148 ARMARX_WARNING << "Try to add a skill factory for skill '" + skillId.toString() +
149 "' which already exists in list. Ignoring this skill.";
150 return;
151 }
152
153 ARMARX_INFO << "Adding skill `" << skillId << "` to component `" << componentName << "` .";
154
155 skillFactories.emplace(skillId, std::move(fac));
156
157
158 // if (connected)
159 // {
160 // // if skill is added after onConnect we have to set the proxies manually.
161 // std::string providerName = parent().getName();
162 // s.first->second.skill->manager = manager;
163 // s.first->second.skill->providerName = providerName;
164 // }
165 }
166
173
175 SkillProviderComponentPlugin::getSkillFactory(const armarx::skills::SkillID& skillId)
176 {
177 // NON BLOCKING: WE ASSERT THAT THE LOCK IS ALREADY TAKEN
179
180 if (skillFactories.count(skillId) == 0)
181 {
182 ARMARX_INFO << "Could not find a skill factory for id: " << skillId;
183 return nullptr;
184 }
185
186 auto* facPtr = skillFactories.at(skillId).get();
187 return static_cast<skills::SkillBlueprint*>(facPtr);
188 }
189
190 std::optional<skills::SkillStatusUpdate>
192 const skills::SkillExecutionID& execId) const
193 {
195
196 const std::shared_lock l(skillExecutionsMutex);
197 auto it = skillExecutions.find(execId);
198 if (it == skillExecutions.end())
199 {
200 ARMARX_WARNING << "Skill execution for skill '" + execId.skillId.toString() +
201 "' not found!";
202 return std::nullopt;
203 }
204
205 std::scoped_lock l2{it->second->skillStatusesMutex};
206 return it->second->statusUpdate;
207 }
208
209 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
211 {
212 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> skillUpdates;
213
214 const std::shared_lock l(skillExecutionsMutex);
215 for (const auto& [key, impl] : skillExecutions)
216 {
217 const std::scoped_lock l2(impl->skillStatusesMutex);
218 skillUpdates.insert({key, impl->statusUpdate});
219 }
220 return skillUpdates;
221 }
222
223 std::optional<skills::SkillDescription>
225 {
227
228 const std::shared_lock l(skillFactoriesMutex);
229 if (skillFactories.find(skillId) == skillFactories.end())
230 {
231 std::stringstream ss;
232 ss << "Skill description for skill '" + skillId.toString() +
233 "' not found! Found instead: {"
234 << "\n";
235 for (const auto& [k, _] : skillFactories)
236 {
237 ss << "\t" << k.toString() << "\n";
238 }
239 ss << "}";
240 ARMARX_WARNING << ss.str();
241
242 return std::nullopt;
243 }
244
245 return skillFactories.at(skillId)->createSkillDescription(*skillId.providerId);
246 }
247
248 std::map<skills::SkillID, skills::SkillDescription>
250 {
251 std::map<skills::SkillID, skills::SkillDescription> skillDesciptions;
252 const std::shared_lock l(skillFactoriesMutex);
253 for (const auto& [key, fac] : skillFactories)
254 {
255 ARMARX_CHECK(key.isFullySpecified());
256 skillDesciptions.insert({key, fac->createSkillDescription(*key.providerId)});
257 }
258 return skillDesciptions;
259 }
260
263 const skills::SkillExecutionRequest& executionRequest)
264 {
265 ARMARX_CHECK(executionRequest.skillId.isFullySpecified());
266
267 skills::SkillExecutionID executionId{.skillId = executionRequest.skillId,
268 .executorName = executionRequest.executorName,
269 .executionStartedTime =
271
273 {executionId, executionRequest.parameters, executionRequest.callbackInterface}};
274
275 std::shared_ptr<skills::detail::SkillRuntime> runtime;
276 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> finishedToJoin;
277 {
278 auto l1 = std::unique_lock{skillFactoriesMutex};
279
280 const auto& fac = getSkillFactory(executionId.skillId);
281 ARMARX_CHECK(fac) << "Could not find a factory for skill " << executionId.skillId;
282
283 {
284 const std::unique_lock l2{skillExecutionsMutex};
285
286 // Drop terminated executions from the map. Joining must be
287 // done outside the lock to avoid blocking other API calls
288 // while we wait for a thread to finish.
289 finishedToJoin = collectFinishedExecutions_locked();
290
291 runtime = std::make_shared<skills::detail::SkillRuntime>(
292 fac,
293 executionId,
294 executionRequest.parameters,
295 executionRequest.callbackInterface);
296 skillExecutions.emplace(executionId, runtime);
297 auto const loggingLevel = parent().getEffectiveLoggingLevel();
298 ARMARX_VERBOSE << "Setting skill runtime's logging level to `"
299 << armarx::LogSender::levelToString(loggingLevel) << "`.";
300 runtime->setLocalMinimumLoggingLevel(loggingLevel);
301
302 // Capture the shared_ptr by VALUE so the runtime is kept
303 // alive for as long as the lambda runs, even if the map
304 // entry is erased concurrently. `ret` is captured by
305 // reference because we join the thread before returning
306 // from this function.
307 runtime->execution = std::thread(
308 [runtime, &ret]()
309 {
310 try
311 {
312 auto x = runtime->executeSkill();
313 ret.result = x.result;
314 ret.status = armarx::skills::toSkillStatus(x.status);
315 }
316 catch (std::exception& e)
317 {
318 ARMARX_WARNING << "Got an uncaught exception when executing a "
319 "skill. Exception was: "
320 << e.what();
321 }
322 });
323 }
324 } // 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
325
326 // Drain previously finished executions outside the lock.
327 for (auto& finished : finishedToJoin)
328 {
329 if (finished && finished->execution.joinable())
330 {
331 finished->execution.join();
332 }
333 }
334 finishedToJoin.clear();
335
336 if (runtime && runtime->execution.joinable())
337 {
338 runtime->execution.join();
339 }
340 return ret;
341 }
342
345 const skills::SkillExecutionRequest& executionRequest)
346 {
347 ARMARX_CHECK(executionRequest.skillId.isFullySpecified());
348
349 skills::SkillExecutionID executionId;
350
351 std::shared_ptr<skills::detail::SkillRuntime> runtime;
352 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> finishedToJoin;
353 {
354 auto l1 = std::unique_lock{skillFactoriesMutex};
355
356 const auto& fac = getSkillFactory(executionRequest.skillId);
357 ARMARX_CHECK(fac) << "Could not find a factory for skill " << executionRequest.skillId;
358
359 {
360 const std::unique_lock l2{skillExecutionsMutex};
361
362 // Drop terminated executions from the map.
363 finishedToJoin = collectFinishedExecutions_locked();
364
365 executionId = skills::SkillExecutionID{executionRequest.skillId,
366 executionRequest.executorName,
368
369 if (skillExecutions.count(executionId) > 0)
370 {
371 ARMARX_ERROR << "SkillsExecutionID already exists! This is undefined behaviour "
372 "and should not occur!";
373 }
374
375 runtime = std::make_shared<skills::detail::SkillRuntime>(
376 fac,
377 executionId,
378 executionRequest.parameters,
379 executionRequest.callbackInterface);
380 skillExecutions.emplace(executionId, runtime);
381 auto const loggingLevel = parent().getEffectiveLoggingLevel();
382 ARMARX_INFO << "Setting skill runtime's logging level to `"
383 << armarx::LogSender::levelToString(loggingLevel) << "`.";
384 runtime->setLocalMinimumLoggingLevel(loggingLevel);
385
386 // Capture the shared_ptr by VALUE. The function returns
387 // before the thread finishes, so a reference capture would
388 // dangle as soon as the local `runtime` variable is
389 // destroyed -> use-after-free.
390 runtime->execution = std::thread(
391 [runtime]()
392 {
393 try
394 {
395 auto x = runtime->executeSkill();
396 (void)x;
397 }
398 catch (std::exception& e)
399 {
400 ARMARX_WARNING << "Got an uncaught exception when executing a "
401 "skill. Exception was: "
402 << e.what();
403 }
404 });
405 }
406 }
407
408 // Drain previously finished executions outside the lock.
409 for (auto& finished : finishedToJoin)
410 {
411 if (finished && finished->execution.joinable())
412 {
413 finished->execution.join();
414 }
415 }
416 finishedToJoin.clear();
417
418 // wait until skill is constructed. This assures, that a status update exists.
419 while (true)
420 {
421 {
422 std::scoped_lock l(runtime->skillStatusesMutex);
423
424 if (runtime->statusUpdate.hasBeenConstructed())
425 {
426 break;
427 }
428 }
429
430 std::this_thread::sleep_for(std::chrono::milliseconds(20));
431 }
432
433 return executionId;
434 }
435
436 bool
438 const armarx::aron::data::DictPtr& input)
439 {
441
442 std::shared_ptr<skills::detail::SkillRuntime> runtime;
443 {
444 std::shared_lock l{skillExecutionsMutex};
445 auto it = skillExecutions.find(executionId);
446 if (it == skillExecutions.end())
447 {
448 ARMARX_INFO << "No acive execution for skill '" + executionId.skillId.toString() +
449 "' found! Ignoring prepareSkill request.";
450 return false;
451 }
452 runtime = it->second;
453 }
454
455 std::scoped_lock l2{runtime->skillStatusesMutex};
456 if (runtime->statusUpdate.status != skills::SkillStatus::Preparing)
457 {
458 ARMARX_INFO << "Could not prepare the skill '" + executionId.skillId.toString() +
459 "' because its not in preparing phase.";
460 return false;
461 }
462
463 runtime->updateSkillParameters(input);
464 return true;
465 }
466
467 bool
469 {
471
472 std::shared_ptr<skills::detail::SkillRuntime> runtime;
473 {
474 std::shared_lock l(skillExecutionsMutex);
475 auto it = skillExecutions.find(executionId);
476 if (it == skillExecutions.end())
477 {
478 ARMARX_INFO << "No acive execution for skill '" + executionId.skillId.toString() +
479 "' found! Ignoring abortSkill request.";
480 return false;
481 }
482 runtime = it->second;
483 }
484
485 runtime->stopSkill();
486
487 while (true)
488 {
489 {
490 std::scoped_lock l2(runtime->skillStatusesMutex);
491 auto status = runtime->statusUpdate;
492
493 if (status.hasBeenTerminated())
494 {
495 break;
496 }
497 }
498 std::this_thread::sleep_for(std::chrono::milliseconds(20));
499 }
500
501 return true;
502 }
503
504 bool
506 {
508
509 std::shared_ptr<skills::detail::SkillRuntime> runtime;
510 {
511 std::shared_lock l(skillExecutionsMutex);
512 auto it = skillExecutions.find(executionId);
513 if (it == skillExecutions.end())
514 {
515 ARMARX_INFO << "No active execution for skill '" + executionId.skillId.toString() +
516 "' found! Ignoring abortSkill request.";
517 return false;
518 }
519 runtime = it->second;
520 }
521
522 runtime->stopSkill();
523 return true;
524 }
525
526 void
528 const skills::SkillStatusUpdate& statusUpdate)
529 {
530 // Snapshot the runtimes under the lock so we can call into them
531 // without holding the lock (sub-skill status updates can be slow).
532 std::vector<std::pair<skills::SkillExecutionID,
533 std::shared_ptr<skills::detail::SkillRuntime>>>
534 snapshot;
535 {
536 std::shared_lock l(skillExecutionsMutex);
537 snapshot.reserve(skillExecutions.size());
538 for (const auto& [id, runtime] : skillExecutions)
539 {
540 snapshot.emplace_back(id, runtime);
541 }
542 }
543 for (auto& [id, runtime] : snapshot)
544 {
545 ARMARX_DEBUG << "updating subskill status for " << id.toString() << " with "
546 << statusUpdate.executionId.toString();
547 runtime->updateSubSkillStatus(statusUpdate);
548 }
549 }
550
551 const skills::manager::dti::SkillManagerInterfacePrx&
553 {
554 return manager;
555 }
556
557 std::vector<std::shared_ptr<skills::detail::SkillRuntime>>
558 SkillProviderComponentPlugin::collectFinishedExecutions_locked()
559 {
560 // Caller MUST hold an exclusive lock on skillExecutionsMutex.
561 // We move terminated entries OUT of the map (under the lock) and
562 // return them, so the caller can join the threads outside the lock.
563 // The caller is responsible for joining; the SkillRuntime will be
564 // destroyed when its shared_ptr ref count drops to zero, which is
565 // safe only AFTER the embedded std::thread has been joined.
566 std::vector<std::shared_ptr<skills::detail::SkillRuntime>> ret;
567 for (auto it = skillExecutions.begin(); it != skillExecutions.end();)
568 {
569 const auto& runtime = it->second;
570 bool terminated = false;
571 {
572 std::scoped_lock statusLock(runtime->skillStatusesMutex);
573 terminated = runtime->statusUpdate.hasBeenTerminated();
574 }
575 if (terminated)
576 {
577 ret.push_back(std::move(it->second));
578 it = skillExecutions.erase(it);
579 }
580 else
581 {
582 ++it;
583 }
584 }
585 return ret;
586 }
587} // namespace armarx::plugins
588
589namespace armarx
590{
595
596 IceUtil::Optional<skills::provider::dto::SkillDescription>
598 const skills::provider::dto::SkillID& skillId,
599 const Ice::Current& /*unused*/)
600 {
601 auto id = skills::SkillID::FromIce(skillId, skills::ProviderID{.providerName = getName()});
602 auto o = plugin->getSkillDescription(id);
603 if (o.has_value())
604 {
605 return o->toProviderIce();
606 }
607 return {};
608 }
609
610 skills::provider::dto::SkillDescriptionMap
612 {
613 skills::provider::dto::SkillDescriptionMap ret;
614 for (const auto& [k, v] : plugin->getSkillDescriptions())
615 {
616 ret.insert({k.toProviderIce(), v.toProviderIce()});
617 }
618 return ret;
619 }
620
621 IceUtil::Optional<skills::provider::dto::SkillStatusUpdate>
623 const skills::provider::dto::SkillExecutionID& executionId,
624 const Ice::Current& /*unused*/)
625 {
627 executionId, skills::ProviderID{.providerName = getName()});
628 auto o = plugin->getSkillExecutionStatus(execId);
629 if (o.has_value())
630 {
631 return o->toProviderIce();
632 }
633 return {};
634 }
635
636 skills::provider::dto::SkillStatusUpdateMap
638 {
639 skills::provider::dto::SkillStatusUpdateMap ret;
640 for (const auto& [k, v] : plugin->getSkillExecutionStatuses())
641 {
642 ret.insert({k.toProviderIce(), v.toProviderIce()});
643 }
644 return ret;
645 }
646
647 // Please not that this method waits until the skill can be scheduled!
648 skills::provider::dto::SkillStatusUpdate
650 const skills::provider::dto::SkillExecutionRequest& info,
651 const Ice::Current& /*unused*/)
652 {
654 info, skills::ProviderID{.providerName = getName()});
655 auto up = this->plugin->executeSkill(exec);
656 return up.toProviderIce();
657 }
658
659 skills::provider::dto::SkillExecutionID
661 const skills::provider::dto::SkillExecutionRequest& info,
662 const Ice::Current& current /*unused*/)
663 {
665 info, skills::ProviderID{.providerName = getName()});
666 auto id = this->plugin->executeSkillAsync(exec);
667 return id.toProviderIce();
668 }
669
670 skills::provider::dto::ParameterUpdateResult
672 const skills::provider::dto::SkillExecutionID& id,
673 const aron::data::dto::DictPtr& input,
674 const Ice::Current& current /*unused*/)
675 {
676 skills::provider::dto::ParameterUpdateResult res;
677
678 auto exec =
681 res.success = this->plugin->updateSkillParameters(exec, prep);
682 return res;
683 }
684
685 skills::provider::dto::AbortSkillResult
686 SkillProviderComponentPluginUser::abortSkill(const skills::provider::dto::SkillExecutionID& id,
687 const Ice::Current& /*unused*/)
688 {
689 skills::provider::dto::AbortSkillResult res;
690 auto exec =
692 res.success = this->plugin->abortSkill(exec);
693 return res;
694 }
695
696 skills::provider::dto::AbortSkillResult
698 const skills::provider::dto::SkillExecutionID& id,
699 const Ice::Current& /*unused*/)
700 {
701 skills::provider::dto::AbortSkillResult res;
702 auto exec =
704 res.success = this->plugin->abortSkillAsync(exec);
705 return res;
706 }
707
708 void
710 const skills::provider::dto::SkillStatusUpdate& statusUpdate,
711 const std::string& providerName,
712 const Ice::Current& /*current*/)
713 {
714 auto status = skills::SkillStatusUpdate::FromIce(statusUpdate);
715 status.executionId.skillId.providerId.emplace().providerName = providerName;
716 plugin->updateSubSkillStatus(status);
717 }
718
721 {
722 return plugin;
723 }
724} // namespace armarx
static std::string levelToString(MessageTypeT type)
MessageTypeT getEffectiveLoggingLevel() const
Definition Logging.cpp:130
const std::string & prefix() const
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
IceUtil::Optional< skills::provider::dto::SkillStatusUpdate > getSkillExecutionStatus(const skills::provider::dto::SkillExecutionID &executionId, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::SkillStatusUpdateMap getSkillExecutionStatuses(const Ice::Current &current=Ice::Current()) override
skills::provider::dto::AbortSkillResult abortSkill(const skills::provider::dto::SkillExecutionID &skill, const Ice::Current &current=Ice::Current()) override
IceUtil::Optional< skills::provider::dto::SkillDescription > getSkillDescription(const skills::provider::dto::SkillID &skill, 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
skills::provider::dto::SkillExecutionID executeSkillAsync(const skills::provider::dto::SkillExecutionRequest &executionInfo, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::AbortSkillResult abortSkillAsync(const skills::provider::dto::SkillExecutionID &skill, const Ice::Current &current=Ice::Current()) override
const std::experimental::observer_ptr< plugins::SkillProviderComponentPlugin > & getSkillProviderPlugin() const
void reportSkillEvent(const skills::provider::dto::SkillStatusUpdate &statusUpdate, const std::string &providerName, const Ice::Current &current) override
skills::provider::dto::ParameterUpdateResult updateSkillParameters(const skills::provider::dto::SkillExecutionID &executionId, const armarx::aron::data::dto::DictPtr &parameters, const Ice::Current &current=Ice::Current()) override
skills::provider::dto::SkillDescriptionMap getSkillDescriptions(const Ice::Current &current=Ice::Current()) override
static PointerType FromAronDictDTO(const data::dto::DictPtr &aron)
Definition Dict.cpp:130
static DateTime Now()
Definition DateTime.cpp:51
skills::SkillExecutionID executeSkillAsync(const skills::SkillExecutionRequest &executionInfo)
bool abortSkill(const skills::SkillExecutionID &execId)
skills::SkillStatusUpdate executeSkill(const skills::SkillExecutionRequest &executionInfo)
std::optional< skills::SkillStatusUpdate > getSkillExecutionStatus(const skills::SkillExecutionID &) const
std::optional< skills::SkillDescription > getSkillDescription(const skills::SkillID &) const
void postCreatePropertyDefinitions(PropertyDefinitionsPtr &properties) override
const skills::manager::dti::SkillManagerInterfacePrx & skillManager() const
std::map< skills::SkillExecutionID, skills::SkillStatusUpdate > getSkillExecutionStatuses() const
void addSkillFactory(std::unique_ptr< skills::SkillBlueprint > &&)
bool updateSkillParameters(const skills::SkillExecutionID &id, const armarx::aron::data::DictPtr &params)
std::map< skills::SkillID, skills::SkillDescription > getSkillDescriptions() const
void updateSubSkillStatus(const skills::SkillStatusUpdate &statusUpdate)
bool abortSkillAsync(const skills::SkillExecutionID &execId)
std::function< TerminatedSkillStatus()> FunctionType
Definition LambdaSkill.h:12
callback::dti::SkillProviderCallbackInterfacePrx callbackInterface
static SkillExecutionRequest FromIce(const manager::dto::SkillExecutionRequest &)
provider::dto::SkillExecutionRequest toProviderIce() const
std::string toString() const
Definition SkillID.cpp:68
std::optional< ProviderID > providerId
Definition SkillID.h:40
bool isFullySpecified() const
Definition SkillID.cpp:78
bool isSkillSpecified() const
Definition SkillID.cpp:84
static SkillID FromIce(const manager::dto::SkillID &)
Definition SkillID.cpp:36
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
::IceInternal::Handle< Dict > DictPtr
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
This file is part of ArmarX.
SkillStatus toSkillStatus(const ActiveOrTerminatedSkillStatus &d)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
static SkillExecutionID FromIce(const skills::manager::dto::SkillExecutionID &)
static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate &update, const std::optional< skills::ProviderID > &providerId=std::nullopt)