29 #include <SimoxUtility/algorithm/string/string_tools.h> 
   30 #include <VirtualRobot/CollisionDetection/CollisionChecker.h> 
   31 #include <VirtualRobot/CollisionDetection/CollisionModel.h> 
   32 #include <VirtualRobot/Nodes/RobotNode.h> 
   33 #include <VirtualRobot/Obstacle.h> 
   34 #include <VirtualRobot/Robot.h> 
   35 #include <VirtualRobot/RobotNodeSet.h> 
   48 #define FLOOR_OBJ_STR "FLOOR" 
   53     SelfCollisionChecker::_preOnInitRobotUnit()
 
   57         selfCollisionAvoidanceRobot = _module<RobotData>().cloneRobot(
true);
 
   60             const std::string colModelsString =
 
   61                 getProperty<std::string>(
"SelfCollisionCheck_ModelGroupsToCheck").getValue();
 
   62             std::vector<std::string> groups;
 
   63             if (!colModelsString.empty())
 
   67             ARMARX_DEBUG << 
"Processing groups for self collision checking:";
 
   68             for (std::string& group : groups)
 
   72                 simox::alg::trim_if(group, 
" \t{}");
 
   73                 std::set<std::set<std::string>> setsOfNode;
 
   76                     if (splittedRaw.size() < 2)
 
   80                     for (
auto& subentry : splittedRaw)
 
   82                         simox::alg::trim_if(subentry, 
" \t{}");
 
   83                         if (selfCollisionAvoidanceRobot->hasRobotNodeSet(subentry))
 
   85                             std::set<std::string> nodes;
 
   87                             for (
const auto& node :
 
   88                                  selfCollisionAvoidanceRobot->getRobotNodeSet(subentry)
 
   91                                 if (!node->getCollisionModel())
 
   96                                                    << node->getName() << 
"'";
 
   99                                 nodes.emplace(node->getName());
 
  101                                              << 
",  node: " << node->getName();
 
  103                             setsOfNode.emplace(std::move(nodes));
 
  105                         else if (selfCollisionAvoidanceRobot->hasRobotNode(subentry))
 
  108                             if (!selfCollisionAvoidanceRobot->getRobotNode(subentry)
 
  109                                      ->getCollisionModel())
 
  113                                     << 
"Self Collision Avoidance: No collision model found for '" 
  114                                     << selfCollisionAvoidanceRobot->getRobotNode(subentry)
 
  119                             setsOfNode.emplace(std::set<std::string>{subentry});
 
  125                             setsOfNode.emplace(std::set<std::string>{subentry});
 
  130                             ARMARX_ERROR << 
"No RobotNodeSet or RobotNode with name '" << subentry
 
  132                                          << _module<RobotData>().getRobotFileName()
 
  139                 auto addCombinationOfSetsToCollisionCheck =
 
  140                     [
this](
const std::set<std::string>& 
a, 
const std::set<std::string>& b)
 
  142                     for (
const auto& nodeA : 
a)
 
  144                         for (
const auto& nodeB : b)
 
  152                                 ARMARX_DEBUG << 
"------------ " << nodeA << 
"  " << nodeB;
 
  153                                 namePairsToCheck.emplace(nodeA, nodeB);
 
  157                                 ARMARX_DEBUG << 
"------------ " << nodeB << 
"  " << nodeA;
 
  158                                 namePairsToCheck.emplace(nodeB, nodeA);
 
  165                 for (
auto setAIt = setsOfNode.begin(); setAIt != setsOfNode.end(); ++setAIt)
 
  167                     auto setBIt = setAIt;
 
  169                     for (; setBIt != setsOfNode.end(); ++setBIt)
 
  171                         addCombinationOfSetsToCollisionCheck(*setAIt, *setBIt);
 
  176                 ARMARX_DEBUG << 
"-------- group: " << group << 
"...DONE!\n";
 
  178             ARMARX_DEBUG << 
"Processing groups for self collision checking...DONE!";
 
  181             getProperty<float>(
"SelfCollisionCheck_Frequency").getValue());
 
  183             getProperty<float>(
"SelfCollisionCheck_MinSelfDistance").getValue());
 
  191         std::lock_guard<std::mutex> guard{selfCollisionDataMutex};
 
  194             throw InvalidArgumentException{std::string{__FILE__} + 
": " + BOOST_CURRENT_FUNCTION +
 
  197         if (
distance == minSelfDistance && !nodePairsToCheck.empty())
 
  204         selfCollisionAvoidanceRobot = _module<RobotData>().cloneRobot(
true);
 
  205         selfCollisionAvoidanceRobotNodes = selfCollisionAvoidanceRobot->getRobotNodes();
 
  206         nodePairsToCheck.clear();
 
  209             floor.reset(
new VirtualRobot::SceneObjectSet(
 
  210                 "FLOORSET", selfCollisionAvoidanceRobot->getCollisionChecker()));
 
  211             static constexpr 
float floorSize = 1e16f;
 
  212             VirtualRobot::ObstaclePtr boxOb = VirtualRobot::Obstacle::createBox(
 
  215                 std::min(0.001f, minSelfDistance / 2),
 
  216                 VirtualRobot::VisualizationFactory::Color::Red(),
 
  218                 selfCollisionAvoidanceRobot->getCollisionChecker());
 
  221             floor->addSceneObject(boxOb);
 
  224         for (
const auto& node : selfCollisionAvoidanceRobotNodes)
 
  226             if (node->getCollisionModel())
 
  228                 node->getCollisionModel()->inflateModel(minSelfDistance / 2.f);
 
  236             std::vector<std::pair<std::string, std::string>> validNamePairsToCheck(
 
  237                 namePairsToCheck.begin(), namePairsToCheck.end());
 
  239             const auto isCollisionIgnored = [
this](
const std::string& 
a,
 
  240                                                    const std::string& b) -> 
bool 
  247                 const auto nodeA = selfCollisionAvoidanceRobot->getRobotNode(
a);
 
  248                 const auto nodeB = selfCollisionAvoidanceRobot->getRobotNode(b);
 
  250                 if (nodeA == 
nullptr or nodeB == 
nullptr)
 
  255                 const std::vector<std::string> nodesIgnoredByA = nodeA->getIgnoredCollisionModels();
 
  256                 const std::vector<std::string> nodesIgnoredByB = nodeB->getIgnoredCollisionModels();
 
  258                 if (
std::find(nodesIgnoredByA.begin(), nodesIgnoredByA.end(), b) !=
 
  259                     nodesIgnoredByA.end())
 
  261                     ARMARX_VERBOSE << 
"Ignoring collision between nodes: " << 
a << 
" -- " << b;
 
  265                 if (
std::find(nodesIgnoredByB.begin(), nodesIgnoredByB.end(), 
a) !=
 
  266                     nodesIgnoredByB.end())
 
  268                     ARMARX_VERBOSE << 
"Ignoring collision between nodes: " << b << 
" -- " << 
a;
 
  275             validNamePairsToCheck.erase(std::remove_if(validNamePairsToCheck.begin(),
 
  276                                                        validNamePairsToCheck.end(),
 
  277                                                        [&isCollisionIgnored](
const auto& p) -> 
bool 
  279                                                            const auto& [a, b] = p;
 
  280                                                            return isCollisionIgnored(a, b);
 
  282                                         validNamePairsToCheck.end());
 
  284             ARMARX_VERBOSE << 
"Removed " << (namePairsToCheck.size() - validNamePairsToCheck.size())
 
  285                            << 
" collision pairs.";
 
  288             namePairsToCheck = 
std::set(validNamePairsToCheck.begin(), validNamePairsToCheck.end());
 
  292         for (
const auto& pair : namePairsToCheck)
 
  296                     ? floor->getSceneObject(0)
 
  297                     : selfCollisionAvoidanceRobot->getRobotNode(pair.first);
 
  303                     ? floor->getSceneObject(0)
 
  304                     : selfCollisionAvoidanceRobot->getRobotNode(pair.second);
 
  308             nodePairsToCheck.emplace_back(first, second);
 
  319             throw InvalidArgumentException{std::string{__FILE__} + 
": " + BOOST_CURRENT_FUNCTION +
 
  322         checkFrequency = freq;
 
  329         return checkFrequency != 0;
 
  336         return checkFrequency;
 
  343         return minSelfDistance;
 
  347     SelfCollisionChecker::_componentPropertiesUpdated(
const std::set<std::string>& changed)
 
  350         if (changed.count(
"SelfCollisionCheck_Frequency"))
 
  353                 getProperty<float>(
"SelfCollisionCheck_Frequency").getValue());
 
  355         if (changed.count(
"SelfCollisionCheck_MinSelfDistance"))
 
  358                 getProperty<float>(
"SelfCollisionCheck_MinSelfDistance").getValue());
 
  363     SelfCollisionChecker::_postFinishControlThreadInitialization()
 
  365         selfCollisionAvoidanceThread = std::thread{[&] { selfCollisionAvoidanceTask(); }};
 
  369     SelfCollisionChecker::selfCollisionAvoidanceTask()
 
  372         ARMARX_INFO << 
"Self collision checker: entered selfCollisionAvoidanceTask";
 
  375             ARMARX_INFO << 
"Self collision checker: leaving selfCollisionAvoidanceTask";
 
  379             const auto freq = checkFrequency.load();
 
  388             const bool inEmergencyStop =
 
  389                 _module<ControlThread>().getEmergencyStopState() == eEmergencyStopActive;
 
  390             if (inEmergencyStop || freq == 0)
 
  395                 std::this_thread::sleep_for(std::chrono::microseconds{1
'000}); 
  398             //update robot + check 
  400                 std::lock_guard<std::mutex> guard{selfCollisionDataMutex}; 
  402                 _module<ControlThreadDataBuffer>().updateVirtualRobot( 
  403                     selfCollisionAvoidanceRobot, selfCollisionAvoidanceRobotNodes); 
  405                 //check for all nodes 0 
  407                     bool allJoints0 = true; 
  408                     for (const auto& node : selfCollisionAvoidanceRobotNodes) 
  410                         ARMARX_CHECK_NOT_NULL(node); 
  411                         if (0 != node->getJointValue()) 
  423                 bool collision = false; 
  424                 for (std::size_t idx = 0; idx < nodePairsToCheck.size(); ++idx) 
  426                     const auto& pair = nodePairsToCheck.at(idx); 
  428                     ARMARX_CHECK_NOT_NULL(pair.first); 
  429                     ARMARX_CHECK_NOT_NULL(pair.second); 
  431                     if (selfCollisionAvoidanceRobot->getCollisionChecker()->checkCollision( 
  432                             pair.first, pair.second)) 
  435                         lastCollisionPairIndex = idx; 
  436                         ARMARX_WARNING << "Self collision checker: COLLISION: '" 
  437                                        << pair.first->getName() << "' and '" 
  438                                        << pair.second->getName() << "'"; 
  439                         _module<Units>().getEmergencyStopMaster()->setEmergencyStopState( 
  440                             EmergencyStopState::eEmergencyStopActive); 
  441                         // since at least one of the NJoint-Controllers is going to cause a collision, we just kick them all. 
  442                         _module<ControlThreadDataBuffer>().setActivateControllersRequest({}); 
  448                     ARMARX_VERBOSE << deactivateSpam() 
  449                                    << "Self collision checker: no collision found between the " 
  450                                    << nodePairsToCheck.size() << " pairs"; 
  455             const auto duration = metronome.waitForNextTick(); 
  457             if (not duration.isPositive()) 
  459                 ARMARX_WARNING << deactivateSpam(10) 
  460                                << "Self collision checking took too long. " 
  461                                   "Exceeding time budget by " 
  462                                << duration.toMilliSecondsDouble() << "ms."; 
  468     SelfCollisionChecker::_preFinishRunning() 
  470         throwIfInControlThread(BOOST_CURRENT_FUNCTION); 
  471         ARMARX_INFO << "Stopping Self Collision Avoidance."; 
  472         if (selfCollisionAvoidanceThread.joinable()) 
  474             selfCollisionAvoidanceThread.join(); 
  477 } // namespace armarx::RobotUnitModule