28 #include <VirtualRobot/LinkedCoordinate.h>
29 #include <VirtualRobot/math/Helpers.h>
39 #include <MemoryX/interface/components/WorkingMemoryInterface.h>
50 classSegmentName(
"objectClasses"),
51 instanceSegmentName(
"objectInstances"),
52 agentInstancesSegmentName(
"agentInstances"),
53 referenceFrameName(
"Platform")
63 this->classSegmentName = classSegmentName;
64 this->instanceSegmentName = instanceSegmentName;
72 this->referenceFrameName = referenceFrameName;
84 objectClassSegment = getSegment<ObjectClassMemorySegmentBase>(classSegmentName);
85 objectInstanceSegment = getSegment<ObjectInstanceMemorySegment>(instanceSegmentName);
86 agentInstancesSegment = getSegment<AgentInstancesSegment>(agentInstancesSegmentName);
92 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
93 usingProxy(getProperty<std::string>(
"LongtermMemoryName").getValue());
96 if (!getProperty<std::string>(
"RobotStateObserverName").getValue().
empty())
98 usingProxy(getProperty<std::string>(
"RobotStateObserverName").getValue());
101 if (!getProperty<std::string>(
"CommonPlacesLearnerName").getValue().
empty())
103 usingProxy(getProperty<std::string>(
"CommonPlacesLearnerName").getValue());
106 workingMemoryName = getProperty<std::string>(
"WorkingMemoryName").getValue();
107 checkFieldOfView = getProperty<bool>(
"CheckFieldOfView").getValue();
108 cameraOpeningAngle = getProperty<float>(
"CameraOpeningAngle").getValue();
109 robotNodeNameLeftCamera = getProperty<std::string>(
"RobotNodeNameLeftCamera").getValue();
110 robotNodeNameRightCamera = getProperty<std::string>(
"RobotNodeNameRightCamera").getValue();
111 handNodeNameLeft = getProperty<std::string>(
"HandNodeNameLeft").getValue();
112 handNodeNameRight = getProperty<std::string>(
"HandNodeNameRight").getValue();
113 headMotionVelocityLimit = getProperty<float>(
"HeadMotionVelocityLimit").getValue();
115 if (checkFieldOfView)
117 ARMARX_IMPORTANT <<
"Objects will only be localized when they are assumed to be in the field of view";
121 ARMARX_IMPORTANT <<
"Objects will always be localized, even when they are not in the field of view";
128 robotStateInterfacePrx = getProxy<armarx::RobotStateComponentInterfacePrx>(getProperty<std::string>(
"RobotStateComponentName").getValue());
129 longtermMemoryPrx = getProxy<memoryx::LongtermMemoryInterfacePrx>(getProperty<std::string>(
"LongtermMemoryName").getValue());
130 auto robot = robotStateInterfacePrx->getSynchronizedRobot();
131 referenceFrameName = robot->getRootNode()->getName();
132 agentName = robot->getName();
134 if (!getProperty<std::string>(
"RobotStateObserverName").getValue().
empty())
136 robotStateObserverProxy = getProxy<armarx::ObserverInterfacePrx>(getProperty<std::string>(
"RobotStateObserverName").getValue());
137 headTCPVelocityDatafieldID =
new armarx::DataFieldIdentifier(getProperty<std::string>(
"RobotStateObserverName").getValue(),
"TCPVelocities", getProperty<std::string>(
"GazeTCPName").getValue());
140 if (!getProperty<std::string>(
"CommonPlacesLearnerName").getValue().
empty())
142 commonPlacesLearnerProxy = getProxy<memoryx::CommonPlacesLearnerInterfacePrx>(getProperty<std::string>(
"CommonPlacesLearnerName").getValue());
148 localizationTask->start();
154 if (localizationTask)
156 localizationTask->stop();
171 if (segmentName != classSegmentName)
177 ObjectClassPtr objectClassOld = ObjectClassPtr::dynamicCast(entityOld);
178 ObjectClassPtr objectClassNew = ObjectClassPtr::dynamicCast(entityNew);
180 if (!objectClassOld || !objectClassNew)
188 LocalizationQueryList queriesOld = recognitionWrapperOld->getLocalizationQueries();
189 LocalizationQueryList queriesNew = recognitionWrappeNew->getLocalizationQueries();
191 std::unique_lock lock(jobsMutex);
194 LocalizationQueryList queriesCreated = getMissingQueries(queriesOld, queriesNew);
196 for (LocalizationQueryList::iterator iter = queriesCreated.begin(); iter != queriesCreated.end(); iter++)
199 ARMARX_INFO <<
"Adding new query " << query->queryName;
202 std::vector<LocalizationJobPtr> createdjobs = query->createJobs(objectClassSegment);
209 std::move(createdjobs.begin(), createdjobs.end(), std::back_inserter(jobs));
213 LocalizationQueryList queriesRemoved = getMissingQueries(queriesNew, queriesOld);
215 for (LocalizationQueryList::iterator iter = queriesRemoved.begin(); iter != queriesRemoved.end(); iter++)
220 std::vector<LocalizationJobPtr>::iterator iterJobs = jobs.begin();
222 while (iterJobs != jobs.end())
224 if ((*iterJobs)->getQueryName() == query->queryName)
226 iterJobs = jobs.erase(iterJobs);
234 ARMARX_INFO <<
"removed query " << query->queryName;
244 void ObjectLocalizationMemoryUpdater::predictPoses()
246 std::unique_lock lock(predictionMutex);
248 EntityIdList allEntityIDs = objectInstanceSegment->getAllEntityIds();
250 for (EntityIdList::iterator it = allEntityIDs.begin(); it != allEntityIDs.end(); it++)
252 auto entity = objectInstanceSegment->getEntityById(*it);
267 ARMARX_DEBUG <<
deactivateSpam(5, objectInstance->getName()) <<
"prediction for " << objectInstance->getName() <<
" motion model: " << objectInstance->getMotionModel()->ice_id();
269 armarx::LinkedPosePtr predictedPose = armarx::LinkedPosePtr::dynamicCast(motionModel->getPredictedPose());
270 MultivariateNormalDistributionBasePtr positionUncertainty = motionModel->getUncertainty();
273 ARMARX_DEBUG <<
deactivateSpam(1, objectInstance->getName()) <<
"last localization: " << objectInstance->getMotionModel()->getPoseAtLastLocalisation()->output();
275 if (positionUncertainty)
277 ARMARX_DEBUG <<
deactivateSpam(1, objectInstance->getName()) <<
"positionUncertainty->getDimensions(): " << positionUncertainty->getDimensions();
282 if (predictedPose->frame.empty())
284 ARMARX_VERBOSE <<
"predicting pose of " << objectInstance->getName() <<
" position: "
285 << predictedPose->position->x <<
" " << predictedPose->position->y <<
" " << predictedPose->position->z <<
" frame: " << predictedPose->frame;
289 objectInstance->setPosition(
new armarx::FramedPosition(predictedPose->toEigen(), predictedPose->frame, predictedPose->agent));
290 objectInstance->setOrientation(
new armarx::FramedOrientation(predictedPose->toEigen(), predictedPose->frame, predictedPose->agent));
292 if (positionUncertainty)
294 objectInstance->setPositionUncertainty(positionUncertainty);
297 objectInstance->setClass(objectInstance->getMostProbableClass(), objectInstance->getClassProbability(objectInstance->getMostProbableClass()));
298 objectInstance->setExistenceCertainty(objectInstance->getExistenceCertainty());
300 if (objectInstanceSegment->getListenerProxy() && objectInstanceSegment->hasEntityById(objectInstance->getId(), Ice::emptyCurrent))
302 auto reportClone = objectInstance->clone();
303 objectInstanceSegment->getListenerProxy()->reportEntityUpdated(objectInstanceSegment->getSegmentName(), reportClone, reportClone);
320 void ObjectLocalizationMemoryUpdater::scheduleJobs()
325 std::unique_lock lock(jobsMutex);
328 std::multimap<std::string, LocalizationJobPtr> recognizerJobs;
329 std::set<std::string> recognizerNames;
331 bool aJobIsWaiting =
false;
337 recognizerJobs.insert(std::make_pair(job->getRecognitionMethod(), job));
338 recognizerNames.insert(job->getRecognitionMethod());
340 aJobIsWaiting =
true;
356 Eigen::Vector3f tcpVelocity;
357 tcpVelocity.setZero();
359 if (robotStateObserverProxy)
361 if (robotStateObserverProxy->existsDataField(headTCPVelocityDatafieldID->getChannelName(), headTCPVelocityDatafieldID->getDataFieldName()))
363 tcpVelocity = armarx::VariantPtr::dynamicCast(robotStateObserverProxy->getDataField(headTCPVelocityDatafieldID))->get<
armarx::FramedDirection>()->
toEigen();
370 if (tcpVelocity.norm() > headMotionVelocityLimit)
377 for (
const auto& recognitionMethod : recognizerNames)
381 if (isRecognitionMethodRunning(recognitionMethod))
390 std::pair< std::map<std::string, LocalizationJobPtr>::iterator, std::map<std::string, LocalizationJobPtr>::iterator> elements = recognizerJobs.equal_range(recognitionMethod);
391 std::map<std::string, LocalizationJobPtr>::iterator iterElements = elements.first;
395 std::unique_lock lockPrediction(predictionMutex, std::defer_lock);
397 if (lockPrediction.try_lock())
399 while (iterElements != elements.second)
404 std::vector<std::string> classNames = job->getAllClassNames();
405 std::vector<std::string> classNamesToBeLocalized;
407 for (
size_t i = 0; i < classNames.size(); i++)
409 ObjectInstanceList instances = objectInstanceSegment->getObjectInstancesByClass(classNames.at(i));
411 if (instances.size() != 0)
413 bool atLeastOneInstanceIsVisibleOrLost =
false;
415 for (
size_t j = 0; j < instances.size(); j++)
418 float existenceCertainty = instance->getExistenceCertainty();
421 if (checkObjectVisibility(pos) || existenceCertainty < 0.5f)
423 atLeastOneInstanceIsVisibleOrLost =
true;
427 if (atLeastOneInstanceIsVisibleOrLost)
429 for (
const auto& instance : instances)
431 if (ObjectInstancePtr::dynamicCast(instance)->getMotionModel())
433 ObjectInstancePtr::dynamicCast(instance)->getMotionModel()->savePredictedPoseAtStartOfCurrentLocalization();
437 classNamesToBeLocalized.push_back(classNames.at(i));
441 ARMARX_INFO <<
deactivateSpam(5, classNames.at(i)) <<
"Not trying to localize " << classNames.at(i) <<
" because it is currently not in the field of view";
447 classNamesToBeLocalized.push_back(classNames.at(i));
452 if (classNamesToBeLocalized.size() > 0)
454 job->setClassNamesToBeLocalized(classNamesToBeLocalized);
455 container->addJob(job);
466 startLocalization(container);
478 ARMARX_ERROR <<
"predicting poses caused an exception!";
483 void ObjectLocalizationMemoryUpdater::runJobs()
489 catch (std::exception&)
501 ObjectClassNameList objectClassNames = jobContainer->getClassNamesUnique();
502 std::string recognitionMethod = jobContainer->getRecognitionMethod();
504 ObjectLocalizerInterfacePrx proxy = getProxyCached(recognitionMethod);
510 finishJobContainer(jobContainer);
518 auto robotName = robotStateInterfacePrx->getSynchronizedRobot()->getName();
520 jobContainer->setRobotState(sharedRobotProxy);
524 robotPose = armarx::PosePtr::dynamicCast(sharedRobotProxy->getGlobalPose());
527 jobContainer->setRobotPose(robotPose);
532 setRecognitionMethodRunningState(recognitionMethod,
true);
534 jobContainer->startJobs();
535 ARMARX_VERBOSE <<
deactivateSpam(5, jobContainer->getRecognitionMethod()) <<
"starting localization of " << objectClassNames <<
" with " << jobContainer->getRecognitionMethod();
536 proxy->begin_localizeObjectClasses(objectClassNames, Ice::newCallback(
this, &ObjectLocalizationMemoryUpdater::localizationFinished), jobContainer);
542 bool ObjectLocalizationMemoryUpdater::isRecognitionMethodRunning(
const std::string& recognitionMethod)
544 std::unique_lock lock(recognitionMethodStateMutex);
545 std::map<std::string, bool>::iterator iter = recognitionMethodRunning.find(recognitionMethod);
547 if (iter == recognitionMethodRunning.end())
552 bool result = recognitionMethodRunning[recognitionMethod];
559 void ObjectLocalizationMemoryUpdater::setRecognitionMethodRunningState(
const std::string& recognitionMethod,
bool running)
561 std::unique_lock lock(recognitionMethodStateMutex);
563 recognitionMethodRunning[recognitionMethod] =
running;
571 jobContainer->finishJobs();
572 setRecognitionMethodRunningState(jobContainer->getRecognitionMethod(),
false);
574 updateQueries(jobContainer);
578 void ObjectLocalizationMemoryUpdater::localizationFinished(
const Ice::AsyncResultPtr& r)
581 ObjectLocalizerInterfacePrx objectLocalizer = ObjectLocalizerInterfacePrx::uncheckedCast(r->getProxy());
583 ObjectLocalizationResultList resultList;
587 resultList = objectLocalizer->end_localizeObjectClasses(r);
590 if (jobContainer->getClassNamesUnique().empty())
592 ARMARX_WARNING <<
"There is a bug: Returned from localization, but list of class names is empty";
593 finishJobContainer(jobContainer);
596 std::string allObjectNames;
598 for (
size_t i = 0; i < jobContainer->getClassNamesUnique().size(); i++)
600 allObjectNames.append(jobContainer->getClassNamesUnique().at(i));
601 allObjectNames.append(
" ");
604 ARMARX_DEBUG <<
deactivateSpam(1) <<
"Localization of " << allObjectNames <<
" returned - number of detected instances: " << resultList.size();
607 if (resultList.empty())
610 if (checkFieldOfView)
612 ObjectInstanceList instances = objectInstanceSegment->getObjectInstancesByClass(jobContainer->getClassNamesUnique().at(0));
614 if (instances.size() == 1)
617 float oldExistenceCertainty = instance->getExistenceCertainty();
618 instance->setExistenceCertainty(getProperty<float>(
"ExistenceCertaintyReductionFactorWhenLocalizationFailed").
getValue() * oldExistenceCertainty);
621 ARMARX_INFO <<
deactivateSpam(3, instance->getName()) << instance->getName() <<
" not found in view altough it should be there - decreasing existence certainty to: " << instance->getExistenceCertainty();
622 if (objectInstanceSegment->getListenerProxy() && objectInstanceSegment->hasEntityById(instance->getId(), Ice::emptyCurrent))
624 auto reportClone = instance->clone();
625 objectInstanceSegment->getListenerProxy()->reportEntityUpdated(objectInstanceSegment->getSegmentName(), reportClone, reportClone);
628 else if (instances.size() > 1)
630 ARMARX_IMPORTANT <<
"Dealing with failed localizations is not implemented for the case that multiple instances exist";
637 const std::string rootNodeName = jobContainer->getRobotState()->getRootNode()->getName();
638 for (
const ObjectLocalizationResult& result : resultList)
641 if (result.objectClassName.empty())
643 ARMARX_ERROR <<
"Object name in localization result is empty";
648 if (result.timeStamp)
652 ARMARX_INFO <<
deactivateSpam(3) <<
"object pose is already " << (now - timestamp->toTime()).toMilliSecondsDouble() <<
"ms old";
653 robotState = robotStateInterfacePrx->getRobotSnapshotAtTimestamp(timestamp->getTimestamp());
657 <<
"(possibly a bug in the simulation, time server, or something else)";
658 robotState = robotStateInterfacePrx->getRobotSnapshot(
"");
660 robotPose = armarx::PosePtr::dynamicCast(robotState->getGlobalPose());
661 jobContainer->setRobotState(robotState);
662 jobContainer->setRobotPose(robotPose);
666 ARMARX_WARNING <<
deactivateSpam(1, jobContainer->getRecognitionMethod()) <<
"Recognition method " << jobContainer->getRecognitionMethod() <<
" did not provide a timestamp - using robotstate from before starting recognition";
671 ObjectInstancePtr update =
new ObjectInstance(result.instanceName.empty() ? result.objectClassName : result.instanceName);
672 update->setLocalizationTimestamp(result.timeStamp);
677 Eigen::Vector3f positionBeforeFrameChange = measuredPosition->toEigen();
678 measuredPosition->changeFrame(robotState, rootNodeName);
679 measuredOrientation->changeFrame(robotState, rootNodeName);
680 Eigen::Vector3f positionTranslation = measuredPosition->toEigen() - positionBeforeFrameChange;
682 measuredOrientation->toEigen());
685 <<
"New pose from localizer: " << measuredPose <<
" (in reference frame " << measuredPosition->frame <<
")";
692 update->setPosition(posInRef);
693 update->setOrientation(orientationInRef);
698 if (
q->className == result.objectClassName)
700 priority =
q->priority;
703 update->setLocalizationPriority(priority);
710 MultivariateNormalDistributionBasePtr uncertaintyInRef = result.positionNoise;
711 auto mean = uncertaintyInRef->getMean();
712 if (
mean.size() == 3)
714 Eigen::Vector3f meanEigen(
mean.at(0),
mean.at(1),
mean.at(2));
715 meanEigen += positionTranslation;
718 update->setPositionUncertainty(uncertaintyInRef);
721 update->addClass(result.objectClassName, result.recognitionCertainty);
724 ARMARX_INFO <<
deactivateSpam(5, result.objectClassName) << result.objectClassName <<
": existence certainty: " << result.recognitionCertainty;
725 update->setExistenceCertainty(result.recognitionCertainty);
728 ObjectInstancePtr correspondingEntity = ObjectInstancePtr::dynamicCast(objectInstanceSegment->getCorrespondingObjectInstance(
update));
731 if (!correspondingEntity)
735 if (!
update->getMotionModel())
740 update->getMotionModel()->setPoseAtLastLocalisation(linkedPose, robotPose, uncertaintyInRef);
741 objectInstanceSegment->addEntity(
update);
747 std::unique_lock lock(predictionMutex);
749 if (!correspondingEntity->getMotionModel())
751 ARMARX_IMPORTANT <<
"Corresponding entity has no motion model, creating a new one";
752 setMotionModel(correspondingEntity);
753 correspondingEntity->getMotionModel()->setPoseAtLastLocalisation(linkedPose, robotPose, uncertaintyInRef);
756 AbstractMotionModelPtr motionModel = ObjectInstancePtr::dynamicCast(correspondingEntity)->getMotionModel();
762 objectInstanceSegment->updateEntityInternal(correspondingEntity->getId(),
update);
766 ObjectInstancePtr objectInstance = ObjectInstancePtr::dynamicCast(objectInstanceSegment->getEntityById(correspondingEntity->getId()));
769 ARMARX_DEBUG <<
update->getName() <<
" obj Pose from memory: " << objectInstance->getPose()->output() <<
" robot global pose: " << jobContainer->getRobotState()->getGlobalPose()->output();
770 objectInstance->setLocalizationTimestamp(result.timeStamp);
772 ARMARX_DEBUG <<
"Ori after fusion: " << *objectInstance->getOrientation();
774 motionModel->setPoseAtLastLocalisation(linkedObjectPose, robotPose, objectInstance->getPositionUncertainty());
775 armarx::LinkedPosePtr predictedPose = armarx::LinkedPosePtr::dynamicCast(motionModel->getPredictedPose());
777 objectInstance->setPose(predictedPose);
786 if (commonPlacesLearnerProxy)
791 commonPlacesLearnerProxy->learnFromObject(
update);
801 catch (std::exception& e)
803 ARMARX_ERROR <<
deactivateSpam(2, jobContainer->getRecognitionMethod()) <<
"Localization failed of type " << jobContainer->getRecognitionMethod() <<
"\nReason: " << e.what();
809 finishJobContainer(jobContainer);
817 std::vector<LocalizationQueryPtr> queries = jobContainer->getQueries();
819 for (std::vector<LocalizationQueryPtr>::iterator iter = queries.begin() ; iter != queries.end() ; iter++)
823 if (query->getFinished())
826 EntityBasePtr entity = objectClassSegment->getEntityByName(query->className, Ice::emptyCurrent);
835 recognitionWrapper->updateLocalizationQuery(query->queryName, query);
841 objectClassSegment->updateClass(query->className, objectClass);
850 ObjectLocalizerInterfacePrx ObjectLocalizationMemoryUpdater::getProxyCached(
const std::string& recognitionMethod)
853 std::map<std::string, ObjectLocalizerInterfacePrx>::iterator iter;
854 iter = knownObjectProxies.find(recognitionMethod);
856 if (iter != knownObjectProxies.end())
863 ObjectLocalizerInterfacePrx objectLocalizerProxy;
867 objectLocalizerProxy =
getWorkingMemory()->getProxy<ObjectLocalizerInterfacePrx>(recognitionMethod);
875 if (objectLocalizerProxy)
877 std::pair<std::string, ObjectLocalizerInterfacePrx> entry;
878 entry.first = recognitionMethod;
879 entry.second =
getWorkingMemory()->getProxy<ObjectLocalizerInterfacePrx>(recognitionMethod);
881 knownObjectProxies.insert(entry);
884 return objectLocalizerProxy;
890 LocalizationQueryList ObjectLocalizationMemoryUpdater::getMissingQueries(
const LocalizationQueryList& queriesBase,
const LocalizationQueryList& queriesCompare)
892 LocalizationQueryList missing;
894 for (LocalizationQueryList::const_iterator iter = queriesCompare.begin() ; iter != queriesCompare.end() ; iter++)
898 for (LocalizationQueryList::const_iterator iterBase = queriesBase.begin() ; iterBase != queriesBase.end(); iterBase++)
900 if ((*iterBase)->queryName == (*iter)->queryName)
908 missing.push_back(*iter);
920 if (!checkFieldOfView)
925 auto robot = robotStateInterfacePrx->getSynchronizedRobot();
927 posInLeftCamCS->changeFrame(robot, robotNodeNameLeftCamera);
928 Eigen::Vector3f positionInLeftCamCS = posInLeftCamCS->toEigen();
930 posInRightCamCS->changeFrame(robot, robotNodeNameRightCamera);
931 Eigen::Vector3f positionInRightCamCS = posInRightCamCS->toEigen();
934 if (positionInLeftCamCS(2) > getProperty<float>(
"MaximalObjectDistance").
getValue())
939 Eigen::Vector3f viewDirection = Eigen::Vector3f::UnitZ();
940 positionInLeftCamCS.normalize();
941 positionInRightCamCS.normalize();
942 float angleLeft = acos(viewDirection.dot(positionInLeftCamCS));
943 float angleRight = acos(viewDirection.dot(positionInRightCamCS));
945 if (2 * angleLeft < cameraOpeningAngle && 2 * angleRight < cameraOpeningAngle)
955 void ObjectLocalizationMemoryUpdater::setMotionModel(
ObjectInstancePtr& objectInstance)
957 std::string objectClassName = objectInstance->getMostProbableClass();
959 ObjectClassPtr objectClass = ObjectClassPtr::dynamicCast(objectClassSegment->getEntityByName(objectClassName));
962 if (!recognitionWrapper)
964 recognitionWrapper = objectClass->addWrapper(
new EntityWrappers::ObjectRecognitionWrapper());
967 std::string motionModelName = recognitionWrapper->getDefaultMotionModel();
968 ARMARX_INFO <<
"Motion model is " << motionModelName;
972 switch (motionModelType)
976 motionModel =
new MotionModelStaticObject(robotStateInterfacePrx);
982 std::string handNodeName;
984 if (objectClassName.find(
"left") != std::string::npos || objectClassName.find(
"Left") != std::string::npos)
986 handNodeName = handNodeNameLeft;
990 handNodeName = handNodeNameRight;
993 ARMARX_INFO <<
"The hand node name in the kinematic model is assumed to be " << handNodeName;
994 motionModel =
new MotionModelRobotHand(robotStateInterfacePrx, handNodeName);
1002 motionModel =
new MotionModelKBM(getProperty<std::string>(
"KBMReferenceNodeName").
getValue(), getProperty<std::string>(
"KBMLeftArmNodeSetName").
getValue(), robotStateInterfacePrx, longtermMemoryPrx);
1006 motionModel =
new MotionModelKBM(getProperty<std::string>(
"KBMReferenceNodeName").
getValue(), getProperty<std::string>(
"KBMRightArmNodeSetName").
getValue(), robotStateInterfacePrx, longtermMemoryPrx);
1013 ARMARX_WARNING <<
"Motion model type " << motionModelName <<
" not yet implemented here!";
1014 motionModel =
new MotionModelStaticObject(robotStateInterfacePrx);
1018 objectInstance->setMotionModel(motionModel);