42 #include <VirtualRobot/CollisionDetection/CollisionChecker.h>
44 #include <SimoxUtility/algorithm/string/string_tools.h>
46 #include <boost/regex.hpp>
58 interval = getProperty<int>(
"interval").getValue();
60 useWorkingMemory = getProperty<bool>(
"UseWorkingMemory").getValue();
63 workingMemoryName = getProperty<std::string>(
"WorkingMemoryName").getValue();
64 ARMARX_INFO <<
"Using WorkingMemory \"" << workingMemoryName <<
"\" to get SceneObjects." << std::endl;
66 usingTopic(getProperty<std::string>(
"WorkingMemoryListenerTopicName").getValue());
70 robotStateComponentName = getProperty<std::string>(
"RobotStateComponentName").getValue();
71 ARMARX_INFO <<
"Using RobotStateComponent \"" << robotStateComponentName <<
"\" to get SceneObjects." << std::endl;
75 std::string collisionPairsString = getProperty<std::string>(
"CollisionPairs").getValue();
76 boost::regex regexCollisionPair(
"[\\[\\{\\(](([^:,\\[\\{\\(\\]\\}\\)]+:)?([^,\\[\\{\\(\\]\\}\\)]+,|[\\[\\{\\(]([^,\\[\\{\\(\\]\\}\\)]+,)*[^,\\[\\{\\(\\]\\}\\)]+[\\]\\}\\)],)){2}[0-9]*[.]?[0-9]*[\\]\\}\\)]");
78 boost::sregex_token_iterator iterCollisionPair(collisionPairsString.begin(), collisionPairsString.end(), regexCollisionPair, 0);
79 boost::sregex_token_iterator end;
81 for (; iterCollisionPair != end; ++iterCollisionPair)
83 std::string collisionPairString = *iterCollisionPair;
84 while ((collisionPairString[0] ==
'{' && collisionPairString[collisionPairString.size() - 1] ==
'}') ||
85 (collisionPairString[0] ==
'(' && collisionPairString[collisionPairString.size() - 1] ==
')') ||
86 (collisionPairString[0] ==
'[' && collisionPairString[collisionPairString.size() - 1] ==
']'))
88 collisionPairString = collisionPairString.substr(1, collisionPairString.size() - 2);
91 if ((collisionPairString[0] ==
'{' || collisionPairString[0] ==
'(' || collisionPairString[0] ==
'[') &&
92 (collisionPairString[collisionPairString.size() - 1] ==
'}' || collisionPairString[collisionPairString.size() - 1] ==
')' || collisionPairString[collisionPairString.size() - 1] ==
']'))
94 ARMARX_ERROR <<
"Could not parse collision pair: " << *iterCollisionPair <<
". Ignoring..." << std::endl;
98 boost::regex regex(
"([^:,\\[\\{\\(\\]\\}\\)]+:)?([\\{\\[\\(][^\\{\\[\\(\\]\\}\\)]+[\\]\\}\\)]|[^\\{\\[\\(\\]\\}\\),]+)");
100 boost::sregex_token_iterator iter(collisionPairString.begin(), collisionPairString.end(), regex, 0);
101 boost::sregex_token_iterator end;
105 std::string robotName1;
106 std::vector<std::string> nodeNames1;
108 std::string nodeSetName1;
109 parseNodeSet(*iter, robotName1, nodeNames1, usesNodeSet1, nodeSetName1);
114 std::string robotName2;
115 std::vector<std::string> nodeNames2;
117 std::string nodeSetName2;
118 parseNodeSet(*iter, robotName2, nodeNames2, usesNodeSet2, nodeSetName2);
123 addCollisionPair(robotName1, nodeNames1, usesNodeSet1, nodeSetName1, robotName2, nodeNames2, usesNodeSet2, nodeSetName2, std::atof(((std::string)*iter).c_str()));
128 collisionChecker = VirtualRobot::CollisionChecker::getGlobalCollisionChecker();
130 offeringTopic(getProperty<std::string>(
"CollisionListenerTopicName").getValue());
131 offeringTopic(getProperty<std::string>(
"DistanceListenerTopicName").getValue());
133 useDebugDrawer = getProperty<bool>(
"UseDebugDrawer").getValue();
140 std::scoped_lock lockData(dataMutex);
144 if (useWorkingMemory)
146 workingMemoryPrx = getProxy<memoryx::WorkingMemoryInterfacePrx>(workingMemoryName);
147 objectInstancesPrx = workingMemoryPrx->getObjectInstancesSegment();
148 agentInstancesPrx = workingMemoryPrx->getAgentInstancesSegment();
150 for (memoryx::AgentInstanceBasePtr& agent : agentInstancesPrx->getAllAgentInstances())
155 robots.push_back({robot, robotStateComponentPrx});
164 RobotPair r = {robot, robotStateComponentPrx};
169 std::unique_lock lock(connectedMutex);
174 for (SceneObjectPair& pair : sceneObjectPairs)
176 if (!resolveCollisionPair(pair))
178 std::ostringstream nodeNames1Str;
179 std::copy(pair.nodeNames1.begin(), pair.nodeNames1.end() - 1, std::ostream_iterator<std::string>(nodeNames1Str,
","));
180 nodeNames1Str << pair.nodeNames1.back();
182 std::ostringstream nodeNames2Str;
183 std::copy(pair.nodeNames2.begin(), pair.nodeNames2.end() - 1, std::ostream_iterator<std::string>(nodeNames2Str,
","));
184 nodeNames2Str << pair.nodeNames2.back();
185 ARMARX_WARNING <<
"Could not resolve collision pair: {" << pair.robotName1 << (pair.robotName1 ==
"" ?
"" :
":") <<
"(" << nodeNames1Str.str() <<
")," << pair.robotName2 << (pair.robotName2 ==
"" ?
"" :
":") <<
"(" << nodeNames2Str.str() <<
")," << pair.warningDistance <<
"}" << std::endl;
190 collisionListenerPrx = getTopic<CollisionListenerPrx>(getProperty<std::string>(
"CollisionListenerTopicName").getValue());
191 distanceListenerPrx = getTopic<DistanceListenerPrx>(getProperty<std::string>(
"DistanceListenerTopicName").getValue());
202 debugDrawerTopicPrx = getTopic<DebugDrawerInterfacePrx>(getProperty<std::string>(
"DebugDrawerTopicName").getValue());
204 if (!debugDrawerTopicPrx)
206 ARMARX_ERROR <<
"Failed to obtain debug drawer proxy." << std::endl;
207 useDebugDrawer =
false;
216 std::unique_lock lock(connectedMutex);
221 std::scoped_lock lockData(dataMutex);
222 for (SceneObjectPair& pair : sceneObjectPairs)
224 pair.objects1 = VirtualRobot::SceneObjectSetPtr();
225 pair.objects2 = VirtualRobot::SceneObjectSetPtr();
229 if (useDebugDrawer && debugDrawerTopicPrx)
231 debugDrawerTopicPrx->clearLayer(
"distanceVisu");
232 debugDrawerTopicPrx->removeLayer(
"distanceVisu");
248 bool armarx::CollisionCheckerComponent::resolveCollisionPair(SceneObjectPair& pair)
250 std::shared_lock lockConnected(connectedMutex);
256 if (pair.usesNodeSet1 && pair.nodeSetName1 !=
"")
258 pair.nodeNames1.clear();
259 if (pair.robotName1 !=
"")
261 for (RobotPair& robotPair :
robots)
263 if (robotPair.robot->getName() == pair.robotName1)
265 VirtualRobot::SceneObjectSetPtr
set = robotPair.robot->getRobotNodeSet(pair.nodeSetName1);
270 pair.nodeNames1.push_back(
so->getName());
275 ARMARX_WARNING <<
"Robot \"" << pair.robotName1 <<
"\" has no set with name \"" << pair.nodeSetName1 <<
"\"" << std::endl;
283 ARMARX_WARNING <<
"No robot name given for RobotNodeSet \"" << pair.nodeSetName1 <<
"\"" << std::endl;
287 VirtualRobot::SceneObjectSetPtr objects1(
new VirtualRobot::SceneObjectSet());
288 for (std::string& nodeName : pair.nodeNames1)
293 ARMARX_DEBUG <<
"failed to get object: \"" << pair.robotName1 <<
"\" : \"" << nodeName <<
"\"" << std::endl;
296 if (!sc->getCollisionModel())
298 ARMARX_WARNING << pair.robotName1 << (pair.robotName1 ==
"" ?
"" :
".") << nodeName <<
" does not have a collision model. Ignoring..." << std::endl;
301 objects1->addSceneObject(sc);
304 if (pair.usesNodeSet2 && pair.nodeSetName2 !=
"")
306 pair.nodeNames2.clear();
307 if (pair.robotName2 !=
"")
309 for (RobotPair& robotPair :
robots)
311 if (robotPair.robot->getName() == pair.robotName2)
313 VirtualRobot::SceneObjectSetPtr
set = robotPair.robot->getRobotNodeSet(pair.nodeSetName2);
318 pair.nodeNames2.push_back(
so->getName());
323 ARMARX_WARNING <<
"Robot \"" << pair.robotName2 <<
"\" has no set with name \"" << pair.nodeSetName2 <<
"\"" << std::endl;
331 ARMARX_WARNING <<
"No robot name given for RobotNodeSet \"" << pair.nodeSetName2 <<
"\"" << std::endl;
335 VirtualRobot::SceneObjectSetPtr objects2(
new VirtualRobot::SceneObjectSet());
336 for (std::string& nodeName : pair.nodeNames2)
341 ARMARX_DEBUG <<
"failed to get object: \"" << pair.robotName2 <<
"\" : \"" << nodeName <<
"\"" << std::endl;
344 if (!sc->getCollisionModel())
346 ARMARX_WARNING << pair.robotName2 << (pair.robotName2 ==
"" ?
"" :
".") << nodeName <<
" does not have a collision model. Ignoring..." << std::endl;
349 objects2->addSceneObject(sc);
352 if (!objects1 || !objects2 || objects1->getSize() == 0 || objects2->getSize() == 0)
357 pair.objects1 = objects1;
358 pair.objects2 = objects2;
362 VirtualRobot::SceneObjectPtr armarx::CollisionCheckerComponent::getSceneObject(
const std::string& robotName,
const std::string& nodeName)
364 if (robotName.size() == 0 && useWorkingMemory)
366 ARMARX_DEBUG <<
"Get object from WorkingMemory: " << nodeName << std::endl;
367 return getSceneObjectFromWorkingMemory(nodeName);
369 else if (robotName.size() == 0)
372 ARMARX_DEBUG <<
"Get object from first robot: " << nodeName << std::endl;
373 return robots[0].robot->getRobotNode(nodeName);
377 ARMARX_DEBUG <<
"Searching for matching robot: " << robotName << std::endl;
378 for (RobotPair& r :
robots)
380 if (r.robot->getName() == robotName)
382 ARMARX_DEBUG <<
"Get object from robot: " << nodeName << std::endl;
383 return r.robot->getRobotNode(nodeName);
387 ARMARX_DEBUG << r.robot->getName() <<
" != " << robotName << std::endl;
395 bool armarx::CollisionCheckerComponent::parseNodeSet(
const std::string& setAsString, std::string& robotName, std::vector<std::string>& nodeNames,
bool& usesNodeSet, std::string& nodeSetName)
399 std::string nodeNamesString;
400 switch (
split.size())
404 nodeNamesString =
split[0];
407 robotName =
split[0];
408 nodeNamesString =
split[1];
414 if (nodeNamesString[0] !=
'{' && nodeNamesString[0] !=
'(' && nodeNamesString[0] !=
'[')
417 nodeSetName = nodeNamesString;
424 while ((nodeNamesString[0] ==
'{' && nodeNamesString[nodeNamesString.size() - 1] ==
'}') ||
425 (nodeNamesString[0] ==
'(' && nodeNamesString[nodeNamesString.size() - 1] ==
')') ||
426 (nodeNamesString[0] ==
'[' && nodeNamesString[nodeNamesString.size() - 1] ==
']'))
428 nodeNamesString = nodeNamesString.substr(1, nodeNamesString.size() - 2);
442 if (sc->getName() == name)
447 const memoryx::EntityBasePtr entityBase = objectInstancesPrx->getEntityByName(name);
448 const memoryx::ObjectInstanceBasePtr
object = memoryx::ObjectInstancePtr::dynamicCast(entityBase);
452 ARMARX_ERROR <<
"Could not get object with name " << name << std::endl;
456 const std::string className =
object->getMostProbableClass();
458 memoryx::ObjectClassList classes = workingMemoryPrx->getPriorKnowledge()->getObjectClassesSegment()->getClassWithSubclasses(className);
462 ARMARX_INFO_S <<
"No classes for most probable class '" << className <<
"' of object '" <<
object->getName() <<
"' with name " << name;
467 const PosePtr objectPose = armarx::PosePtr::dynamicCast(armarx::PoseBasePtr {
new armarx::Pose{
object->getPositionBase(), object->getOrientationBase()}});
471 ARMARX_ERROR <<
"Can't use object class with ice id " << classes.at(0)->ice_id() << std::endl;
476 VirtualRobot::ManipulationObjectPtr orgMo = sw->getManipulationObject();
478 std::string moName = orgMo->getName();
479 VirtualRobot::ManipulationObjectPtr mo = orgMo->clone(moName);
484 ARMARX_ERROR <<
"Can't convert pose of " << objectClass->getName() <<
" to armarx::Pose." << std::endl;
487 mo->setGlobalPose(objectPose->toEigen());
490 workingMemorySceneObjects.push_back(mo);
494 void armarx::CollisionCheckerComponent::synchronizeObjectsFromWorkingMemory()
496 std::scoped_lock lockPosition(wmPositionMutex);
499 auto it = currentPositions.find(sc->getName());
500 if (it != currentPositions.end())
502 sc->setGlobalPose(it->second->toEigen());
507 void armarx::CollisionCheckerComponent::reportDistancesAndCollisions()
509 std::scoped_lock lockData(dataMutex);
510 for (RobotPair& r :
robots)
514 synchronizeObjectsFromWorkingMemory();
516 for (SceneObjectPair& pair : sceneObjectPairs)
518 if (!pair.objects1 || !pair.objects2)
523 if (useDebugDrawer && debugDrawerTopicPrx)
525 std::ostringstream nodeNames1Str;
526 std::copy(pair.nodeNames1.begin(), pair.nodeNames1.end() - 1, std::ostream_iterator<std::string>(nodeNames1Str,
","));
527 nodeNames1Str << pair.nodeNames1.back();
529 std::ostringstream nodeNames2Str;
530 std::copy(pair.nodeNames2.begin(), pair.nodeNames2.end() - 1, std::ostream_iterator<std::string>(nodeNames2Str,
","));
531 nodeNames2Str << pair.nodeNames2.back();
533 Eigen::Vector3f p1, p2;
534 distance = collisionChecker->calculateDistance(pair.objects1, pair.objects2, p1, p2);
537 if (
distance <= pair.warningDistance)
549 debugDrawerTopicPrx->setLineVisu(
"distanceVisu", pair.robotName1 + (pair.robotName1 ==
"" ?
"" :
": ") + nodeNames1Str.str() +
" - " + pair.robotName2 + (pair.robotName2 ==
"" ?
"" :
": ") + nodeNames2Str.str(), p1a, p2a, 1, color);
553 distance = collisionChecker->calculateDistance(pair.objects1, pair.objects2);
556 distanceListenerPrx->reportDistance(pair.robotName1, pair.nodeNames1, pair.robotName2, pair.nodeNames2,
distance);
558 if (
distance <= pair.warningDistance)
560 collisionListenerPrx->reportCollisionWarning(pair.robotName1, pair.nodeNames1, pair.robotName2, pair.nodeNames2,
distance);
563 if (collisionChecker->checkCollision(pair.objects1, pair.objects2))
565 collisionListenerPrx->reportCollision(pair.robotName1, pair.nodeNames1, pair.robotName2, pair.nodeNames2,
distance);
570 void CollisionCheckerComponent::addCollisionPair(
const std::string& robotName1,
const std::vector<std::string>& nodeNames1,
const std::string& robotName2,
const std::vector<std::string>& nodeNames2,
double warningDistance,
const Ice::Current&)
572 addCollisionPair(robotName1, nodeNames1,
false,
"", robotName2, nodeNames2,
false,
"", warningDistance);
575 void CollisionCheckerComponent::addCollisionPair(
const std::string& robotName1,
const std::vector<std::string>& nodeNames1,
const bool usesNodeSet1,
const std::string& nodeSetName1,
const std::string& robotName2,
const std::vector<std::string>& nodeNames2,
const bool usesNodeSet2,
const std::string& nodeSetName2,
double warningDistance)
581 SceneObjectPair pair = {VirtualRobot::SceneObjectSetPtr(), robotName1, nodeNames1, usesNodeSet1, nodeSetName1, VirtualRobot::SceneObjectSetPtr(), robotName2, nodeNames2, usesNodeSet2, nodeSetName2, warningDistance};
582 std::scoped_lock lockData(dataMutex);
583 resolveCollisionPair(pair);
584 sceneObjectPairs.push_back(pair);
589 std::scoped_lock lockData(dataMutex);
590 for (
auto it = sceneObjectPairs.begin(); it != sceneObjectPairs.end(); it++)
592 if ((it->robotName1 == robotName1 && it->nodeNames1 == nodeNames1 &&
593 it->robotName2 == robotName2 && it->nodeNames2 == nodeNames2) ||
594 (it->robotName1 == robotName2 && it->nodeNames1 == nodeNames2 &&
595 it->robotName2 == robotName1 && it->nodeNames2 == nodeNames1))
597 sceneObjectPairs.erase(it);
605 std::scoped_lock lockData(dataMutex);
606 for (
const SceneObjectPair& pair : sceneObjectPairs)
608 if ((pair.robotName1 == robotName1 && pair.nodeNames1 == nodeNames1 &&
609 pair.robotName2 == robotName2 && pair.nodeNames2 == nodeNames2) ||
610 (pair.robotName1 == robotName2 && pair.nodeNames1 == nodeNames2 &&
611 pair.robotName2 == robotName1 && pair.nodeNames2 == nodeNames1))
619 void CollisionCheckerComponent::setWarningDistance(
const std::string& robotName1,
const std::vector<std::string>& nodeNames1,
const std::string& robotName2,
const std::vector<std::string>& nodeNames2,
double warningDistance,
const Ice::Current&)
621 std::scoped_lock lockData(dataMutex);
622 for (SceneObjectPair& pair : sceneObjectPairs)
624 if ((pair.robotName1 == robotName1 && pair.nodeNames1 == nodeNames1 &&
625 pair.robotName2 == robotName2 && pair.nodeNames2 == nodeNames2) ||
626 (pair.robotName1 == robotName2 && pair.nodeNames1 == nodeNames2 &&
627 pair.robotName2 == robotName1 && pair.nodeNames2 == nodeNames1))
629 pair.warningDistance = warningDistance;
637 std::scoped_lock lockData(dataMutex);
638 for (
const SceneObjectPair& pair : sceneObjectPairs)
640 if ((pair.robotName1 == robotName1 && pair.nodeNames1 == nodeNames1 &&
641 pair.robotName2 == robotName2 && pair.nodeNames2 == nodeNames2) ||
642 (pair.robotName1 == robotName2 && pair.nodeNames1 == nodeNames2 &&
643 pair.robotName2 == robotName1 && pair.nodeNames2 == nodeNames1))
645 return pair.warningDistance;
653 std::scoped_lock lockData(dataMutex);
654 CollisionPairList
list;
655 for (
const SceneObjectPair& pair : sceneObjectPairs)
657 armarx::CollisionPair p = {pair.robotName1, pair.nodeNames1, pair.robotName2, pair.nodeNames2, pair.warningDistance};
670 std::shared_lock lockConnected(connectedMutex);
672 if (connected && reportTask && reportTask->isRunning())
684 void CollisionCheckerComponent::reportEntityCreated(
const std::string& segmentName,
const memoryx::EntityBasePtr& entity,
const Ice::Current&)
686 if (segmentName == objectInstancesPrx->getSegmentName())
688 std::scoped_lock lockData(dataMutex);
689 for (SceneObjectPair& pair : sceneObjectPairs)
691 if ((!pair.objects1 || !pair.objects2) &&
692 ((pair.robotName1 ==
"" && std::find(pair.nodeNames1.begin(), pair.nodeNames1.end(), entity->getName()) != pair.nodeNames1.end()) ||
693 (pair.robotName2 ==
"" && std::find(pair.nodeNames2.begin(), pair.nodeNames2.end(), entity->getName()) != pair.nodeNames2.end())))
695 resolveCollisionPair(pair);
699 else if (segmentName == agentInstancesPrx->getSegmentName())
701 std::scoped_lock lockData(dataMutex);
702 memoryx::AgentInstanceBasePtr agent = agentInstancesPrx->getAgentInstanceById(entity->getId());
706 robots.push_back({robot, robotStateComponentPrx});
709 for (SceneObjectPair& pair : sceneObjectPairs)
711 if ((!pair.objects1 || !pair.objects2) &&
712 (pair.robotName1 == entity->getName() ||
713 pair.robotName2 == entity->getName()))
715 resolveCollisionPair(pair);
721 void CollisionCheckerComponent::reportEntityUpdated(
const std::string& segmentName,
const memoryx::EntityBasePtr& entityOld,
const memoryx::EntityBasePtr& entityNew,
const Ice::Current&)
723 if (segmentName == objectInstancesPrx->getSegmentName())
725 std::scoped_lock lockPosition(wmPositionMutex);
726 const memoryx::ObjectInstanceBasePtr
object = memoryx::ObjectInstancePtr::dynamicCast(entityNew);
727 currentPositions[entityNew->getName()] = armarx::PosePtr::dynamicCast(armarx::PoseBasePtr {
new armarx::Pose{
object->getPositionBase(), object->getOrientationBase()}});
731 void CollisionCheckerComponent::reportEntityRemoved(
const std::string& segmentName,
const memoryx::EntityBasePtr& entity,
const Ice::Current&)
733 if (segmentName == objectInstancesPrx->getSegmentName())
735 std::scoped_lock lockData(dataMutex);
736 for (SceneObjectPair& pair : sceneObjectPairs)
738 if ((pair.robotName1 ==
"" && std::find(pair.nodeNames1.begin(), pair.nodeNames1.end(), entity->getName()) != pair.nodeNames1.end()) ||
739 (pair.robotName2 ==
"" && std::find(pair.nodeNames2.begin(), pair.nodeNames2.end(), entity->getName()) != pair.nodeNames2.end()))
741 pair.objects1.reset();
742 pair.objects2.reset();
745 for (
auto it = workingMemorySceneObjects.begin(); it != workingMemorySceneObjects.end(); ++it)
747 if ((*it)->getName() == entity->getName())
749 workingMemorySceneObjects.erase(it);
754 else if (segmentName == agentInstancesPrx->getSegmentName())
756 std::scoped_lock lockData(dataMutex);
757 for (
auto it =
robots.begin(); it !=
robots.end(); ++it)
759 if ((*it).robot->getName() == entity->getName())
766 for (SceneObjectPair& pair : sceneObjectPairs)
768 if (pair.robotName1 == entity->getName() ||
769 pair.robotName2 == entity->getName())
771 pair.objects1.reset();
772 pair.objects2.reset();
778 void CollisionCheckerComponent::reportSnapshotLoaded(
const std::string& segmentName,
const Ice::Current&)
780 if (segmentName == objectInstancesPrx->getSegmentName())
782 std::scoped_lock lockData(dataMutex);
783 for (SceneObjectPair& pair : sceneObjectPairs)
785 if (!pair.objects1 || !pair.objects2)
787 resolveCollisionPair(pair);
793 void CollisionCheckerComponent::reportSnapshotCompletelyLoaded(
const Ice::Current&
c)
798 void CollisionCheckerComponent::reportMemoryCleared(
const std::string& segmentName,
const Ice::Current&)
800 if (segmentName == objectInstancesPrx->getSegmentName())
802 std::scoped_lock lockData(dataMutex);
803 for (SceneObjectPair& pair : sceneObjectPairs)
805 if (pair.robotName1 ==
"" || pair.robotName2 ==
"")
807 pair.objects1.reset();
808 pair.objects2.reset();