212 tab.maxEntries.setRange(1, 100);
213 tab.maxEntries.setValue(guiMaxEntries);
218 settingsGrid.
add(
Label(
"Max Entries"),
Pos{0, col++});
219 settingsGrid.
add(tab.maxEntries,
Pos{0, col++});
224 settingsGroup.
addChild(settingsGrid);
227 std::vector<armem::task_outcome::TaskOutcome> outcomes;
228 std::vector<armem::MemoryID> outcomeIds;
233 [&outcomes, &outcomeIds](
const auto& providerSegment)
235 providerSegment.forEachEntity(
236 [&outcomes, &outcomeIds](
const auto& entity)
238 entity.forEachSnapshot(
239 [&outcomes, &outcomeIds](
const auto& snapshot)
241 snapshot.forEachInstance(
242 [&outcomes, &outcomeIds](
const auto& instance)
247 armarx::task_outcome::arondto::
248 TaskOutcome::FromAron(
252 outcomes.push_back(bo);
253 outcomeIds.push_back(instance.id());
265 if (
static_cast<int>(outcomes.size()) > guiMaxEntries)
267 const int excess =
static_cast<int>(outcomes.size()) - guiMaxEntries;
268 outcomes.erase(outcomes.begin(), outcomes.begin() + excess);
269 outcomeIds.erase(outcomeIds.begin(), outcomeIds.begin() + excess);
274 std::vector<size_t> idx(outcomes.size());
275 std::iota(idx.begin(), idx.end(), 0);
276 std::sort(idx.begin(),
278 [&outcomes](
size_t a,
size_t b)
279 { return outcomes[a].endTime > outcomes[b].endTime; });
281 std::vector<armem::task_outcome::TaskOutcome> sortedOutcomes(outcomes.size());
282 std::vector<armem::MemoryID> sortedIds(outcomeIds.size());
283 for (
size_t i = 0; i < idx.size(); ++i)
285 sortedOutcomes[i] = std::move(outcomes[idx[i]]);
286 sortedIds[i] = std::move(outcomeIds[idx[i]]);
288 outcomes = std::move(sortedOutcomes);
289 outcomeIds = std::move(sortedIds);
293 if (selectedOutcomeIndex >=
static_cast<int>(outcomes.size()))
295 selectedOutcomeIndex = -1;
298 displayedOutcomeIds = outcomeIds;
301 tab.selectButtons.clear();
311 resultsGrid.
add(
Label(
"Failure Types"),
Pos{row, 3});
318 for (
int i = 0; i < static_cast<int>(outcomes.size()); ++i)
320 const auto& outcome = outcomes[i];
322 auto& btn = tab.selectButtons[i];
323 btn.setLabel(
"select");
324 btn.setValue(i == selectedOutcomeIndex);
326 const std::string failureStr =
327 outcome.failureInfo.has_value()
328 ? failureTypeSummary(outcome.failureInfo->failureType)
331 const std::string recoveredStr =
332 outcome.couldRecover.has_value()
333 ? (outcome.couldRecover.value() ?
"yes" :
"no")
336 resultsGrid.
add(btn,
Pos{row, 0});
337 resultsGrid.
add(
Label(truncateStr(outcome.taskName, 20)),
Pos{row, 1});
339 Label(outcomeTypeToString(outcome.outcomeType)),
Pos{row, 2});
340 resultsGrid.
add(
Label(truncateStr(failureStr, 50)),
Pos{row, 3});
341 resultsGrid.
add(
Label(taskTypeToString(outcome.taskType)),
Pos{row, 4});
342 resultsGrid.
add(
Label(outcome.endTime.toTimeString()),
Pos{row, 5});
345 Label(truncateStr(outcome.errorMessage.value_or(
"-"), 35)),
Pos{row, 7});
350 const std::string resultsLabel =
351 "Task Outcomes (" + std::to_string(outcomes.size()) +
" entries)";
353 resultsGroup.
setLabel(resultsLabel);
359 constexpr size_t detailMaxLen = 80;
362 if (selectedOutcomeIndex >= 0 &&
363 selectedOutcomeIndex <
static_cast<int>(outcomes.size()))
365 const auto& sel = outcomes[selectedOutcomeIndex];
366 detailGroup.
setLabel(
"Selected: " + sel.taskName);
372 detailGrid.
add(
Label(truncateStr(sel.taskName, detailMaxLen)),
Pos{row, 1});
376 detailGrid.
add(
Label(outcomeTypeToString(sel.outcomeType)),
Pos{row, 1});
380 detailGrid.
add(
Label(taskTypeToString(sel.taskType)),
Pos{row, 1});
383 if (sel.specialTaskTypeDescription.has_value())
385 detailGrid.
add(
Label(
"Special Type"),
Pos{row, 0});
386 detailGrid.
add(
Label(truncateStr(sel.specialTaskTypeDescription.value(), detailMaxLen)),
Pos{row, 1});
391 detailGrid.
add(
Label(truncateStr(sel.agent, detailMaxLen)),
Pos{row, 1});
395 detailGrid.
add(
Label(sel.startTime.toTimeString()),
Pos{row, 1});
399 detailGrid.
add(
Label(sel.endTime.toTimeString()),
Pos{row, 1});
403 detailGrid.
add(
Label(truncateStr(sel.errorMessage.value_or(
"-"), detailMaxLen)),
Pos{row, 1});
407 const std::string failureStr = sel.failureInfo.has_value()
408 ? failureTypeSummary(sel.failureInfo->failureType)
411 detailGrid.
add(
Label(
"Failure Types"),
Pos{row, 0});
412 detailGrid.
add(
Label(truncateStr(failureStr, detailMaxLen)),
Pos{row, 1});
416 if (sel.failureInfo.has_value() &&
417 sel.failureInfo->specialFailureDescription.has_value())
419 detailGrid.
add(
Label(
"Failure Desc"),
Pos{row, 0});
421 Label(truncateStr(sel.failureInfo->specialFailureDescription.value(), detailMaxLen)),
426 detailGrid.
add(
Label(
"Could Recover"),
Pos{row, 0});
428 Label(sel.couldRecover.has_value()
429 ? (sel.couldRecover.value() ?
"true" :
"false")
434 if (sel.recoveryInfo.has_value())
436 detailGrid.
add(
Label(
"Recovery Time"),
Pos{row, 0});
438 Label(sel.recoveryInfo->recoveryTime.toTimeString()),
Pos{row, 1});
441 detailGrid.
add(
Label(
"Recovery Measure"),
Pos{row, 0});
443 Label(truncateStr(sel.recoveryInfo->recoveryMeasure, detailMaxLen)),
449 detailGrid.
add(
Label(truncateStr(sel.context.skillName, detailMaxLen)),
Pos{row, 1});
452 if (sel.context.skillExecutionStartedTimestamp.has_value())
454 detailGrid.
add(
Label(
"Skill Exec Started"),
Pos{row, 0});
455 detailGrid.
add(
Label(sel.context.skillExecutionStartedTimestamp->toTimeString()),
Pos{row, 1});
459 if (sel.context.naturalLanguageDescription.has_value())
462 detailGrid.
add(
Label(truncateStr(sel.context.naturalLanguageDescription.value(), detailMaxLen)),
Pos{row, 1});
466 for (
const auto& [key, value] : sel.context.parameters)
468 detailGrid.
add(
Label(
"Param: " + key),
Pos{row, 0});
469 detailGrid.
add(
Label(truncateStr(value, detailMaxLen)),
Pos{row, 1});
473 for (
const auto& [key, value] : sel.context.additional)
475 detailGrid.
add(
Label(
"Extra: " + key),
Pos{row, 0});
476 detailGrid.
add(
Label(truncateStr(value, detailMaxLen)),
Pos{row, 1});
480 for (
const auto& [key, value] : sel.context.taskPreconditions.items())
482 detailGrid.
add(
Label(
"Precond: " + key),
Pos{row, 0});
483 detailGrid.
add(
Label(truncateStr(value.dump(), detailMaxLen)),
Pos{row, 1});
487 for (
const auto& [key, value] : sel.context.taskPostconditions.items())
489 detailGrid.
add(
Label(
"Postcond: " + key),
Pos{row, 0});
490 detailGrid.
add(
Label(truncateStr(value.dump(), detailMaxLen)),
Pos{row, 1});
498 detailGroup.
setLabel(
"Selected: (none)");
499 detailGroup.
addChild(
Label(
"Click \"select\" on a row to select an outcome."));
509 const bool hasSelection = selectedOutcomeIndex >= 0 &&
510 selectedOutcomeIndex < static_cast<int>(outcomes.size());
512 if (selectionJustChanged)
514 editStatusMessage =
"";
517 const auto& sel = outcomes[selectedOutcomeIndex];
518 editErrorText = sel.errorMessage.value_or(
"");
519 editStatus = outcomeTypeToString(sel.outcomeType);
520 editFailureType = sel.failureInfo.has_value()
521 ? sel.failureInfo->failureType
527 editStatus =
"UNKNOWN";
530 selectionJustChanged =
false;
533 tab.statusComboBox.setOptions({
"UNKNOWN",
"SUCCESS",
"FAILURE",
"ABORTED",
"SUSPENDED"});
534 tab.statusComboBox.setValue(editStatus);
537 tab.failureCheckBoxes.planningNoTrajectoryFound.setValue(editFailureType.planning.noTrajectoryFound);
538 tab.failureCheckBoxes.planningNoGraspFound.setValue(editFailureType.planning.noGraspFound);
539 tab.failureCheckBoxes.planningSpecial.setValue(editFailureType.planning.special);
540 tab.failureCheckBoxes.perceptionObjectNotDetected.setValue(editFailureType.knowledge.perception.objectNotDetected);
541 tab.failureCheckBoxes.perceptionCameraNotWorking.setValue(editFailureType.knowledge.perception.cameraNotWorking);
542 tab.failureCheckBoxes.knowledgeRetrievalTechnicalFailure.setValue(editFailureType.knowledge.knowledgeRetrieval.technicalFailure);
543 tab.failureCheckBoxes.knowledgeRetrievalKnowledgeNotInMemory.setValue(editFailureType.knowledge.knowledgeRetrieval.knowledgeNotInMemory);
544 tab.failureCheckBoxes.executionRobotNotMoving.setValue(editFailureType.execution.robotNotMoving);
545 tab.failureCheckBoxes.executionHandNotClosing.setValue(editFailureType.execution.handNotClosing);
546 tab.failureCheckBoxes.executionGraspingFailureDetected.setValue(editFailureType.execution.graspingFailureDetected);
547 tab.failureCheckBoxes.interactionNoHumanForHandover.setValue(editFailureType.interaction.noHumanForHandover);
548 tab.failureCheckBoxes.interactionDesiredObjectNotAtLocation.setValue(editFailureType.interaction.desiredObjectNotAtLocation);
549 tab.failureCheckBoxes.interactionCommunicationFailure.setValue(editFailureType.interaction.communicationFailure);
550 tab.failureCheckBoxes.interruptionUserStopped.setValue(editFailureType.interruption.userStopped);
551 tab.failureCheckBoxes.subskillFailureFailed.setValue(editFailureType.subskillFailure.failed);
552 tab.failureCheckBoxes.subskillFailureName.setValue(editFailureType.subskillFailure.subskillName);
554 tab.errorMessageInput.setValue(editErrorText);
555 tab.saveButton.setLabel(
"Save");
561 editGrid.
add(
Label(
"Select an outcome to edit."),
Pos{editRow, 0});
566 editGrid.
add(tab.statusComboBox,
Pos{editRow, 0});
572 planningGroup.
setLabel(
"Planning Failures");
574 planningGrid.
add(tab.failureCheckBoxes.planningNoTrajectoryFound,
Pos{0, 0});
575 planningGrid.
add(
Label(
"No Trajectory Found"),
Pos{0, 1});
576 planningGrid.
add(tab.failureCheckBoxes.planningNoGraspFound,
Pos{1, 0});
577 planningGrid.
add(
Label(
"No Grasp Found"),
Pos{1, 1});
578 planningGrid.
add(tab.failureCheckBoxes.planningSpecial,
Pos{2, 0});
580 planningGroup.
addChild(planningGrid);
581 editGrid.
add(planningGroup,
Pos{editRow, 0});
588 knowledgeGroup.
setLabel(
"Knowledge Failures");
591 knowledgeGrid.
add(
Label(
"-- Perception --"),
Pos{kRow, 0},
Span{1, 2});
593 knowledgeGrid.
add(tab.failureCheckBoxes.perceptionObjectNotDetected,
Pos{kRow, 0});
594 knowledgeGrid.
add(
Label(
"Object Not Detected"),
Pos{kRow, 1});
596 knowledgeGrid.
add(tab.failureCheckBoxes.perceptionCameraNotWorking,
Pos{kRow, 0});
597 knowledgeGrid.
add(
Label(
"Camera Not Working"),
Pos{kRow, 1});
599 knowledgeGrid.
add(
Label(
"-- Knowledge Retrieval --"),
Pos{kRow, 0},
Span{1, 2});
601 knowledgeGrid.
add(tab.failureCheckBoxes.knowledgeRetrievalTechnicalFailure,
Pos{kRow, 0});
602 knowledgeGrid.
add(
Label(
"Technical Failure"),
Pos{kRow, 1});
604 knowledgeGrid.
add(tab.failureCheckBoxes.knowledgeRetrievalKnowledgeNotInMemory,
Pos{kRow, 0});
605 knowledgeGrid.
add(
Label(
"Knowledge Not In Memory"),
Pos{kRow, 1});
606 knowledgeGroup.
addChild(knowledgeGrid);
607 editGrid.
add(knowledgeGroup,
Pos{editRow, 0});
614 executionGroup.
setLabel(
"Execution Failures");
616 executionGrid.
add(tab.failureCheckBoxes.executionRobotNotMoving,
Pos{0, 0});
617 executionGrid.
add(
Label(
"Robot Not Moving"),
Pos{0, 1});
618 executionGrid.
add(tab.failureCheckBoxes.executionHandNotClosing,
Pos{1, 0});
619 executionGrid.
add(
Label(
"Hand Not Closing"),
Pos{1, 1});
620 executionGrid.
add(tab.failureCheckBoxes.executionGraspingFailureDetected,
Pos{2, 0});
621 executionGrid.
add(
Label(
"Grasping Failure Detected"),
Pos{2, 1});
622 executionGroup.
addChild(executionGrid);
623 editGrid.
add(executionGroup,
Pos{editRow, 0});
630 interactionGroup.
setLabel(
"Interaction Failures");
632 interactionGrid.
add(tab.failureCheckBoxes.interactionNoHumanForHandover,
Pos{0, 0});
633 interactionGrid.
add(
Label(
"No Human For Handover"),
Pos{0, 1});
634 interactionGrid.
add(tab.failureCheckBoxes.interactionDesiredObjectNotAtLocation,
Pos{1, 0});
635 interactionGrid.
add(
Label(
"Desired Object Not At Location"),
Pos{1, 1});
636 interactionGrid.
add(tab.failureCheckBoxes.interactionCommunicationFailure,
Pos{2, 0});
637 interactionGrid.
add(
Label(
"Communication Failure"),
Pos{2, 1});
638 interactionGroup.
addChild(interactionGrid);
639 editGrid.
add(interactionGroup,
Pos{editRow, 0});
646 interruptionGroup.
setLabel(
"Interruption Failures");
648 interruptionGrid.
add(tab.failureCheckBoxes.interruptionUserStopped,
Pos{0, 0});
649 interruptionGrid.
add(
Label(
"User Stopped"),
Pos{0, 1});
650 interruptionGroup.
addChild(interruptionGrid);
651 editGrid.
add(interruptionGroup,
Pos{editRow, 0});
658 subskillGroup.
setLabel(
"Subskill Failure");
660 subskillGrid.
add(tab.failureCheckBoxes.subskillFailureFailed,
Pos{0, 0});
662 subskillGrid.
add(
Label(
"Subskill Name:"),
Pos{1, 0});
663 subskillGrid.
add(tab.failureCheckBoxes.subskillFailureName,
Pos{1, 1});
664 subskillGroup.
addChild(subskillGrid);
665 editGrid.
add(subskillGroup,
Pos{editRow, 0});
669 editGrid.
add(
Label(
"Error Message:"),
Pos{editRow, 0});
671 editGrid.
add(tab.errorMessageInput,
Pos{editRow, 0});
673 editGrid.
add(tab.saveButton,
Pos{editRow, 0});
675 const std::string messageHtml = editStatusMessage.empty()
677 :
"<font color='red'>" + editStatusMessage +
"</font>";
690 bool needsRebuild =
false;
693 editErrorText = tab.errorMessageInput.getValue();
694 editStatus = tab.statusComboBox.getValue();
695 editFailureType.planning.noTrajectoryFound = tab.failureCheckBoxes.planningNoTrajectoryFound.getValue();
696 editFailureType.planning.noGraspFound = tab.failureCheckBoxes.planningNoGraspFound.getValue();
697 editFailureType.planning.special = tab.failureCheckBoxes.planningSpecial.getValue();
698 editFailureType.knowledge.perception.objectNotDetected = tab.failureCheckBoxes.perceptionObjectNotDetected.getValue();
699 editFailureType.knowledge.perception.cameraNotWorking = tab.failureCheckBoxes.perceptionCameraNotWorking.getValue();
700 editFailureType.knowledge.knowledgeRetrieval.technicalFailure = tab.failureCheckBoxes.knowledgeRetrievalTechnicalFailure.getValue();
701 editFailureType.knowledge.knowledgeRetrieval.knowledgeNotInMemory = tab.failureCheckBoxes.knowledgeRetrievalKnowledgeNotInMemory.getValue();
702 editFailureType.execution.robotNotMoving = tab.failureCheckBoxes.executionRobotNotMoving.getValue();
703 editFailureType.execution.handNotClosing = tab.failureCheckBoxes.executionHandNotClosing.getValue();
704 editFailureType.execution.graspingFailureDetected = tab.failureCheckBoxes.executionGraspingFailureDetected.getValue();
705 editFailureType.interaction.noHumanForHandover = tab.failureCheckBoxes.interactionNoHumanForHandover.getValue();
706 editFailureType.interaction.desiredObjectNotAtLocation = tab.failureCheckBoxes.interactionDesiredObjectNotAtLocation.getValue();
707 editFailureType.interaction.communicationFailure = tab.failureCheckBoxes.interactionCommunicationFailure.getValue();
708 editFailureType.interruption.userStopped = tab.failureCheckBoxes.interruptionUserStopped.getValue();
709 editFailureType.subskillFailure.failed = tab.failureCheckBoxes.subskillFailureFailed.getValue();
710 editFailureType.subskillFailure.subskillName = tab.failureCheckBoxes.subskillFailureName.getValue();
712 if (tab.maxEntries.hasValueChanged())
714 guiMaxEntries = tab.maxEntries.getValue();
719 for (
auto& [
index, btn] : tab.selectButtons)
721 if (btn.hasValueChanged() && btn.getValue())
723 selectedOutcomeIndex =
index;
724 selectionJustChanged =
true;
727 else if (btn.hasValueChanged() && !btn.getValue() &&
728 index == selectedOutcomeIndex)
730 selectedOutcomeIndex = -1;
731 selectionJustChanged =
true;
737 if (tab.saveButton.wasClicked() && selectedOutcomeIndex >= 0 &&
738 selectedOutcomeIndex <
static_cast<int>(displayedOutcomeIds.size()))
740 const std::string newError = tab.errorMessageInput.getValue();
741 const std::string newStatus = tab.statusComboBox.getValue();
742 const auto&
id = displayedOutcomeIds[selectedOutcomeIndex];
744 const auto newOutcomeType = stringToOutcomeType(newStatus);
746 editStatusMessage =
"";
752 .getProviderSegment(
id.providerSegmentName)
753 .getEntity(
id.entityName)
755 .getInstance(
id.instanceIndex);
757 auto dto = armarx::task_outcome::arondto::TaskOutcome::FromAron(
761 dto.errorMessage = newError.empty()
762 ? std::optional<std::string>(std::nullopt)
763 : std::optional<std::string>(newError);
769 if (!dto.failureInfo.has_value())
771 armarx::task_outcome::arondto::FailureInfo fi;
774 dto.failureInfo = fi;
778 instance.data() = dto.toAron();
780 ARMARX_INFO <<
"Updated outcome for '" <<
id.entityName
781 <<
"': status=" << newStatus
782 <<
", failures=" << failureTypeSummary(editFailureType)
783 <<
", error='" << newError <<
"'";
785 catch (
const std::exception& e)
794 if (selectedOutcomeIndex < 0 && newDataAvailable.exchange(
false))