SkillImplementationWrapper.cpp
Go to the documentation of this file.
2
3#include <chrono>
4#include <exception>
5#include <mutex>
6#include <string>
7#include <thread>
8
14
15#include <RobotAPI/interface/skills/SkillManagerInterface.h>
16#include <RobotAPI/interface/skills/SkillProviderInterface.h>
21#include <RobotAPI/libraries/skills/core/aron/SkillErrorResult.aron.generated.h>
24
25namespace armarx
26{
28 {
30 const skills::SkillBlueprint* fac,
31 const skills::SkillExecutionID& execId,
32 const aron::data::DictPtr& initial_parameters,
33 const skills::callback::dti::SkillProviderCallbackInterfacePrx& callbackInterface) :
34 factory(fac), statusUpdate{{execId, initial_parameters, callbackInterface}}
35 {
36 ;
37 }
38
39 // ask a skill to stop
40 void
42 {
43 while (this->skill == nullptr)
44 {
46 << "Trying to stop a skill that has not been constructed yet... "
47 "Waiting until construction...";
48 std::this_thread::sleep_for(std::chrono::milliseconds(100));
49 }
50
51 this->skill->notifySkillToStop();
52 }
53
54 void
56 {
57 while (this->skill == nullptr)
58 {
60 << "Trying to add params to a skill that has not been constructed "
61 "yet... Waiting until construction...";
62 std::this_thread::sleep_for(std::chrono::milliseconds(100));
63 }
64
65 this->skill->updateParameters(i);
66 }
67
70 {
71 std::scoped_lock l(this->executionMutex);
72 // -------------------------------------------------------------------------------------
73 // sanity check
74 // -------------------------------------------------------------------------------------
75 ARMARX_CHECK(this->skill == nullptr)
76 << "A SKILL HAS ALREADY BEEN CONSTRUCTED. THIS SHOULD NOT HAPPEN!!";
77
78 // -------------------------------------------------------------------------------------
79 // setup basic vars and lambdas
80 // -------------------------------------------------------------------------------------
81 // actually we should lock... however this is only read access and the members are const throughout the execution...
82 ARMARX_CHECK(statusUpdate.executionId.skillId.isFullySpecified());
83
84 const auto& initial_aron_params = statusUpdate.parameters;
85 const auto& callback_interface = statusUpdate.callbackInterface;
86 const auto& skillId = statusUpdate.executionId.skillId;
87 const auto& skillName = skillId.skillName;
88 const auto& providerId = *skillId.providerId;
89 const auto& executorName = statusUpdate.executionId.executorName;
90 const auto& manager =
91 skills::manager::dti::SkillManagerInterfacePrx::checkedCast(callback_interface);
92
93 ARMARX_INFO << "Executing skill: " << skillName;
94
95 auto updateStatus =
96 [&](const SkillStatus status, const aron::data::DictPtr& data = nullptr)
97 {
98 std::unique_lock l(skillStatusesMutex);
99 statusUpdate.status = status;
100
101 statusUpdate.result = data;
102 if (skill) // if skill has been constructed
103 {
104 // update parameterization
105 statusUpdate.parameters = skill->getParameters();
106 }
107
108 if (callback_interface) // if callback interface is used
109 {
110 auto pid = providerId.toCallbackIce();
111 callback_interface->updateStatusForSkill(statusUpdate.toProviderIce(), pid);
112 }
113 };
114
115 {
116 std::unique_lock l(skillStatusesMutex);
117
118 // ---------------------------------------------------------------------------------
119 // check times
120 // ---------------------------------------------------------------------------------
122 statusUpdate.executionId.executionStartedTime) >
124 {
125 ARMARX_WARNING << "SkillError 001: For some reason the skill '"
126 << skillId.toString()
127 << "' has been scheduled > 1s ago. The execution should start "
128 "much faster! Continue, but this is bad behavior..";
129 }
130 }
131
132 // -------------------------------------------------------------------------------------
133 // construct skill
134 // -------------------------------------------------------------------------------------
135 ARMARX_INFO << "Construct skill `" << skillName << "`.";
136
137 updateStatus(SkillStatus::Constructing);
138 ARMARX_CHECK_NOT_NULL(factory) << "Skill Factory is a nullptr";
139 this->skill = this->factory->createSkill(providerId, getEffectiveLoggingLevel());
140 this->skill->setExecutorName(executorName);
141 this->skill->setManager(manager);
142 this->skill->setCallback([&](const SkillStatus s, const armarx::aron::data::DictPtr& d)
143 { updateStatus(s, d); });
144
145 // set initial parameters that were attached to the execution request (only add as we are not sure whether some updates already arrived)
146 this->updateSkillParameters(initial_aron_params);
147
148 auto makeAbortedResult = [&](const std::string& errorCode,
150 const std::string& message)
151 {
152 armarx::skills::arondto::SkillErrorResult errorResult;
153 errorResult.errorCode = errorCode;
154 errorResult.data = data;
155 errorResult.errorMessage = message;
156
157 updateStatus(SkillStatus::Aborted, errorResult.toAron());
158
159 std::unique_lock l(skillStatusesMutex);
160 auto terminated = TerminatedSkillStatusUpdate{
161 {.executionId = statusUpdate.executionId,
162 .parameters = statusUpdate.parameters,
163 .callbackInterface = statusUpdate.callbackInterface,
164 .result = statusUpdate.result}};
166 return terminated;
167 };
168
169 auto makeFailedResult = [&](const std::string& errorCode,
171 const std::string& message)
172 {
173 armarx::skills::arondto::SkillErrorResult errorResult;
174 errorResult.errorCode = errorCode;
175 errorResult.data = data;
176 errorResult.errorMessage = message;
177
178 updateStatus(SkillStatus::Failed, errorResult.toAron());
179
180 std::unique_lock l(skillStatusesMutex);
181 auto terminated = TerminatedSkillStatusUpdate{
182 {.executionId = statusUpdate.executionId,
183 .parameters = statusUpdate.parameters,
184 .callbackInterface = statusUpdate.callbackInterface,
185 .result = statusUpdate.result}};
187 return terminated;
188 };
189
190 // -------------------------------------------------------------------------------------
191 // Check params
192 // -------------------------------------------------------------------------------------
193 // NOT RELEVANT ANYMORE!!
194 // if (skill->getSkillDescription().acceptedType && initial_aron_params &&
195 // not(initial_aron_params->fullfillsType(skill->getSkillDescription().acceptedType)))
196 // {
197 // std::string message =
198 // "SkillError 002: The Skill '" + skillName +
199 // "' has a type and got parameters but the input does not match the type.";
200 // ARMARX_ERROR << message;
201 // return makeTerminationResult(message);
202 // }
203
204 auto exitAndMakeFailedResult = [&](const std::string& errorCode,
206 const std::string& message)
207 {
208 skill->exitSkill(); // try to exit skill. Ignore return value
209 return makeFailedResult(errorCode, data, message);
210 };
211 auto exitAndMakeAbortedResult = [&](const std::string& errorCode,
213 const std::string& message)
214 {
215 skill->exitSkill(); // try to exit skill. Ignore return value
216 return makeAbortedResult(errorCode, data, message);
217 };
218
219 // Construction succeeded!
220 // -------------------------------------------------------------------------------------
221 // Init skill
222 // -------------------------------------------------------------------------------------
223 ARMARX_INFO << "Init skill: " << skillName;
224 updateStatus(SkillStatus::Initializing);
225
226 try
227 {
228 Skill::InitResult initRet = skill->initSkill();
230 {
231 std::string message = "SkillError 101: The initialization of skill '" +
232 skillName + "' did not succeed.";
233 return exitAndMakeFailedResult("101", nullptr, message);
234 }
235 }
236 catch (const error::SkillAbortedException& ex)
237 {
238 return exitAndMakeAbortedResult("101x", nullptr, GetHandledExceptionString());
239 }
240 catch (const error::SkillFailedException& ex)
241 {
242 return exitAndMakeFailedResult("101x", nullptr, GetHandledExceptionString());
243 }
244 catch (const std::exception& ex)
245 {
246 std::string message =
247 "SkillError 101e: An error occured during the initialization of skill '" +
248 skillName + "'. The error was: " + GetHandledExceptionString();
249 ARMARX_ERROR << message;
250 return exitAndMakeFailedResult("101e", nullptr, message);
251 }
252
253 // Init succeeded!
254 // -------------------------------------------------------------------------------------
255 // Prepare skill
256 // -------------------------------------------------------------------------------------
257 ARMARX_INFO << "Prepare skill: " << skillName;
258 updateStatus(SkillStatus::Preparing);
259
260 try
261 {
262 auto prepareRet = skill->prepareSkill();
263 while (prepareRet.status == ActiveOrTerminatedSkillStatus::Running)
264 {
265 ARMARX_INFO << deactivateSpam() << "Not all requirements for skill "
266 << skillName << " fulfilled. Waiting...";
267
268 // wait...
269 std::this_thread::sleep_for(std::chrono::milliseconds(50));
270 prepareRet = skill->prepareSkill();
271 }
272
273 if (prepareRet.status != ActiveOrTerminatedSkillStatus::Succeeded)
274 {
275 std::string message = "SkillError 201: The prepare method of skill '" +
276 skillName + "' did not succeed. ";
277 const bool shouldSkillTerminate = skill->shouldSkillTerminate();
278 ARMARX_ERROR << message << VAROUT(shouldSkillTerminate);
279 return exitAndMakeFailedResult("201", nullptr, message);
280 }
281 }
282 catch (const error::SkillAbortedException& ex)
283 {
284 return exitAndMakeAbortedResult("201x", nullptr, GetHandledExceptionString());
285 }
286 catch (const error::SkillFailedException& ex)
287 {
288 return exitAndMakeFailedResult("201x", nullptr, GetHandledExceptionString());
289 }
290 catch (const std::exception& ex)
291 {
292 std::string message = "SkillError 201e: An error occured during waiting for skill "
293 "dependencies of skill '" +
294 skillName +
295 "'. The error was: " + GetHandledExceptionString();
296 ARMARX_ERROR << message;
297 return exitAndMakeFailedResult("201e", nullptr, message);
298 }
299
300 // Prepare succeeded!
301 // -------------------------------------------------------------------------------------
302 // Main of skill
303 // -------------------------------------------------------------------------------------
304 // execute. If the skill fails for some reason, from this point it will always execute its exit function.
305 ARMARX_INFO << "Main skill: " << skillName;
306 updateStatus(SkillStatus::Running);
307
308 Skill::MainResult mainRet;
309 try
310 {
311 mainRet = skill->mainOfSkill();
313 {
314 std::string message =
315 "SkillError 501: The main method of skill '" + skillName + "' did fail.";
316
317 return exitAndMakeFailedResult("501", mainRet.data, message);
318 }
319 else if (mainRet.status == TerminatedSkillStatus::Aborted)
320 {
321 std::string message =
322 "SkillError 501: The main method of skill '" + skillName + "' got aborted.";
323 return exitAndMakeAbortedResult("501", mainRet.data, message);
324 }
325 }
326 catch (const error::SkillAbortedException& ex)
327 {
328 return exitAndMakeAbortedResult("501x", mainRet.data, GetHandledExceptionString());
329 }
330 catch (const error::SkillFailedException& ex)
331 {
332 return exitAndMakeFailedResult("501x", mainRet.data, GetHandledExceptionString());
333 }
334 catch (const std::exception& ex)
335 {
336 std::string message =
337 "SkillError 501e: An error occured during the main method of skill '" +
338 skillName + "'. The error was: " + GetHandledExceptionString();
339 ARMARX_ERROR << message;
340 return exitAndMakeFailedResult("501e", mainRet.data, message);
341 }
342
343 // Main succeeded!
344 // -------------------------------------------------------------------------------------
345 // Exit of skill
346 // -------------------------------------------------------------------------------------
347 ARMARX_INFO << "Exit skill: " << skillName;
348 try
349 {
350 Skill::ExitResult exitRet = skill->exitSkill();
352 {
353 std::string message = "SkillError 601: The exit method of skill '" + skillName +
354 "' did not succeed.";
355 return makeFailedResult("601", mainRet.data, message);
356 }
357 }
358 catch (const error::SkillAbortedException& ex)
359 {
360 return makeAbortedResult("601x", mainRet.data, GetHandledExceptionString());
361 }
362 catch (const error::SkillFailedException& ex)
363 {
364 return makeFailedResult("601x", mainRet.data, GetHandledExceptionString());
365 }
366 catch (const std::exception& ex)
367 {
368 std::string message =
369 "SkillError 601e: An error occured during the exit method of skill '" +
370 skillName + "'. The error was: " + GetHandledExceptionString();
371 ARMARX_ERROR << message;
372 return makeFailedResult("601e", mainRet.data, message);
373 }
374
375 // Exit succeeded!
376 // All succeeded!
377 {
378 updateStatus(SkillStatus::Succeeded, mainRet.data);
379
380 // return result of main method
381 std::unique_lock l(skillStatusesMutex);
383 {.executionId = statusUpdate.executionId,
384 .parameters = statusUpdate.parameters,
385 .callbackInterface = statusUpdate.callbackInterface}};
386 ret.result = mainRet.data;
388 return ret;
389 }
390 }
391 } // namespace skills::detail
392} // namespace armarx
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
MessageTypeT getEffectiveLoggingLevel() const
Definition Logging.cpp:130
static DateTime Now()
Definition DateTime.cpp:51
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition Duration.cpp:72
void updateSkillParameters(const aron::data::DictPtr &i)
SkillRuntime(const skills::SkillBlueprint *fac, const skills::SkillExecutionID &, const aron::data::DictPtr &, const skills::callback::dti::SkillProviderCallbackInterfacePrx &)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#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_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::string GetHandledExceptionString()
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