TaskOutcomeDebugger.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <sstream>
5#include <vector>
6
7#include <SimoxUtility/algorithm/string/string_tools.h>
8
10
12
14{
15
16 const std::string TaskOutcomeDebugger::providerName = "task_outcome_debugger";
17
25
26 void
30
31 void
33 {
34 running = true;
35
36 writer.connect(memoryNameSystem());
37 reader.connect(memoryNameSystem());
38
39 while (running)
40 {
41 this->run();
42 }
43 }
44
45 void
49
50 void
54
55 void
56 TaskOutcomeDebugger::run()
57 {
58 ARMARX_INFO << "\n--- TaskOutcome Debugger ---";
59 ARMARX_INFO << "Commands:";
60 ARMARX_INFO << " commit <taskName> <taskType> <outcome> [errorMessage]";
61 ARMARX_INFO << " taskType: GRASPING_FAMILIAR, GRASPING_KNOWN, MANIPULATION,";
62 ARMARX_INFO << " VERBALIZATION, DETECTION, NAVIGATION, SPEAKING,";
63 ARMARX_INFO << " SPECIAL, UNKNOWN";
64 ARMARX_INFO << " outcome: SUCCESS, FAILURE, ABORTED, SUSPENDED, UNKNOWN";
65 ARMARX_INFO << " Example: commit grasp_cup GRASPING_FAMILIAR SUCCESS";
66 ARMARX_INFO << " Example: commit grasp_cup GRASPING_KNOWN FAILURE gripper_timeout";
67 ARMARX_INFO << " read - read all task outcomes";
68 ARMARX_INFO << " read_type <taskType> - read outcomes by task type";
69 ARMARX_INFO << " read_failures - read only failures";
70 ARMARX_INFO << " exit - exit the debugger";
71
72 std::string command;
73 std::cin >> command;
74
75 if (command == "commit")
76 {
77 commitCommand();
78 }
79 else if (command == "read")
80 {
81 readAllCommand();
82 }
83 else if (command == "read_type")
84 {
85 readByTypeCommand();
86 }
87 else if (command == "read_failures")
88 {
89 readFailuresCommand();
90 }
91 else if (command == "exit")
92 {
93 running = false;
94 }
95 else
96 {
97 ARMARX_WARNING << "Unrecognized command: " << command;
98 }
99
100 std::cin.clear();
101 }
102
103 void
104 TaskOutcomeDebugger::commitCommand()
105 {
106 // Read the rest of the line to handle optional errorMessage
107 std::string restOfLine;
108 std::getline(std::cin, restOfLine);
109
110 std::istringstream iss(restOfLine);
111 std::string taskName, taskTypeStr, outcomeStr;
112
113 iss >> taskName >> taskTypeStr >> outcomeStr;
114
115 if (taskName.empty() || taskTypeStr.empty() || outcomeStr.empty())
116 {
118 << "Usage: commit <taskName> <taskType> <outcome> [errorMessage]";
119 return;
120 }
121
122 auto taskType = parseTaskType(taskTypeStr);
123 auto outcomeType = parseOutcomeType(outcomeStr);
124
126 simox::alg::to_upper(outcomeStr) != "UNKNOWN")
127 {
128 ARMARX_WARNING << "Unknown outcome type: " << outcomeStr << ". Using UNKNOWN.";
129 }
130
132 simox::alg::to_upper(taskTypeStr) != "UNKNOWN")
133 {
134 ARMARX_WARNING << "Unknown task type: " << taskTypeStr << ". Using UNKNOWN.";
135 }
136
137 // Read optional error message (rest of line)
138 std::optional<std::string> errorMsg;
139 std::string remaining;
140 if (std::getline(iss >> std::ws, remaining) && !remaining.empty())
141 {
142 errorMsg = remaining;
143 }
144
145 commitOutcome(taskName, taskType, outcomeType, errorMsg);
146 }
147
148 void
149 TaskOutcomeDebugger::readAllCommand()
150 {
151 armem::task_outcome::client::TaskOutcomeReader::Query query = {
152 .providerName = "",
153 .taskTypeFilter = std::nullopt,
154 .outcomeFilter = std::nullopt,
155 .timestamp = armarx::armem::Time::Now(),
156 .maxAge = armarx::Duration::Minutes(1000)};
157
158 auto result = reader.query(query);
159
160 if (not result)
161 {
162 ARMARX_WARNING << "Failed to read task outcomes: " << result.errorMessage;
163 return;
164 }
165
166 if (result.outcomes.empty())
167 {
168 ARMARX_INFO << "No task outcomes found in memory.";
169 return;
170 }
171
172 ARMARX_INFO << "Task outcomes in memory (" << result.outcomes.size() << " total):";
173 printOutcomes(result.outcomes);
174 }
175
176 void
177 TaskOutcomeDebugger::readByTypeCommand()
178 {
179 std::string taskTypeStr;
180 std::cin >> taskTypeStr;
181
182 if (taskTypeStr.empty())
183 {
184 ARMARX_WARNING << "Usage: read_type <taskType>";
185 return;
186 }
187
188 auto taskType = parseTaskType(taskTypeStr);
189
190 auto outcomes =
191 reader.queryByTaskType(taskType, armarx::Duration::Minutes(1000));
192
193 if (outcomes.empty())
194 {
195 ARMARX_INFO << "No task outcomes found for type '"
196 << taskTypeToString(taskType) << "'.";
197 return;
198 }
199
200 ARMARX_INFO << "Task outcomes of type '" << taskTypeToString(taskType) << "' ("
201 << outcomes.size() << " total):";
202 printOutcomes(outcomes);
203 }
204
205 void
206 TaskOutcomeDebugger::readFailuresCommand()
207 {
208 auto outcomes = reader.queryFailures(armarx::Duration::Minutes(1000));
209
210 if (outcomes.empty())
211 {
212 ARMARX_INFO << "No failures found in memory.";
213 return;
214 }
215
216 ARMARX_INFO << "Failures in memory (" << outcomes.size() << " total):";
217 printOutcomes(outcomes);
218 }
219
220 void
221 TaskOutcomeDebugger::commitOutcome(
222 const std::string& taskName,
225 const std::optional<std::string>& errorMessage)
226 {
227 armem::task_outcome::TaskOutcome outcome;
228 outcome.taskName = taskName;
229 outcome.taskType = taskType;
230 outcome.outcomeType = outcomeType;
231 outcome.agent = "ARMAR-7";
232 outcome.errorMessage = errorMessage;
234 outcome.endTime = armarx::DateTime::Now();
235
236 // Fill specialTaskTypeDescription for SPECIAL type
238 {
239 outcome.specialTaskTypeDescription = "custom_debug_task";
240 }
241
242 // Add fake failureInfo for FAILURE outcomes
244 {
245 armem::task_outcome::FailureInfo fi;
247 fi.specialFailureDescription = std::nullopt;
248 outcome.failureInfo = fi;
249 }
250
251 // Add fake context with required skillName, parameters, and additional entries
252 outcome.context.skillName = "GraspObject";
253 outcome.context.parameters = {{"object", "cup_01"},
254 {"approach_direction", "left"},
255 {"gripper", "right_hand"}};
256 outcome.context.additional = {{"location", "kitchen_table"},
257 {"attempt_number", "3"},
258 {"planner", "grasp_planner_v2"}};
259 outcome.context.naturalLanguageDescription = "Grasp the cup from the kitchen table using the right hand";
260 outcome.context.taskPreconditions["object_visible"] = true;
261 outcome.context.taskPreconditions["target_object"] = std::string("cup_01");
262 outcome.context.taskPreconditions["reachable_objects"] =
263 std::vector<std::string>{"cup_01", "plate_02", "bowl_03"};
264 outcome.context.taskPreconditions["min_grip_force"] = 2.5;
265
266 outcome.context.taskPostconditions["object_in_hand"] = true;
267 outcome.context.taskPostconditions["placement_surface"] = std::string("kitchen_table");
268 outcome.context.taskPostconditions["contacted_objects"] =
269 std::vector<std::string>{"cup_01"};
270 outcome.context.taskPostconditions["grip_force_applied"] = 3.7;
271
272 ARMARX_INFO << "Committing task outcome: taskName='" << taskName
273 << "' taskType=" << taskTypeToString(taskType)
274 << " outcome=" << outcomeTypeToString(outcomeType)
275 << " agent='" << outcome.agent << "'"
276 << " skill='" << outcome.context.skillName << "'"
277 << (errorMessage.has_value()
278 ? " error='" + errorMessage.value() + "'"
279 : "");
280
281 bool success =
282 writer.commitTaskOutcome(outcome, providerName, armarx::armem::Time::Now());
283
284 if (success)
285 {
286 ARMARX_INFO << "Successfully committed task outcome.";
287 }
288 else
289 {
290 ARMARX_WARNING << "Failed to commit task outcome.";
291 }
292 }
293
294 void
295 TaskOutcomeDebugger::printOutcomes(
296 const std::vector<armem::task_outcome::TaskOutcome>& outcomes)
297 {
298 for (const auto& outcome : outcomes)
299 {
300 ARMARX_INFO << " Task: " << outcome.taskName;
301 ARMARX_INFO << " Type: " << taskTypeToString(outcome.taskType);
302 ARMARX_INFO << " Outcome: " << outcomeTypeToString(outcome.outcomeType);
303 ARMARX_INFO << " Agent: " << outcome.agent;
304
305 if (outcome.specialTaskTypeDescription.has_value())
306 {
307 ARMARX_INFO << " Special type: "
308 << outcome.specialTaskTypeDescription.value();
309 }
310
311 if (outcome.errorMessage.has_value())
312 {
313 ARMARX_INFO << " Error: " << outcome.errorMessage.value();
314 }
315
316 if (outcome.failureInfo.has_value())
317 {
318 ARMARX_INFO << " Failure type: "
319 << failureTypeToString(outcome.failureInfo->failureType);
320 if (outcome.failureInfo->specialFailureDescription.has_value())
321 {
322 ARMARX_INFO << " Failure description: "
323 << outcome.failureInfo->specialFailureDescription.value();
324 }
325 }
326
327 ARMARX_INFO << " Start time: " << outcome.startTime;
328 ARMARX_INFO << " End time: " << outcome.endTime;
329
330 if (outcome.couldRecover.has_value())
331 {
332 ARMARX_INFO << " Could recover: "
333 << (outcome.couldRecover.value() ? "true" : "false");
334 }
335
336 if (outcome.recoveryInfo.has_value())
337 {
338 ARMARX_INFO << " Recovery info:";
339 ARMARX_INFO << " Time: " << outcome.recoveryInfo->recoveryTime;
340 ARMARX_INFO << " Measure: " << outcome.recoveryInfo->recoveryMeasure;
341 }
342
343 ARMARX_INFO << " Context:";
344 ARMARX_INFO << " skillName = " << outcome.context.skillName;
345 if (outcome.context.naturalLanguageDescription.has_value())
346 {
347 ARMARX_INFO << " Description: "
348 << outcome.context.naturalLanguageDescription.value();
349 }
350 if (not outcome.context.parameters.empty())
351 {
352 ARMARX_INFO << " Parameters:";
353 for (const auto& [key, value] : outcome.context.parameters)
354 {
355 ARMARX_INFO << " " << key << " = " << value;
356 }
357 }
358 if (not outcome.context.additional.empty())
359 {
360 ARMARX_INFO << " Additional:";
361 for (const auto& [key, value] : outcome.context.additional)
362 {
363 ARMARX_INFO << " " << key << " = " << value;
364 }
365 }
366 if (not outcome.context.taskPreconditions.empty())
367 {
368 ARMARX_INFO << " Preconditions:";
369 for (const auto& [key, value] : outcome.context.taskPreconditions.items())
370 {
371 ARMARX_INFO << " " << key << " = " << value.dump();
372 }
373 }
374 if (not outcome.context.taskPostconditions.empty())
375 {
376 ARMARX_INFO << " Postconditions:";
377 for (const auto& [key, value] : outcome.context.taskPostconditions.items())
378 {
379 ARMARX_INFO << " " << key << " = " << value.dump();
380 }
381 }
382
383 ARMARX_INFO << "";
384 }
385 }
386
388 TaskOutcomeDebugger::parseOutcomeType(const std::string& str)
389 {
390 std::string upper = simox::alg::to_upper(str);
391
392 if (upper == "SUCCESS")
394 if (upper == "FAILURE")
396 if (upper == "ABORTED")
398 if (upper == "SUSPENDED")
400
402 }
403
405 TaskOutcomeDebugger::parseTaskType(const std::string& str)
406 {
407 std::string upper = simox::alg::to_upper(str);
408
409 if (upper == "GRASPING_FAMILIAR")
411 if (upper == "GRASPING_KNOWN")
413 if (upper == "MANIPULATION")
415 if (upper == "VERBALIZATION")
417 if (upper == "DETECTION")
419 if (upper == "NAVIGATION")
421 if (upper == "SPEAKING")
423 if (upper == "SPECIAL")
425
427 }
428
429 std::string
430 TaskOutcomeDebugger::outcomeTypeToString(armem::task_outcome::TaskOutcomeType type)
431 {
432 switch (type)
433 {
435 return "SUCCESS";
437 return "FAILURE";
439 return "ABORTED";
441 return "SUSPENDED";
443 return "UNKNOWN";
444 }
445 return "UNKNOWN";
446 }
447
448 std::string
449 TaskOutcomeDebugger::taskTypeToString(armem::task_outcome::TaskType type)
450 {
451 switch (type)
452 {
454 return "GRASPING_FAMILIAR";
456 return "GRASPING_KNOWN";
458 return "MANIPULATION";
460 return "VERBALIZATION";
462 return "DETECTION";
464 return "NAVIGATION";
466 return "SPEAKING";
468 return "SPECIAL";
470 return "UNKNOWN";
471 }
472 return "UNKNOWN";
473 }
474
475 std::string
476 TaskOutcomeDebugger::failureTypeToString(const armem::task_outcome::FailureType& type)
477 {
478 std::vector<std::string> active;
479
481 active.push_back("Planning: NoTrajectoryFound");
482 if (type.planning.noGraspFound)
483 active.push_back("Planning: NoGraspFound");
484 if (type.planning.special)
485 active.push_back("Planning: Special");
486
488 active.push_back("Knowledge/Perception: ObjectNotDetected");
490 active.push_back("Knowledge/Perception: CameraNotWorking");
492 active.push_back("Knowledge/Retrieval: TechnicalFailure");
494 active.push_back("Knowledge/Retrieval: KnowledgeNotInMemory");
495
496 if (type.execution.robotNotMoving)
497 active.push_back("Execution: RobotNotMoving");
498 if (type.execution.handNotClosing)
499 active.push_back("Execution: HandNotClosing");
501 active.push_back("Execution: GraspingFailureDetected");
502
504 active.push_back("Interaction: NoHumanForHandover");
506 active.push_back("Interaction: DesiredObjectNotAtLocation");
508 active.push_back("Interaction: CommunicationFailure");
509
510 if (type.interruption.userStopped)
511 active.push_back("Interruption: UserStopped");
512
513 if (type.subskillFailure.failed)
514 active.push_back("SubskillFailure: " + type.subskillFailure.subskillName);
515
516 if (active.empty())
517 {
518 return "(none)";
519 }
520
521 std::string result;
522 for (size_t i = 0; i < active.size(); ++i)
523 {
524 if (i > 0)
525 result += ", ";
526 result += active[i];
527 }
528 return result;
529 }
530
531 std::string
533 {
534 return GetDefaultName();
535 }
536
537 std::string
539 {
540 return "TaskOutcomeDebugger";
541 }
542
543} // namespace armarx::components::task_outcome_debugger
std::string str(const T &t)
Default component property definition container.
Definition Component.h:70
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
static DateTime Now()
Definition DateTime.cpp:51
static Duration Minutes(std::int64_t minutes)
Constructs a duration in minutes.
Definition Duration.cpp:96
void onInitComponent() override
Pure virtual hook for the subclass.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
Pure virtual hook for the subclass.
std::string getDefaultName() const override
Retrieve default name of component.
static DateTime Now()
Definition DateTime.cpp:51
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855
std::optional< std::string > specialFailureDescription
Definition types.h:99
InterruptionFailures interruption
Definition types.h:92
InteractionFailures interaction
Definition types.h:91
KnowledgeRetrievalFailures knowledgeRetrieval
Definition types.h:58
std::optional< std::string > naturalLanguageDescription
Definition types.h:113
std::map< std::string, std::string > parameters
Definition types.h:111
std::map< std::string, std::string > additional
Definition types.h:112
armarx::core::time::DateTime startTime
Definition types.h:128
std::optional< RecoveryInfo > recoveryInfo
Definition types.h:131
std::optional< std::string > errorMessage
Definition types.h:126
armarx::core::time::DateTime endTime
Definition types.h:129
std::optional< bool > couldRecover
Definition types.h:130
std::optional< std::string > specialTaskTypeDescription
Definition types.h:123
std::optional< FailureInfo > failureInfo
Definition types.h:127